diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b85c19d..c21857bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: branches: - master pull_request: - types: [opened, synchronize, reopened] + types: [ opened, synchronize, reopened ] workflow_dispatch: env: @@ -56,12 +56,12 @@ jobs: checks: name: Checks [${{ matrix.os }}] - needs: [formatting] runs-on: ${{ matrix.runner }} + needs: formatting strategy: fail-fast: false matrix: - os: [windows, linux, macos] + os: [ windows, linux, macos ] include: - os: windows runner: windows-latest @@ -75,17 +75,17 @@ jobs: uses: actions/checkout@v4 - name: Install devel packages - if: ${{ runner.os == 'Linux' }} + if: runner.os == 'Linux' run: | sudo apt-get -y install libasound2-dev - name: Install NASM - if: ${{ runner.os == 'Windows' }} + if: runner.os == 'Windows' + shell: pwsh run: | choco install nasm $Env:PATH += ";$Env:ProgramFiles\NASM" echo "PATH=$Env:PATH" >> $Env:GITHUB_ENV - shell: pwsh - name: Rust cache uses: Swatinem/rust-cache@v2.7.3 @@ -118,8 +118,8 @@ jobs: fuzz: name: Fuzzing - needs: [formatting] runs-on: ubuntu-latest + needs: formatting steps: - uses: actions/checkout@v4 @@ -147,8 +147,8 @@ jobs: web: name: Web Client - needs: [formatting] runs-on: ubuntu-latest + needs: formatting steps: - uses: actions/checkout@v4 @@ -173,8 +173,8 @@ jobs: ffi: name: FFI - needs: [formatting] runs-on: ubuntu-latest + needs: formatting steps: - uses: actions/checkout@v4 @@ -202,14 +202,20 @@ jobs: success: name: Success - if: ${{ always() }} - needs: [formatting, typos, checks, fuzz, web, ffi] runs-on: ubuntu-latest + if: ${{ always() }} + needs: + - formatting + - typos + - checks + - fuzz + - web + - ffi steps: - name: Check success + shell: pwsh run: | $results = '${{ toJSON(needs.*.result) }}' | ConvertFrom-Json $succeeded = $($results | Where { $_ -Ne "success" }).Count -Eq 0 exit $(if ($succeeded) { 0 } else { 1 }) - shell: pwsh diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 25aefe75..4e830be0 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -5,7 +5,7 @@ on: branches: - master pull_request: - types: [opened, synchronize, reopened] + types: [ opened, synchronize, reopened ] workflow_dispatch: env: @@ -32,19 +32,19 @@ jobs: run: cargo xtask cov install -v - name: Generate PR report - if: ${{ github.event.number != '' }} - run: cargo xtask cov report-gh --repo "${{ github.repository }}" --pr "${{ github.event.number }}" -v + if: github.event.number != '' env: GH_TOKEN: ${{ github.token }} + run: cargo xtask cov report-gh --repo "${{ github.repository }}" --pr "${{ github.event.number }}" -v - name: Configure Git Identity - if: ${{ github.ref == 'refs/heads/master' }} + if: github.ref == 'refs/heads/master' run: | git config --local user.name "github-actions[bot]" git config --local user.email "github-actions[bot]@users.noreply.github.com" - name: Update coverage data - if: ${{ github.ref == 'refs/heads/master' }} - run: cargo xtask cov update -v + if: github.ref == 'refs/heads/master' env: GH_TOKEN: ${{ secrets.DEVOLUTIONSBOT_TOKEN }} + run: cargo xtask cov update -v diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 26a9d855..71d6762c 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -36,12 +36,12 @@ jobs: fuzz: name: Fuzzing ${{ matrix.target }} - needs: [corpus-download] runs-on: ubuntu-latest + needs: corpus-download strategy: fail-fast: false matrix: - target: [pdu_decoding, rle_decompression, bitmap_stream, cliprdr_format, channel_processing] + target: [ pdu_decoding, rle_decompression, bitmap_stream, cliprdr_format, channel_processing ] steps: - uses: actions/checkout@v4 @@ -108,9 +108,9 @@ jobs: corpus-merge: name: Corpus merge artifacts - if: ${{ always() && !cancelled() }} - needs: [fuzz] runs-on: ubuntu-latest + needs: fuzz + if: ${{ always() && !cancelled() }} steps: - name: Merge Artifacts @@ -122,9 +122,9 @@ jobs: corpus-upload: name: Upload corpus - if: ${{ always() && !cancelled() }} - needs: [corpus-merge] runs-on: ubuntu-latest + needs: corpus-merge + if: ${{ always() && !cancelled() }} env: AZURE_STORAGE_KEY: ${{ secrets.CORPUS_AZURE_STORAGE_KEY }} @@ -156,13 +156,13 @@ jobs: notify: name: Notify failure - if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }} - needs: [fuzz] runs-on: ubuntu-latest + if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }} + needs: + - fuzz env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_ARCHITECTURE }} SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK - steps: - name: Send slack notification id: slack diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index dddf8fa6..2a559f72 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -21,6 +21,7 @@ jobs: steps: - name: Get dry run id: get-dry-run + shell: pwsh run: | $IsDryRun = '${{ github.event.inputs.dry-run }}' -Eq 'true' -Or '${{ github.event_name }}' -Eq 'schedule' @@ -29,12 +30,13 @@ jobs: } else { echo "dry-run=false" >> $Env:GITHUB_OUTPUT } - shell: pwsh build: name: Build package [${{matrix.library}}] - needs: [preflight] runs-on: ubuntu-latest + needs: + - preflight + strategy: fail-fast: false matrix: @@ -47,17 +49,18 @@ jobs: uses: actions/checkout@v4 - name: Setup wasm-pack + shell: bash run: | curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - shell: bash - name: Install dependencies + shell: pwsh run: | Set-Location -Path "./web-client/${{matrix.library}}/" npm install - shell: pwsh - name: Build package + shell: pwsh run: | Set-PSDebug -Trace 1 @@ -65,15 +68,14 @@ jobs: npm run build Set-Location -Path ./dist npm pack - shell: pwsh - name: Harvest package + shell: pwsh run: | Set-PSDebug -Trace 1 New-Item -ItemType "directory" -Path . -Name "npm-packages" Get-ChildItem -Path ./web-client/ -Recurse *.tgz | ForEach { Copy-Item $_ "./npm-packages" } - shell: pwsh - name: Upload package artifact uses: actions/upload-artifact@v4 @@ -83,8 +85,8 @@ jobs: npm-merge: name: Merge artifacts - needs: [build] runs-on: ubuntu-latest + needs: build steps: - name: Merge Artifacts @@ -96,13 +98,12 @@ jobs: publish: name: Publish package - environment: publish - if: ${{ github.event_name == 'workflow_dispatch' }} - needs: [preflight, npm-merge] runs-on: ubuntu-latest - permissions: - contents: write - id-token: write + if: github.event_name == 'workflow_dispatch' + environment: publish + needs: + - preflight + - npm-merge steps: - name: Checkout repository @@ -116,7 +117,12 @@ jobs: name: npm path: npm-packages + - name: Prepare npm + shell: pwsh + run: npm config set "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" + - name: Publish + shell: pwsh run: | Set-PSDebug -Trace 1 @@ -162,10 +168,15 @@ jobs: $publishCmd = $publishCmd -Join ' ' Invoke-Expression $publishCmd } - shell: pwsh - name: Create version tags if: ${{ needs.preflight.outputs.dry-run == 'false' }} + shell: bash + env: + GIT_AUTHOR_NAME: github-actions + GIT_AUTHOR_EMAIL: github-actions@github.com + GIT_COMMITTER_NAME: github-actions + GIT_COMMITTER_EMAIL: github-actions@github.com run: | set -e @@ -191,12 +202,6 @@ jobs: git tag "$tag" "$GITHUB_SHA" git push origin "$tag" done - shell: bash - env: - GIT_AUTHOR_NAME: github-actions - GIT_AUTHOR_EMAIL: github-actions@github.com - GIT_COMMITTER_NAME: github-actions - GIT_COMMITTER_EMAIL: github-actions@github.com - name: Update Artifactory Cache if: ${{ needs.preflight.outputs.dry-run == 'false' }} @@ -208,13 +213,14 @@ jobs: notify: name: Notify failure - if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }} - needs: [preflight, build] runs-on: ubuntu-latest + if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }} + needs: + - preflight + - build env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_ARCHITECTURE }} SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK - steps: - name: Send slack notification id: slack diff --git a/.github/workflows/nuget-publish.yml b/.github/workflows/nuget-publish.yml index eb6350b0..267a0fe3 100644 --- a/.github/workflows/nuget-publish.yml +++ b/.github/workflows/nuget-publish.yml @@ -26,6 +26,7 @@ jobs: - name: Get dry run id: get-dry-run + shell: pwsh run: | $IsDryRun = '${{ github.event.inputs.dry-run }}' -Eq 'true' -Or '${{ github.event_name }}' -Eq 'schedule' @@ -34,27 +35,26 @@ jobs: } else { echo "dry-run=false" >> $Env:GITHUB_OUTPUT } - shell: pwsh - name: Get version id: get-version + shell: pwsh run: | $CsprojXml = [Xml] (Get-Content .\ffi\dotnet\Devolutions.IronRdp\Devolutions.IronRdp.csproj) $ProjectVersion = $CsprojXml.Project.PropertyGroup.Version | Select-Object -First 1 $PackageVersion = $ProjectVersion -Replace "^(\d+)\.(\d+)\.(\d+).(\d+)$", "`$1.`$2.`$3" echo "project-version=$ProjectVersion" >> $Env:GITHUB_OUTPUT echo "package-version=$PackageVersion" >> $Env:GITHUB_OUTPUT - shell: pwsh build-native: name: Native build - needs: [preflight] runs-on: ${{matrix.runner}} + needs: preflight strategy: fail-fast: false matrix: - os: [win, osx, linux, ios, android] - arch: [x86, x64, arm, arm64] + os: [ win, osx, linux, ios, android ] + arch: [ x86, x64, arm, arm64 ] include: - os: win runner: windows-2022 @@ -89,20 +89,20 @@ jobs: uses: actions/checkout@v4 - name: Configure Android NDK - if: ${{ matrix.os == 'android' }} uses: Devolutions/actions-public/cargo-android-ndk@v1 + if: matrix.os == 'android' with: android_api_level: "21" - name: Configure macOS deployement target if: ${{ matrix.os == 'osx' }} - run: Write-Output "MACOSX_DEPLOYMENT_TARGET=10.10" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append shell: pwsh + run: Write-Output "MACOSX_DEPLOYMENT_TARGET=10.10" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Configure iOS deployement target if: ${{ matrix.os == 'ios' }} - run: Write-Output "IPHONEOS_DEPLOYMENT_TARGET=12.1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append shell: pwsh + run: Write-Output "IPHONEOS_DEPLOYMENT_TARGET=12.1" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - name: Update runner if: ${{ matrix.os == 'linux' }} @@ -110,11 +110,12 @@ jobs: - name: Install dependencies for rustls if: ${{ runner.os == 'Windows' }} + shell: pwsh run: | choco install ninja nasm # We need to add the NASM binary folder to the PATH manually. - # We don't need to do that for ninja. + # We don’t need to do that for ninja. Write-Output "PATH=$Env:PATH;$Env:ProgramFiles\NASM" >> $Env:GITHUB_ENV # libclang / LLVM is a requirement for AWS LC. @@ -124,7 +125,6 @@ jobs: # Install Visual Studio Developer PowerShell Module for cmdlets such as Enter-VsDevShell Install-Module VsDevShell -Force - shell: pwsh # No pre-generated bindings for Android and iOS. # https://aws.github.io/aws-lc-rs/platform_support.html#pre-generated-bindings @@ -141,18 +141,19 @@ jobs: sudo apt-get install gcc-multilib - name: Setup LLVM - if: ${{ matrix.os == 'linux' }} uses: Devolutions/actions-public/setup-llvm@v1 + if: matrix.os == 'linux' with: version: "18.1.8" - name: Setup CBake - if: ${{ matrix.os == 'linux' }} uses: Devolutions/actions-public/setup-cbake@v1 + if: matrix.os == 'linux' with: cargo_env_scripts: true - name: Build native lib (${{matrix.os}}-${{matrix.arch}}) + shell: pwsh run: | $DotNetOs = '${{matrix.os}}' $DotNetArch = '${{matrix.arch}}' @@ -209,7 +210,6 @@ jobs: $OutputPath = Join-Path "dependencies" "runtimes" $DotNetRid "native" New-Item -ItemType Directory -Path $OutputPath | Out-Null Copy-Item $OutputLibrary $(Join-Path $OutputPath $RenamedLibraryName) - shell: pwsh - name: Upload native components uses: actions/upload-artifact@v4 @@ -219,8 +219,8 @@ jobs: build-universal: name: Universal build - needs: [preflight, build-native] runs-on: ubuntu-22.04 + needs: [ preflight, build-native ] strategy: fail-fast: false matrix: @@ -239,6 +239,7 @@ jobs: path: dependencies/runtimes - name: Lipo native components + shell: pwsh run: | Set-Location "dependencies/runtimes" # No RID for universal binaries, see: https://github.com/dotnet/runtime/issues/53156 @@ -248,9 +249,9 @@ jobs: $LipoCmd = $(@('lipo', '-create', '-output', (Join-Path -Path $OutputPath -ChildPath "libDevolutionsIronRdp.dylib")) + $Libraries) -Join ' ' Write-Host $LipoCmd Invoke-Expression $LipoCmd - shell: pwsh - name: Framework + shell: pwsh if: ${{ matrix.os == 'ios' }} run: | $Version = '${{ needs.preflight.outputs.project-version }}' @@ -268,19 +269,19 @@ jobs: [xml] $InfoPlistXml = Get-Content (Join-Path "ffi" "dotnet" "Devolutions.IronRdp" "Info.plist") Select-Xml -xml $InfoPlistXml -XPath "/plist/dict/key[. = 'CFBundleIdentifier']/following-sibling::string[1]" | - %{ + %{ $_.Node.InnerXml = "com.devolutions.ironrdp" } Select-Xml -xml $InfoPlistXml -XPath "/plist/dict/key[. = 'CFBundleExecutable']/following-sibling::string[1]" | - %{ + %{ $_.Node.InnerXml = $BundleName } Select-Xml -xml $InfoPlistXml -XPath "/plist/dict/key[. = 'CFBundleVersion']/following-sibling::string[1]" | - %{ + %{ $_.Node.InnerXml = $Version } Select-Xml -xml $InfoPlistXml -XPath "/plist/dict/key[. = 'CFBundleShortVersionString']/following-sibling::string[1]" | - %{ + %{ $_.Node.InnerXml = $ShortVersion } @@ -293,7 +294,6 @@ jobs: # .NET XML document inserts two square brackets at the end of the DOCTYPE tag # It's perfectly valid XML, but we're dealing with plists here and dyld will not be able to read the file ((Get-Content -Path (Join-Path $FrameworkDir "Info.plist") -Raw) -Replace 'PropertyList-1.0.dtd"\[\]', 'PropertyList-1.0.dtd"') | Set-Content -Path (Join-Path $FrameworkDir "Info.plist") - shell: pwsh - name: Upload native components uses: actions/upload-artifact@v4 @@ -303,8 +303,8 @@ jobs: build-managed: name: Managed build - needs: [build-universal] runs-on: windows-2022 + needs: build-universal steps: - name: Check out ${{ github.repository }} @@ -317,9 +317,9 @@ jobs: run: dotnet workload install ios - name: Prepare dependencies + shell: pwsh run: | New-Item -ItemType Directory -Path "dependencies/runtimes" | Out-Null - shell: pwsh - name: Download native components uses: actions/download-artifact@v4 @@ -327,19 +327,19 @@ jobs: path: dependencies/runtimes - name: Rename dependencies + shell: pwsh run: | Set-Location "dependencies/runtimes" $(Get-Item ".\ironrdp-*") | ForEach-Object { Rename-Item $_ $_.Name.Replace("ironrdp-", "") } Get-ChildItem * -Recurse - shell: pwsh - name: Build Devolutions.IronRdp (managed) + shell: pwsh run: | # net8.0 target packaged as Devolutions.IronRdp dotnet build .\ffi\dotnet\Devolutions.IronRdp\Devolutions.IronRdp.csproj -c Release - # net9.0-ios target packaged as Devolutions.IronRdp.iOS + # net8.0-ios target packaged as Devolutions.IronRdp.iOS dotnet build .\ffi\dotnet\Devolutions.IronRdp\Devolutions.IronRdp.csproj -c Release /p:PackageId=Devolutions.IronRdp.iOS - shell: pwsh - name: Upload managed components uses: actions/upload-artifact@v4 @@ -349,12 +349,12 @@ jobs: publish: name: Publish NuGet package - environment: nuget-publish - if: ${{ needs.preflight.outputs.dry-run == 'false' }} - needs: [preflight, build-managed] runs-on: ubuntu-latest - permissions: - id-token: write + environment: nuget-publish + if: needs.preflight.outputs.dry-run == 'false' + needs: + - preflight + - build-managed steps: - name: Download NuGet package artifact @@ -363,24 +363,19 @@ jobs: name: ironrdp-nupkg path: package - - name: NuGet login (OIDC) - uses: NuGet/login@v1 - id: nuget-login - with: - user: ${{ secrets.NUGET_BOT_USERNAME }} - - name: Publish to nuget.org + shell: pwsh run: | $Files = Get-ChildItem -Recurse package/*.nupkg foreach ($File in $Files) { $PushCmd = @( - 'dotnet', - 'nuget', - 'push', + 'dotnet', + 'nuget', + 'push', "$File", '--api-key', - '${{ steps.nuget-login.outputs.NUGET_API_KEY }}', + '${{ secrets.NUGET_API_KEY }}', '--source', 'https://api.nuget.org/v3/index.json', '--skip-duplicate' @@ -390,17 +385,19 @@ jobs: $PushCmd = $PushCmd -Join ' ' Invoke-Expression $PushCmd } - shell: pwsh notify: name: Notify failure - if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }} - needs: [preflight, build-native, build-universal, build-managed] runs-on: ubuntu-latest + if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }} + needs: + - preflight + - build-native + - build-universal + - build-managed env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_ARCHITECTURE }} SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK - steps: - name: Send slack notification id: slack diff --git a/.github/workflows/release-crates.yml b/.github/workflows/release-crates.yml index 96d0a78d..7465f76f 100644 --- a/.github/workflows/release-crates.yml +++ b/.github/workflows/release-crates.yml @@ -14,8 +14,9 @@ jobs: # Create a PR with the new versions and changelog, preparing the next release. open-pr: name: Open release PR - environment: cratesio-publish runs-on: ubuntu-latest + environment: cratesio-publish + concurrency: group: release-plz-${{ github.ref }} cancel-in-progress: false @@ -36,6 +37,7 @@ jobs: github-token: ${{ secrets.DEVOLUTIONSBOT_WRITE_TOKEN }} - name: Update fuzz/Cargo.lock + shell: pwsh if: ${{ steps.release-plz.outputs.did-open-pr == 'true' }} run: | $prRaw = '${{ steps.release-plz.outputs.pr }}' @@ -59,15 +61,12 @@ jobs: Write-Host "Update the release pull request" git push --force - shell: pwsh # Release unpublished packages. release: name: Release crates - environment: cratesio-publish runs-on: ubuntu-latest - permissions: - id-token: write + environment: cratesio-publish steps: - name: Checkout repository @@ -75,12 +74,8 @@ jobs: with: fetch-depth: 512 - - name: Authenticate with crates.io - id: auth - uses: rust-lang/crates-io-auth-action@v1 - - name: Run release-plz uses: Devolutions/actions-public/release-plz@v1 with: command: release - registry-token: ${{ steps.auth.outputs.token }} + registry-token: ${{ secrets.CRATES_IO_TOKEN }} diff --git a/Cargo.lock b/Cargo.lock index caaee2ce..9d284edf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "ab_glyph" -version = "0.2.32" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" +checksum = "e074464580a518d16a7126262fffaaa47af89d4099d4cb403f8ed938ba12ee7d" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -18,6 +18,15 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + [[package]] name = "adler2" version = "2.0.1" @@ -26,19 +35,19 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aead" -version = "0.6.0-rc.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8202ab55fcbf46ca829833f347a82a2a4ce0596f0304ac322c2d100030cd56" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "crypto-common 0.2.0-rc.4", - "inout", + "crypto-common", + "generic-array", ] [[package]] name = "aes" -version = "0.9.0-rc.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e713c57c2a2b19159e7be83b9194600d7e8eb3b7c2cd67e671adf47ce189a05" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", @@ -47,9 +56,9 @@ dependencies = [ [[package]] name = "aes-gcm" -version = "0.11.0-rc.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0686ba04dc80c816104c96cd7782b748f6ad58c5dd4ee619ff3258cf68e83d54" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", "aes", @@ -61,12 +70,11 @@ dependencies = [ [[package]] name = "aes-kw" -version = "0.3.0-rc.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02eaa2d54d0fad0116e4b1efb65803ea0bf059ce970a67cd49718d87e807cb51" +checksum = "69fa2b352dcefb5f7f3a5fb840e02665d311d878955380515e4fd50095dd3d8c" dependencies = [ "aes", - "const-oid 0.10.1", ] [[package]] @@ -76,7 +84,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.3.4", + "getrandom 0.3.3", "once_cell", "version_check", "zerocopy", @@ -84,22 +92,13 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] -[[package]] -name = "alloca" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" -dependencies = [ - "cc", -] - [[package]] name = "alsa" version = "0.9.1" @@ -107,7 +106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" dependencies = [ "alsa-sys", - "bitflags 2.10.0", + "bitflags 2.9.4", "cfg-if", "libc", ] @@ -129,7 +128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.10.0", + "bitflags 2.9.4", "cc", "cesu8", "jni", @@ -166,9 +165,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.21" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -181,9 +180,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" @@ -196,22 +195,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.11" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -265,7 +264,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.17", + "thiserror 2.0.16", ] [[package]] @@ -332,15 +331,6 @@ dependencies = [ "syn", ] -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - [[package]] name = "atomic-waker" version = "1.1.2" @@ -355,9 +345,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.15.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" +checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786" dependencies = [ "aws-lc-sys", "zeroize", @@ -365,10 +355,11 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.35.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" +checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd" dependencies = [ + "bindgen", "cc", "cmake", "dunce", @@ -376,10 +367,25 @@ dependencies = [ ] [[package]] -name = "base16ct" -version = "0.3.0" +name = "backtrace" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b59d472eab27ade8d770dcb11da7201c11234bef9f82ce7aa517be028d462b" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" @@ -389,9 +395,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "benches" @@ -407,6 +413,26 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.9.4", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + [[package]] name = "bit-set" version = "0.8.0" @@ -436,9 +462,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bitvec" @@ -461,22 +487,13 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-buffer" -version = "0.11.0-rc.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9ef36a6fcdb072aa548f3da057640ec10859eb4e91ddf526ee648d50c76a949" -dependencies = [ - "hybrid-array", -] - [[package]] name = "block-padding" -version = "0.4.0-rc.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e59c1aab3e6c5e56afe1b7e8650be9b5a791cb997bdea449194ae62e4bf8c73" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" dependencies = [ - "hybrid-array", + "generic-array", ] [[package]] @@ -499,24 +516,24 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" -version = "1.24.0" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.10.2" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" dependencies = [ "proc-macro2", "quote", @@ -537,15 +554,15 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.11.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "bytesize" -version = "2.3.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3" +checksum = "f5c434ae3cf0089ca203e9019ebe529c47ff45cefe8af7c85ecb734ef541822f" [[package]] name = "calloop" @@ -553,7 +570,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "log", "polling", "rustix 0.38.44", @@ -581,18 +598,18 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cbc" -version = "0.2.0-rc.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dbf9e5b071e9de872e32b73f485e8f644ff47c7011d95476733e7482ee3e5c3" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" dependencies = [ "cipher", ] [[package]] name = "cc" -version = "1.2.49" +version = "1.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" dependencies = [ "find-msvc-tools", "jobserver", @@ -607,10 +624,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] -name = "cfg-if" -version = "1.0.4" +name = "cexpr" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "cfg_aliases" @@ -628,7 +654,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -660,20 +686,30 @@ dependencies = [ [[package]] name = "cipher" -version = "0.5.0-rc.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e12a13eb01ded5d32ee9658d94f553a19e804204f2dc811df69ab4d9e0cb8c7" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "block-buffer 0.11.0-rc.5", - "crypto-common 0.2.0-rc.4", + "crypto-common", "inout", ] [[package]] -name = "clap" -version = "4.5.53" +name = "clang-sys" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" dependencies = [ "clap_builder", "clap_derive", @@ -681,9 +717,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.53" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" dependencies = [ "anstream", "anstyle", @@ -693,9 +729,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" dependencies = [ "heck", "proc-macro2", @@ -705,15 +741,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.6" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "cmake" -version = "0.1.57" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ "cc", ] @@ -759,17 +795,11 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "const-oid" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dabb6555f92fb9ee4140454eb5dcd14c7960e1225c6d1a6cc361f032947713e" - [[package]] name = "convert_case" -version = "0.10.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" dependencies = [ "unicode-segmentation", ] @@ -808,7 +838,20 @@ checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", "core-foundation 0.9.4", - "core-graphics-types", + "core-graphics-types 0.1.3", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "core-graphics-types 0.2.0", "foreign-types 0.5.0", "libc", ] @@ -824,6 +867,17 @@ dependencies = [ "libc", ] +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "libc", +] + [[package]] name = "coreaudio-rs" version = "0.13.0" @@ -884,11 +938,10 @@ dependencies = [ [[package]] name = "criterion" -version = "0.8.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d883447757bb0ee46f233e9dc22eb84d93a9508c9b868687b274fc431d886bf" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" dependencies = [ - "alloca", "anes", "cast", "ciborium", @@ -897,7 +950,6 @@ dependencies = [ "itertools", "num-traits", "oorandom", - "page_size", "plotters", "rayon", "regex", @@ -909,29 +961,14 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.8.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed943f81ea2faa8dcecbbfa50164acf95d555afec96a27871663b300e387b2e4" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" dependencies = [ "cast", "itertools", ] -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -963,7 +1000,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "crossterm_winapi", "derive_more", "document-features", @@ -991,39 +1028,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] -name = "crypto-bigint" -version = "0.7.0-rc.8" +name = "crypto" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4113edbc9f68c0a64d5b911f803eb245d04bb812680fd56776411f69c670f3e0" +checksum = "bf1e6e5492f8f0830c37f301f6349e0dac8b2466e4fe89eef90e9eef906cd046" dependencies = [ - "hybrid-array", - "num-traits", - "rand_core 0.9.3", - "serdect", + "crypto-common", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", "subtle", "zeroize", ] [[package]] name = "crypto-common" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] -[[package]] -name = "crypto-common" -version = "0.2.0-rc.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8235645834fbc6832939736ce2f2d08192652269e11010a6240f61b908a1c6" -dependencies = [ - "hybrid-array", - "rand_core 0.9.3", -] - [[package]] name = "crypto-mac" version = "0.11.0" @@ -1034,40 +1069,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "crypto-primes" -version = "0.7.0-pre.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f2523fbb68811c8710829417ad488086720a6349e337c38d12fa81e09e50bf" -dependencies = [ - "crypto-bigint", - "libm", - "rand_core 0.9.3", -] - -[[package]] -name = "cryptoki" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "781357a7779a8e92ea985121bbf379a9adf0777f44ab6392efc6abd5aa9b67db" -dependencies = [ - "bitflags 1.3.2", - "cryptoki-sys", - "libloading", - "log", - "paste", - "secrecy", -] - -[[package]] -name = "cryptoki-sys" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "753e27d860277930ae9f394c119c8c70303236aab0ffab1d51f3d207dbb2bc4b" -dependencies = [ - "libloading", -] - [[package]] name = "ctor-lite" version = "0.1.0" @@ -1076,9 +1077,9 @@ checksum = "1f791803201ab277ace03903de1594460708d2d54df6053f2d9e82f592b19e3b" [[package]] name = "ctr" -version = "0.10.0-rc.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e41d01c6f73b9330177f5cf782ae5b581b5f2c7840e298e0275ceee5001434" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ "cipher", ] @@ -1091,14 +1092,14 @@ checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" [[package]] name = "curve25519-dalek" -version = "5.0.0-pre.1" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f9200d1d13637f15a6acb71e758f64624048d85b31a5fdbfd8eca1e2687d0b7" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", - "digest 0.11.0-rc.3", + "digest", "fiat-crypto", "rustc_version", "subtle", @@ -1134,21 +1135,10 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid 0.9.6", + "const-oid", "der_derive", "flagset", - "pem-rfc7468 0.7.0", - "zeroize", -] - -[[package]] -name = "der" -version = "0.8.0-rc.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d8dd2f26c86b27a2a8ea2767ec7f9df7a89516e4794e54ac01ee618dda3aa4" -dependencies = [ - "const-oid 0.10.1", - "pem-rfc7468 1.0.0-rc.3", + "pem-rfc7468", "zeroize", ] @@ -1178,9 +1168,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" dependencies = [ "powerfmt", ] @@ -1198,31 +1188,30 @@ dependencies = [ [[package]] name = "derive_more" -version = "2.1.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.1.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version", "syn", ] [[package]] name = "des" -version = "0.9.0-rc.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f51594a70805988feb1c85495ddec0c2052e4fbe59d9c0bb7f94bfc164f4f90" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" dependencies = [ "cipher", ] @@ -1239,19 +1228,9 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", - "crypto-common 0.1.7", -] - -[[package]] -name = "digest" -version = "0.11.0-rc.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac89f8a64533a9b0eaa73a68e424db0fb1fd6271c74cc0125336a05f090568d" -dependencies = [ - "block-buffer 0.11.0-rc.5", - "const-oid 0.10.1", - "crypto-common 0.2.0-rc.4", + "block-buffer", + "const-oid", + "crypto-common", "subtle", ] @@ -1298,8 +1277,8 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", + "bitflags 2.9.4", + "objc2 0.6.2", ] [[package]] @@ -1330,9 +1309,9 @@ dependencies = [ [[package]] name = "document-features" -version = "0.2.12" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" dependencies = [ "litrs", ] @@ -1351,23 +1330,22 @@ checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "drm" -version = "0.14.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" +checksum = "98888c4bbd601524c11a7ed63f814b8825f420514f78e96f752c437ae9cbb5d1" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "bytemuck", "drm-ffi", "drm-fourcc", - "libc", "rustix 0.38.44", ] [[package]] name = "drm-ffi" -version = "0.9.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e41459d99a9b529845f6d2c909eb9adf3b6d2f82635ae40be8de0601726e8b" +checksum = "97c98727e48b7ccb4f4aea8cfe881e5b07f702d17b7875991881b41af7278d53" dependencies = [ "drm-sys", "rustix 0.38.44", @@ -1381,9 +1359,9 @@ checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" [[package]] name = "drm-sys" -version = "0.8.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bafb66c8dbc944d69e15cfcc661df7e703beffbaec8bd63151368b06c5f9858c" +checksum = "fd39dde40b6e196c2e8763f23d119ddb1a8714534bf7d77fa97a65b0feda3986" dependencies = [ "libc", "linux-raw-sys 0.6.5", @@ -1403,24 +1381,23 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "ecdsa" -version = "0.17.0-rc.7" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ab355ec063f7a110eb627471058093aba00eb7f4e70afbd15e696b79d1077b" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der 0.8.0-rc.9", - "digest 0.11.0-rc.3", + "der", + "digest", "elliptic-curve", "rfc6979", "signature", - "spki 0.8.0-rc.4", - "zeroize", + "spki", ] [[package]] name = "ed25519" -version = "3.0.0-rc.1" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef49c0b20c0ad088893ad2a790a29c06a012b3f05bcfc66661fd22a94b32129" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", "signature", @@ -1428,13 +1405,14 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "3.0.0-pre.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad207ed88a133091f83224265eac21109930db09bedcad05d5252f2af2de20a1" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519", - "rand_core 0.9.3", + "rand_core 0.6.4", + "serde", "sha2", "subtle", "zeroize", @@ -1448,21 +1426,20 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "elliptic-curve" -version = "0.14.0-rc.15" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e3be87c458d756141f3b6ee188828132743bf90c7d14843e2835d6443e5fb03" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest 0.11.0-rc.3", + "digest", "ff", + "generic-array", "group", "hkdf", - "hybrid-array", - "once_cell", - "pem-rfc7468 1.0.0-rc.3", + "pem-rfc7468", "pkcs8", - "rand_core 0.9.3", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -1507,7 +1484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.61.0", ] [[package]] @@ -1537,11 +1514,11 @@ dependencies = [ [[package]] name = "ff" -version = "0.14.0-pre.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d42dd26f5790eda47c1a2158ea4120e32c35ddc9a7743c98a292accc01b54ef3" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.6.4", "subtle", ] @@ -1549,7 +1526,6 @@ dependencies = [ name = "ffi" version = "0.0.0" dependencies = [ - "anyhow", "diplomat", "diplomat-runtime", "embed-resource", @@ -1557,24 +1533,23 @@ dependencies = [ "ironrdp-cliprdr-native", "ironrdp-core", "ironrdp-dvc-pipe-proxy", - "ironrdp-rdcleanpath", "sspi", - "thiserror 2.0.17", + "thiserror 2.0.16", "tracing", "tracing-subscriber", ] [[package]] name = "fiat-crypto" -version = "0.3.0" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" [[package]] name = "flagset" @@ -1584,12 +1559,11 @@ checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", - "libz-sys", "miniz_oxide", ] @@ -1774,16 +1748,17 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] name = "gethostname" -version = "1.1.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" +checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55" dependencies = [ "rustix 1.1.2", - "windows-link", + "windows-targets 0.52.6", ] [[package]] @@ -1795,33 +1770,40 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasip2", + "wasi 0.14.7+wasi-0.2.4", "wasm-bindgen", ] [[package]] name = "ghash" -version = "0.6.0-rc.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f88107cb02ed63adcc4282942e60c4d09d80208d33b360ce7c729ce6dae1739" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ + "opaque-debug", "polyval", ] +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + [[package]] name = "glob" version = "0.3.3" @@ -1873,12 +1855,12 @@ dependencies = [ [[package]] name = "group" -version = "0.14.0-pre.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff6a0b2dd4b981b1ae9e3e6830ab146771f3660d31d57bafd9018805a91b0f1" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.9.3", + "rand_core 0.6.4", "subtle", ] @@ -1903,42 +1885,19 @@ dependencies = [ [[package]] name = "half" -version = "2.7.1" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" dependencies = [ "cfg-if", "crunchy", - "zerocopy", -] - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", ] [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "spin", - "stable_deref_trait", -] +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "heck" @@ -1960,9 +1919,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hickory-proto" -version = "0.25.2" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" +checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" dependencies = [ "async-trait", "cfg-if", @@ -1974,9 +1933,8 @@ dependencies = [ "idna", "ipnet", "once_cell", - "rand 0.9.2", - "ring", - "thiserror 2.0.17", + "rand 0.8.5", + "thiserror 1.0.69", "tinyvec", "tokio", "tracing", @@ -1985,50 +1943,51 @@ dependencies = [ [[package]] name = "hickory-resolver" -version = "0.25.2" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" +checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" dependencies = [ "cfg-if", "futures-util", "hickory-proto", "ipconfig", - "moka", + "lru-cache", "once_cell", "parking_lot", - "rand 0.9.2", + "rand 0.8.5", "resolv-conf", "smallvec", - "thiserror 2.0.17", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "hkdf" -version = "0.13.0-rc.2" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8ef30358b03ca095a5b910547f4f8d4b9f163e4057669c5233ef595b1ecf008" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] [[package]] name = "hmac" -version = "0.13.0-rc.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3fd4dc94c318c1ede8a2a48341c250d6ddecd3ba793da2820301a9f92417ad9" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.11.0-rc.3", + "digest", ] [[package]] name = "http" -version = "1.4.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", + "fnv", "itoa", ] @@ -2061,22 +2020,11 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "hybrid-array" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f471e0a81b2f90ffc0cb2f951ae04da57de8baa46fa99112b062a5173a5088d0" -dependencies = [ - "subtle", - "typenum", - "zeroize", -] - [[package]] name = "hyper" -version = "1.8.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ "atomic-waker", "bytes", @@ -2129,9 +2077,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "base64", "bytes", @@ -2145,7 +2093,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", + "socket2 0.6.0", "system-configuration", "tokio", "tower-service", @@ -2165,7 +2113,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.62.0", ] [[package]] @@ -2179,9 +2127,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", "potential_utf", @@ -2192,9 +2140,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -2205,10 +2153,11 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ + "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -2219,38 +2168,42 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", + "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", "icu_locale_core", + "stable_deref_trait", + "tinystr", "writeable", "yoke", "zerofrom", @@ -2281,9 +2234,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.9" +version = "0.25.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" dependencies = [ "bytemuck", "byteorder-lite", @@ -2294,9 +2247,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown", @@ -2304,12 +2257,12 @@ dependencies = [ [[package]] name = "inout" -version = "0.2.0-rc.6" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1603f76010ff924b616c8f44815a42eb10fb0b93d308b41deaa8da6d4251fd4b" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "block-padding", - "hybrid-array", + "generic-array", ] [[package]] @@ -2318,7 +2271,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2628910d0114e9139056161d8644a2026be7b117f8498943f9437748b04c9e0a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "crossterm", "dyn-clone", "fuzzy-matcher", @@ -2326,6 +2279,17 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", +] + [[package]] name = "ipconfig" version = "0.3.2" @@ -2346,9 +2310,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.9" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" dependencies = [ "memchr", "serde", @@ -2356,7 +2320,7 @@ dependencies = [ [[package]] name = "iron-remote-desktop" -version = "0.7.0" +version = "0.6.0" dependencies = [ "console_error_panic_hook", "tracing", @@ -2368,7 +2332,7 @@ dependencies = [ [[package]] name = "ironrdp" -version = "0.14.0" +version = "0.13.0" dependencies = [ "anyhow", "async-trait", @@ -2401,7 +2365,7 @@ dependencies = [ [[package]] name = "ironrdp-acceptor" -version = "0.8.0" +version = "0.7.0" dependencies = [ "ironrdp-async", "ironrdp-connector", @@ -2415,7 +2379,7 @@ dependencies = [ name = "ironrdp-ainput" version = "0.4.0" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "ironrdp-core", "ironrdp-dvc", "num-derive", @@ -2424,7 +2388,7 @@ dependencies = [ [[package]] name = "ironrdp-async" -version = "0.8.0" +version = "0.7.0" dependencies = [ "bytes", "ironrdp-connector", @@ -2445,7 +2409,7 @@ dependencies = [ [[package]] name = "ironrdp-blocking" -version = "0.8.0" +version = "0.7.0" dependencies = [ "bytes", "ironrdp-connector", @@ -2496,16 +2460,16 @@ dependencies = [ "url", "uuid", "whoami", - "windows 0.62.2", + "windows 0.61.3", "winit", "x509-cert", ] [[package]] name = "ironrdp-cliprdr" -version = "0.5.0" +version = "0.4.0" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "ironrdp-core", "ironrdp-pdu", "ironrdp-svc", @@ -2522,17 +2486,17 @@ dependencies = [ [[package]] name = "ironrdp-cliprdr-native" -version = "0.5.0" +version = "0.4.0" dependencies = [ "ironrdp-cliprdr", "ironrdp-core", "tracing", - "windows 0.62.2", + "windows 0.61.3", ] [[package]] name = "ironrdp-connector" -version = "0.8.0" +version = "0.7.1" dependencies = [ "arbitrary", "ironrdp-core", @@ -2596,7 +2560,7 @@ version = "0.1.3" [[package]] name = "ironrdp-futures" -version = "0.6.0" +version = "0.5.0" dependencies = [ "bytes", "futures-util", @@ -2621,10 +2585,10 @@ dependencies = [ [[package]] name = "ironrdp-graphics" -version = "0.7.0" +version = "0.6.0" dependencies = [ "bit_field", - "bitflags 2.10.0", + "bitflags 2.9.4", "bitvec", "bmp", "bytemuck", @@ -2632,6 +2596,7 @@ dependencies = [ "expect-test", "ironrdp-core", "ironrdp-pdu", + "lazy_static", "num-derive", "num-traits", "yuv", @@ -2651,7 +2616,7 @@ name = "ironrdp-mstsgu" version = "0.0.1" dependencies = [ "base64", - "bitflags 2.10.0", + "bitflags 2.9.4", "futures-util", "http-body-util", "hyper", @@ -2671,21 +2636,22 @@ name = "ironrdp-pdu" version = "0.6.0" dependencies = [ "bit_field", - "bitflags 2.10.0", + "bitflags 2.9.4", "byteorder", "der-parser", "expect-test", "ironrdp-core", "ironrdp-error", - "md-5 0.10.6", + "lazy_static", + "md-5", "num-bigint", "num-derive", "num-integer", "num-traits", - "pkcs1 0.7.5", - "sha1 0.10.6", + "pkcs1", + "sha1", "tap", - "thiserror 2.0.17", + "thiserror 2.0.16", "x509-cert", ] @@ -2702,16 +2668,16 @@ dependencies = [ [[package]] name = "ironrdp-rdcleanpath" -version = "0.2.1" +version = "0.2.0" dependencies = [ - "der 0.7.10", + "der", ] [[package]] name = "ironrdp-rdpdr" -version = "0.5.0" +version = "0.4.1" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "ironrdp-core", "ironrdp-error", "ironrdp-pdu", @@ -2721,7 +2687,7 @@ dependencies = [ [[package]] name = "ironrdp-rdpdr-native" -version = "0.5.0" +version = "0.4.0" dependencies = [ "ironrdp-core", "ironrdp-pdu", @@ -2742,7 +2708,7 @@ dependencies = [ name = "ironrdp-rdpsnd" version = "0.6.0" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "ironrdp-core", "ironrdp-pdu", "ironrdp-svc", @@ -2751,7 +2717,7 @@ dependencies = [ [[package]] name = "ironrdp-rdpsnd-native" -version = "0.4.2" +version = "0.4.1" dependencies = [ "anyhow", "bytemuck", @@ -2764,7 +2730,7 @@ dependencies = [ [[package]] name = "ironrdp-server" -version = "0.10.0" +version = "0.9.0" dependencies = [ "anyhow", "async-trait", @@ -2794,7 +2760,7 @@ dependencies = [ [[package]] name = "ironrdp-session" -version = "0.8.0" +version = "0.7.0" dependencies = [ "ironrdp-connector", "ironrdp-core", @@ -2817,7 +2783,7 @@ version = "0.0.0" name = "ironrdp-svc" version = "0.5.0" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "ironrdp-core", "ironrdp-pdu", ] @@ -2845,6 +2811,7 @@ dependencies = [ "ironrdp-rdpfile", "ironrdp-rdpsnd", "ironrdp-session", + "lazy_static", "paste", "png", "pretty_assertions", @@ -2871,7 +2838,7 @@ dependencies = [ [[package]] name = "ironrdp-tls" -version = "0.2.0" +version = "0.1.4" dependencies = [ "tokio", "tokio-native-tls", @@ -2881,7 +2848,7 @@ dependencies = [ [[package]] name = "ironrdp-tokio" -version = "0.8.0" +version = "0.7.0" dependencies = [ "bytes", "ironrdp-async", @@ -2902,7 +2869,7 @@ dependencies = [ "futures-channel", "futures-util", "getrandom 0.2.16", - "getrandom 0.3.4", + "getrandom 0.3.3", "gloo-net", "gloo-timers", "iron-remote-desktop", @@ -2932,27 +2899,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.2" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[package]] -name = "iso7816" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3c7e91da489667bb054f9cd2f1c60cc2ac4478a899f403d11dbc62189215b0" -dependencies = [ - "heapless", -] - -[[package]] -name = "iso7816-tlv" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7660d28d24a831d690228a275d544654a30f3b167a8e491cf31af5fe5058b546" -dependencies = [ - "untrusted", -] +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -2997,15 +2946,15 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.3.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" dependencies = [ "once_cell", "wasm-bindgen", @@ -3013,9 +2962,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.2.0-rc.0" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d546793a04a1d3049bd192856f804cfe96356e2cf36b54b4e575155babe9f41" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -3025,12 +2974,15 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" -version = "0.2.178" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libloading" @@ -3039,7 +2991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -3061,25 +3013,20 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.11" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "libc", - "redox_syscall 0.6.0", + "redox_syscall 0.5.17", ] [[package]] -name = "libz-sys" -version = "1.1.23" +name = "linked-hash-map" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" @@ -3101,30 +3048,40 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "litrs" -version = "1.0.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" [[package]] name = "lock_api" -version = "0.4.14" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.29" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] [[package]] name = "lru-slab" @@ -3157,17 +3114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest 0.10.7", -] - -[[package]] -name = "md-5" -version = "0.11.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9ec86664728010f574d67ef01aec964e6f1299241a3402857c1a8a390a62478" -dependencies = [ - "cfg-if", - "digest 0.11.0-rc.3", + "digest", ] [[package]] @@ -3176,20 +3123,20 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da5ac363534dce5fabf69949225e174fbf111a498bf0ff794c8ea1fba9f3dda" dependencies = [ - "digest 0.10.7", + "digest", ] [[package]] name = "memchr" -version = "2.7.6" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" -version = "0.9.9" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" dependencies = [ "libc", ] @@ -3212,39 +3159,21 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", - "wasi", - "windows-sys 0.61.2", -] - -[[package]] -name = "moka" -version = "0.12.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8261cd88c312e0004c1d51baad2980c66528dfdb2bee62003e643a4d8f86b077" -dependencies = [ - "crossbeam-channel", - "crossbeam-epoch", - "crossbeam-utils", - "equivalent", - "parking_lot", - "portable-atomic", - "rustc_version", - "smallvec", - "tagptr", - "uuid", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] name = "moxcms" -version = "0.7.11" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08" dependencies = [ "num-traits", "pxfm", @@ -3273,7 +3202,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "jni-sys", "log", "ndk-sys", @@ -3303,7 +3232,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "libc", @@ -3321,11 +3250,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.50.3" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3338,6 +3267,24 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "serde", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -3364,6 +3311,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -3371,13 +3329,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] name = "num_enum" -version = "0.7.5" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" dependencies = [ "num_enum_derive", "rustversion", @@ -3385,9 +3344,9 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.5" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3413,9 +3372,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc" dependencies = [ "objc2-encode", ] @@ -3426,29 +3385,29 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "block2", "libc", "objc2 0.5.2", "objc2-core-data", "objc2-core-image", "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", + "objc2-quartz-core", ] [[package]] name = "objc2-audio-toolbox" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08" +checksum = "10cbe18d879e20a4aea544f8befe38bcf52255eb63d3f23eca2842f3319e4c07" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "libc", - "objc2 0.6.3", + "objc2 0.6.2", "objc2-core-audio", "objc2-core-audio-types", "objc2-core-foundation", - "objc2-foundation 0.3.2", + "objc2-foundation 0.3.1", ] [[package]] @@ -3457,7 +3416,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "block2", "objc2 0.5.2", "objc2-core-location", @@ -3477,24 +3436,24 @@ dependencies = [ [[package]] name = "objc2-core-audio" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1eebcea8b0dbff5f7c8504f3107c68fc061a3eb44932051c8cf8a68d969c3b2" +checksum = "ca44961e888e19313b808f23497073e3f6b3c22bb485056674c8b49f3b025c82" dependencies = [ "dispatch2", - "objc2 0.6.3", + "objc2 0.6.2", "objc2-core-audio-types", "objc2-core-foundation", ] [[package]] name = "objc2-core-audio-types" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c" +checksum = "c0f1cc99bb07ad2ddb6527ddf83db6a15271bb036b3eb94b801cd44fdc666ee1" dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", + "bitflags 2.9.4", + "objc2 0.6.2", ] [[package]] @@ -3503,7 +3462,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -3511,26 +3470,13 @@ dependencies = [ [[package]] name = "objc2-core-foundation" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "dispatch2", - "objc2 0.6.3", -] - -[[package]] -name = "objc2-core-graphics" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" -dependencies = [ - "bitflags 2.10.0", - "dispatch2", - "objc2 0.6.3", - "objc2-core-foundation", - "objc2-io-surface", + "objc2 0.6.2", ] [[package]] @@ -3569,7 +3515,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "block2", "dispatch", "libc", @@ -3578,24 +3524,11 @@ dependencies = [ [[package]] name = "objc2-foundation" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-io-surface" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" -dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-core-foundation", + "objc2 0.6.2", ] [[package]] @@ -3616,7 +3549,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -3628,25 +3561,13 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", "objc2-metal", ] -[[package]] -name = "objc2-quartz-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" -dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-core-foundation", - "objc2-foundation 0.3.2", -] - [[package]] name = "objc2-symbols" version = "0.2.2" @@ -3663,7 +3584,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "block2", "objc2 0.5.2", "objc2-cloud-kit", @@ -3672,7 +3593,7 @@ dependencies = [ "objc2-core-location", "objc2-foundation 0.2.2", "objc2-link-presentation", - "objc2-quartz-core 0.2.2", + "objc2-quartz-core", "objc2-symbols", "objc2-uniform-type-identifiers", "objc2-user-notifications", @@ -3695,13 +3616,22 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "block2", "objc2 0.5.2", "objc2-core-location", "objc2-foundation 0.2.2", ] +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + [[package]] name = "oid" version = "0.2.1" @@ -3716,16 +3646,12 @@ name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -dependencies = [ - "critical-section", - "portable-atomic", -] [[package]] name = "once_cell_polyfill" -version = "1.70.2" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "oorandom" @@ -3734,12 +3660,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] -name = "openssl" -version = "0.10.75" +name = "opaque-debug" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "cfg-if", "foreign-types 0.3.2", "libc", @@ -3767,9 +3699,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.111" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -3779,18 +3711,18 @@ dependencies = [ [[package]] name = "opus2" -version = "0.3.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a4200c196ebf402d8a7091ce21845e8f2cd2f9c0c00deb73aaa14d024f6e6e" +checksum = "a8e79f6e5198dfc9ec913fd4ddc8b53b87263d59c500b989f8449bd566552ce3" dependencies = [ "libopus_sys", ] [[package]] name = "orbclient" -version = "0.3.49" +version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "247ad146e19b9437f8604c21f8652423595cf710ad108af40e77d3ae6e96b827" +checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" dependencies = [ "libredox", ] @@ -3806,61 +3738,47 @@ dependencies = [ [[package]] name = "p256" -version = "0.14.0-pre.11" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b374901df34ee468167a58e2a49e468cb059868479cafebeb804f6b855423d" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ "ecdsa", "elliptic-curve", - "primefield", "primeorder", "sha2", ] [[package]] name = "p384" -version = "0.14.0-pre.11" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "701032b3730df6b882496d6cee8221de0ce4bc11ddc64e6d89784aa5b8a6de30" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" dependencies = [ "ecdsa", "elliptic-curve", - "fiat-crypto", - "primefield", "primeorder", "sha2", ] [[package]] name = "p521" -version = "0.14.0-pre.11" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ba29c2906eb5c89a8c411c4f11243ee4e5517ee7d71d9a13fedc877a6057b1" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" dependencies = [ "base16ct", "ecdsa", "elliptic-curve", - "primefield", "primeorder", - "rand_core 0.9.3", + "rand_core 0.6.4", "sha2", ] -[[package]] -name = "page_size" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "parking_lot" -version = "0.12.5" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -3868,15 +3786,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.12" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.18", + "redox_syscall 0.5.17", "smallvec", - "windows-link", + "windows-targets 0.52.6", ] [[package]] @@ -3887,13 +3805,13 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" -version = "0.13.0-rc.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3fc18bb4460ac250ba6b75dfa7cf9d0b2273e3e623f660bd6ce2c3e902342e" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "digest 0.11.0-rc.3", + "digest", "hmac", - "sha1 0.11.0-rc.2", + "sha1", ] [[package]] @@ -3905,15 +3823,6 @@ dependencies = [ "base64ct", ] -[[package]] -name = "pem-rfc7468" -version = "1.0.0-rc.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e58fab693c712c0d4e88f8eb3087b6521d060bcaf76aeb20cb192d809115ba" -dependencies = [ - "base64ct", -] - [[package]] name = "percent-encoding" version = "2.3.2" @@ -3922,69 +3831,40 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "picky" -version = "7.0.0-rc.20" +version = "7.0.0-rc.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cdc52be663aebd70d7006ae305c87eb32a2b836d6c2f26f7e384f845d80b621" +checksum = "33807ce79d4b14a8918e968a8606e5142ddc6aec933acef79de0bd769cae5fb1" dependencies = [ - "aead", "aes", "aes-gcm", "aes-kw", "base64", - "block-buffer 0.11.0-rc.5", - "block-padding", "cbc", - "cipher", - "crypto-bigint", - "crypto-common 0.2.0-rc.4", - "crypto-primes", - "ctr", - "curve25519-dalek", - "der 0.8.0-rc.9", "des", - "digest 0.11.0-rc.3", - "ecdsa", - "ed25519", + "digest", "ed25519-dalek", - "elliptic-curve", - "ff", - "ghash", - "group", "hex", - "hkdf", "hmac", "http", - "inout", - "keccak", - "md-5 0.11.0-rc.2", + "md-5", + "num-bigint-dig", "p256", "p384", "p521", "pbkdf2", - "pem-rfc7468 1.0.0-rc.3", "picky-asn1", "picky-asn1-der", "picky-asn1-x509", - "pkcs1 0.8.0-rc.4", - "pkcs8", - "polyval", - "primefield", - "primeorder", - "rand 0.9.2", - "rand_core 0.9.3", + "rand 0.8.5", + "rand_core 0.6.4", "rc2", - "rfc6979", "rsa", - "sec1", "serde", "serde_json", - "sha1 0.11.0-rc.2", + "sha1", "sha2", "sha3", - "signature", - "spki 0.8.0-rc.4", - "thiserror 2.0.17", - "universal-hash", + "thiserror 1.0.69", "x25519-dalek", "zeroize", ] @@ -4004,9 +3884,9 @@ dependencies = [ [[package]] name = "picky-asn1-der" -version = "0.5.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b491eb61603cba1ad5c6be0269883538f8d74136c35e3641a840fb0fbcd41efc" +checksum = "9dccb53c26f70c082e008818f524bd45d057069517b047bd0c0ee062d6d7d7f2" dependencies = [ "picky-asn1", "serde", @@ -4015,12 +3895,12 @@ dependencies = [ [[package]] name = "picky-asn1-x509" -version = "0.15.2" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c97cd14d567a17755910fa8718277baf39d08682a980b1b1a4b4da7d0bc61a04" +checksum = "d493f73cf052073ca1fe38666f74c2396987aa6ea660e77dd624cc6c8f60389e" dependencies = [ "base64", - "crypto-bigint", + "num-bigint-dig", "oid", "picky-asn1", "picky-asn1-der", @@ -4031,31 +3911,26 @@ dependencies = [ [[package]] name = "picky-krb" -version = "0.12.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed61c8d7448649c031ecae02afb10c679524c7a9af5fb0fbee466b3cc0d6df1" +checksum = "1e78a55491723b0a10bc2c02709a8d92d74ef674fe1b569cb4a08bac3d105487" dependencies = [ "aes", - "block-buffer 0.11.0-rc.5", - "block-padding", "byteorder", "cbc", - "cipher", - "crypto-bigint", - "crypto-common 0.2.0-rc.4", + "crypto", "des", - "digest 0.11.0-rc.3", "hmac", - "inout", + "num-bigint-dig", "oid", "pbkdf2", "picky-asn1", "picky-asn1-der", "picky-asn1-x509", - "rand 0.9.2", + "rand 0.8.5", "serde", - "sha1 0.11.0-rc.2", - "thiserror 2.0.17", + "sha1", + "thiserror 1.0.69", "uuid", ] @@ -4103,28 +3978,19 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "der 0.7.10", - "spki 0.7.3", -] - -[[package]] -name = "pkcs1" -version = "0.8.0-rc.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e" -dependencies = [ - "der 0.8.0-rc.9", - "spki 0.8.0-rc.4", + "der", + "pkcs8", + "spki", ] [[package]] name = "pkcs8" -version = "0.11.0-rc.7" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93eac55f10aceed84769df670ea4a32d2ffad7399400d41ee1c13b1cd8e1b478" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ - "der 0.8.0-rc.9", - "spki 0.8.0-rc.4", + "der", + "spki", ] [[package]] @@ -4167,7 +4033,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "crc32fast", "fdeflate", "flate2", @@ -4185,26 +4051,21 @@ dependencies = [ "hermit-abi", "pin-project-lite", "rustix 1.1.2", - "windows-sys 0.61.2", + "windows-sys 0.61.0", ] [[package]] name = "polyval" -version = "0.7.0-rc.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffd40cc99d0fbb02b4b3771346b811df94194bc103983efa0203c8893755085" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", + "opaque-debug", "universal-hash", ] -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" - [[package]] name = "portpicker" version = "0.1.1" @@ -4216,9 +4077,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" dependencies = [ "zerovec", ] @@ -4249,23 +4110,20 @@ dependencies = [ ] [[package]] -name = "primefield" -version = "0.14.0-pre.6" +name = "prettyplease" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcd4a163053332fd93f39b81c133e96a98567660981654579c90a99062fbf5" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ - "crypto-bigint", - "ff", - "rand_core 0.9.3", - "subtle", - "zeroize", + "proc-macro2", + "syn", ] [[package]] name = "primeorder" -version = "0.14.0-pre.9" +version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c36e8766fcd270fa9c665b9dc364f570695f5a59240949441b077a397f15b74" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ "elliptic-curve", ] @@ -4287,22 +4145,23 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.9.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" +checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.10.0", + "bitflags 2.9.4", + "lazy_static", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", @@ -4315,9 +4174,9 @@ dependencies = [ [[package]] name = "pxfm" -version = "0.1.27" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" +checksum = "83f9b339b02259ada5c0f4a389b7fb472f933aa17ce176fd2ad98f28bb401fde" dependencies = [ "num-traits", ] @@ -4359,8 +4218,8 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.1", - "thiserror 2.0.17", + "socket2 0.6.0", + "thiserror 2.0.16", "tokio", "tracing", "web-time", @@ -4373,7 +4232,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "getrandom 0.3.4", + "getrandom 0.3.3", "lru-slab", "rand 0.9.2", "ring", @@ -4381,7 +4240,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.17", + "thiserror 2.0.16", "tinyvec", "tracing", "web-time", @@ -4396,16 +4255,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.1", + "socket2 0.6.0", "tracing", "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -4478,7 +4337,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.3.3", ] [[package]] @@ -4518,9 +4377,9 @@ dependencies = [ [[package]] name = "rc2" -version = "0.9.0-pre.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03621ac292cc723def9e0fd0eb9573b1df8d6a9ee7ad637fe94dfc153705f3c" +checksum = "62c64daa8e9438b84aaae55010a93f396f8e60e3911590fcba770d04643fc1dd" dependencies = [ "cipher", ] @@ -4536,27 +4395,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.18" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.10.0", -] - -[[package]] -name = "redox_syscall" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5" -dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", @@ -4566,9 +4416,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -4577,9 +4427,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "relative-path" @@ -4589,9 +4439,9 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "reqwest" -version = "0.12.26" +version = "0.12.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" dependencies = [ "base64", "bytes", @@ -4642,15 +4492,15 @@ dependencies = [ [[package]] name = "resolv-conf" -version = "0.7.6" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" +checksum = "6b3789b30bd25ba102de4beabd95d21ac45b69b1be7d14522bab988c526d6799" [[package]] name = "rfc6979" -version = "0.5.0-rc.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d369f9c4f79388704648e7bcb92749c0d6cf4397039293a9b747694fa4fb4bae" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ "hmac", "subtle", @@ -4681,40 +4531,42 @@ dependencies = [ [[package]] name = "rsa" -version = "0.10.0-rc.9" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8955ab399f6426998fde6b76ae27233cce950705e758a6c17afd2f6d0e5d52" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" dependencies = [ - "const-oid 0.10.1", - "crypto-bigint", - "crypto-primes", - "digest 0.11.0-rc.3", - "pkcs1 0.8.0-rc.4", + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", "pkcs8", - "rand_core 0.9.3", - "sha1 0.11.0-rc.2", + "rand_core 0.6.4", + "sha1", "signature", - "spki 0.8.0-rc.4", + "spki", "subtle", "zeroize", ] [[package]] name = "rstest" -version = "0.26.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a3193c063baaa2a95a33f03035c8a72b83d97a54916055ba22d35ed3839d49" +checksum = "6fc39292f8613e913f7df8fa892b8944ceb47c247b78e1b1ae2f09e019be789d" dependencies = [ "futures-timer", "futures-util", "rstest_macros", + "rustc_version", ] [[package]] name = "rstest_macros" -version = "0.26.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0" +checksum = "1f168d99749d307be9de54d23fd226628d99768225ef08f6ffb52e0182a27746" dependencies = [ "cfg-if", "glob", @@ -4728,6 +4580,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + [[package]] name = "rustc-hash" version = "2.1.1" @@ -4758,7 +4616,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys 0.4.15", @@ -4771,18 +4629,18 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.61.2", + "windows-sys 0.61.0", ] [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ "aws-lc-rs", "log", @@ -4796,14 +4654,14 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.5.1", + "security-framework 3.5.0", ] [[package]] @@ -4817,9 +4675,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ "web-time", "zeroize", @@ -4827,9 +4685,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" dependencies = [ "aws-lc-rs", "ring", @@ -4845,9 +4703,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rusty-fork" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" dependencies = [ "fnv", "quick-error", @@ -4876,7 +4734,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.61.0", ] [[package]] @@ -4906,33 +4764,25 @@ dependencies = [ [[package]] name = "sec1" -version = "0.8.0-rc.10" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dff52f6118bc9f0ac974a54a639d499ac26a6cad7a6e39bc0990c19625e793b" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", - "der 0.8.0-rc.9", - "hybrid-array", + "der", + "generic-array", + "pkcs8", "subtle", "zeroize", ] -[[package]] -name = "secrecy" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" -dependencies = [ - "zeroize", -] - [[package]] name = "security-framework" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -4941,11 +4791,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.5.1" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +checksum = "cc198e42d9b7510827939c9a15f5062a0c913f3371d765977e586d2fe6c16f4a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -4970,9 +4820,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.228" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" dependencies = [ "serde_core", "serde_derive", @@ -4990,18 +4840,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" dependencies = [ "proc-macro2", "quote", @@ -5023,9 +4873,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" dependencies = [ "serde_core", ] @@ -5042,16 +4892,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serdect" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3ef0e35b322ddfaecbc60f34ab448e157e48531288ee49fafbb053696b8ffe2" -dependencies = [ - "base16ct", - "serde", -] - [[package]] name = "sha1" version = "0.10.6" @@ -5060,38 +4900,27 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha1" -version = "0.11.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e046edf639aa2e7afb285589e5405de2ef7e61d4b0ac1e30256e3eab911af9" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.11.0-rc.3", + "digest", ] [[package]] name = "sha2" -version = "0.11.0-rc.2" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1e3878ab0f98e35b2df35fe53201d088299b41a6bb63e3e34dada2ac4abd924" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.11.0-rc.3", + "digest", ] [[package]] name = "sha3" -version = "0.11.0-rc.3" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2103ca0e6f4e9505eae906de5e5883e06fc3b2232fb5d6914890c7bbcb62f478" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.11.0-rc.3", + "digest", "keccak", ] @@ -5122,9 +4951,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", "mio", @@ -5133,28 +4962,28 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.7" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] [[package]] name = "signature" -version = "3.0.0-rc.4" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc280a6ff65c79fbd6622f64d7127f32b85563bca8c53cd2e9141d6744a9056d" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest 0.11.0-rc.3", - "rand_core 0.9.3", + "digest", + "rand_core 0.6.4", ] [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "slab" @@ -5174,7 +5003,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "calloop", "calloop-wayland-source", "cursor-icon", @@ -5214,43 +5043,43 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] name = "softbuffer" -version = "0.4.8" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" +checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" dependencies = [ "as-raw-xcb-connection", "bytemuck", + "cfg_aliases", + "core-graphics 0.24.0", "drm", "fastrand", + "foreign-types 0.5.0", "js-sys", + "log", "memmap2", - "ndk", - "objc2 0.6.3", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.2", - "objc2-quartz-core 0.3.2", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-quartz-core", "raw-window-handle", - "redox_syscall 0.5.18", - "rustix 1.1.2", + "redox_syscall 0.5.17", + "rustix 0.38.44", "tiny-xlib", - "tracing", "wasm-bindgen", "wayland-backend", "wayland-client", "wayland-sys", "web-sys", - "windows-sys 0.61.2", + "windows-sys 0.59.0", "x11rb", ] @@ -5259,9 +5088,6 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] [[package]] name = "spki" @@ -5270,92 +5096,62 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", - "der 0.7.10", -] - -[[package]] -name = "spki" -version = "0.8.0-rc.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8baeff88f34ed0691978ec34440140e1572b68c7dd4a495fd14a3dc1944daa80" -dependencies = [ - "base64ct", - "der 0.8.0-rc.9", + "der", ] [[package]] name = "sspi" -version = "0.18.5" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f73fe6be958ae27fa8e982d9acc42d16f34eb74714d95bb53015528667cae4" +checksum = "523f6a99e26c1e6476a424d54bbda5354a01ee7f18b9d93dc48a8fd45ae8189b" dependencies = [ "async-dnssd", "async-recursion", - "bitflags 2.10.0", - "block-buffer 0.11.0-rc.5", + "bitflags 2.9.4", "byteorder", "cfg-if", - "crypto-bigint", - "crypto-common 0.2.0-rc.4", "crypto-mac", - "crypto-primes", - "cryptoki", - "curve25519-dalek", - "der 0.8.0-rc.9", - "digest 0.11.0-rc.3", - "ed25519-dalek", - "ff", "futures", - "getrandom 0.3.4", - "group", - "hickory-proto", "hickory-resolver", "hmac", - "md-5 0.11.0-rc.2", + "lazy_static", + "md-5", "md4", + "num-bigint-dig", "num-derive", "num-traits", "oid", - "p256", - "p384", - "p521", - "pem-rfc7468 1.0.0-rc.3", "picky", "picky-asn1", "picky-asn1-der", "picky-asn1-x509", "picky-krb", - "pkcs1 0.8.0-rc.4", - "pkcs8", "portpicker", - "primefield", - "primeorder", - "rand 0.9.2", + "rand 0.8.5", "reqwest", "rsa", "rustls", "rustls-native-certs", "serde", - "sha1 0.11.0-rc.2", + "serde_derive", + "sha1", "sha2", - "signature", - "spki 0.8.0-rc.4", "time", "tokio", "tracing", "url", "uuid", - "windows 0.62.2", + "windows 0.61.3", "windows-registry", - "winscard", + "windows-sys 0.60.2", "zeroize", ] [[package]] name = "stable_deref_trait" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "strck" @@ -5393,9 +5189,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.111" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -5428,7 +5224,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -5443,12 +5239,6 @@ dependencies = [ "libc", ] -[[package]] -name = "tagptr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" - [[package]] name = "tap" version = "1.0.1" @@ -5462,10 +5252,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.3.3", "once_cell", "rustix 1.1.2", - "windows-sys 0.61.2", + "windows-sys 0.61.0", ] [[package]] @@ -5479,11 +5269,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.16", ] [[package]] @@ -5499,9 +5289,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", @@ -5595,9 +5385,9 @@ checksum = "9ab95735ea2c8fd51154d01e39cf13912a78071c2d89abc49a7ef102a7dd725a" [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -5651,26 +5441,29 @@ dependencies = [ [[package]] name = "tokio" -version = "1.48.0" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ + "backtrace", "bytes", + "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "slab", + "socket2 0.6.0", "tokio-macros", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", @@ -5689,9 +5482,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.4" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" dependencies = [ "rustls", "tokio", @@ -5699,9 +5492,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.28.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +checksum = "489a59b6730eda1b0171fcfda8b121f4bee2b35cba8645ca35c5f7ba3eb736c1" dependencies = [ "futures-util", "log", @@ -5717,9 +5510,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.17" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ "bytes", "futures-core", @@ -5730,9 +5523,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.9+spec-1.0.0" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5238e643fc34a1d5d7e753e1532a91912d74b63b92b3ea51fde8d1b7bc79dd" +checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" dependencies = [ "indexmap", "serde_core", @@ -5745,18 +5538,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.4+spec-1.0.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe3cea6b2aa3b910092f6abd4053ea464fab5f9c170ba5e9a6aead16ec4af2b6" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.23.10+spec-1.0.0" +version = "0.23.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" dependencies = [ "indexmap", "toml_datetime", @@ -5766,18 +5559,18 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.5+spec-1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c03bee5ce3696f31250db0bbaff18bc43301ce0e8db2ed1f07cbb2acf89984c" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" dependencies = [ "winnow", ] [[package]] name = "toml_writer" -version = "1.0.5+spec-1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9cd6190959dce0994aa8970cd32ab116d1851ead27e866039acaf2524ce44fa" +checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109" [[package]] name = "tower" @@ -5796,11 +5589,11 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "bytes", "futures-util", "http", @@ -5826,9 +5619,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.43" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -5838,9 +5631,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.31" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", @@ -5849,9 +5642,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.35" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -5870,9 +5663,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.22" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ "matchers", "nu-ansi-term", @@ -5929,9 +5722,9 @@ checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" [[package]] name = "tungstenite" -version = "0.28.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d" dependencies = [ "bytes", "data-encoding", @@ -5942,16 +5735,16 @@ dependencies = [ "rand 0.9.2", "rustls", "rustls-pki-types", - "sha1 0.10.6", - "thiserror 2.0.17", + "sha1", + "thiserror 2.0.16", "utf-8", ] [[package]] name = "typenum" -version = "1.19.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unarray" @@ -5961,9 +5754,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-segmentation" @@ -5973,17 +5766,17 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" [[package]] name = "universal-hash" -version = "0.6.0-rc.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55be643b40a21558f44806b53ee9319595bc7ca6896372e4e08e5d7d83c9cd6" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common 0.2.0-rc.4", + "crypto-common", "subtle", ] @@ -6025,13 +5818,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.19.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.3.3", "js-sys", - "serde_core", + "serde", "wasm-bindgen", ] @@ -6118,6 +5911,15 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -6135,9 +5937,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" dependencies = [ "cfg-if", "once_cell", @@ -6147,10 +5949,24 @@ dependencies = [ ] [[package]] -name = "wasm-bindgen-futures" -version = "0.4.56" +name = "wasm-bindgen-backend" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67" dependencies = [ "cfg-if", "js-sys", @@ -6161,9 +5977,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6171,22 +5987,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ - "bumpalo", "proc-macro2", "quote", "syn", + "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" dependencies = [ "unicode-ident", ] @@ -6211,7 +6027,7 @@ version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "rustix 1.1.2", "wayland-backend", "wayland-scanner", @@ -6223,7 +6039,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "cursor-icon", "wayland-backend", ] @@ -6245,7 +6061,7 @@ version = "0.32.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "wayland-backend", "wayland-client", "wayland-scanner", @@ -6257,7 +6073,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a07a14257c077ab3279987c4f8bb987851bf57081b93710381daea94f2c2c032" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "wayland-backend", "wayland-client", "wayland-protocols", @@ -6270,7 +6086,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "wayland-backend", "wayland-client", "wayland-protocols", @@ -6302,9 +6118,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.83" +version = "0.3.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" dependencies = [ "js-sys", "wasm-bindgen", @@ -6322,9 +6138,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.4" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" dependencies = [ "rustls-pki-types", ] @@ -6342,9 +6158,9 @@ dependencies = [ [[package]] name = "widestring" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" +checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" [[package]] name = "winapi" @@ -6368,7 +6184,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.61.0", ] [[package]] @@ -6389,23 +6205,24 @@ dependencies = [ [[package]] name = "windows" -version = "0.62.2" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ "windows-collections", - "windows-core 0.62.2", + "windows-core 0.61.2", "windows-future", + "windows-link 0.1.3", "windows-numerics", ] [[package]] name = "windows-collections" -version = "0.3.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.62.2", + "windows-core 0.61.2", ] [[package]] @@ -6420,33 +6237,46 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.62.2" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", - "windows-link", - "windows-result 0.4.1", - "windows-strings", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.0", + "windows-result 0.4.0", + "windows-strings 0.5.0", ] [[package]] name = "windows-future" -version = "0.3.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core 0.62.2", - "windows-link", + "windows-core 0.61.2", + "windows-link 0.1.3", "windows-threading", ] [[package]] name = "windows-implement" -version = "0.60.2" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", @@ -6455,9 +6285,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.3" +version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", @@ -6466,29 +6296,35 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.2.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" [[package]] name = "windows-numerics" -version = "0.3.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.62.2", - "windows-link", + "windows-core 0.61.2", + "windows-link 0.1.3", ] [[package]] name = "windows-registry" -version = "0.6.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ - "windows-link", - "windows-result 0.4.1", - "windows-strings", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -6502,20 +6338,38 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.4.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", ] [[package]] name = "windows-strings" -version = "0.5.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", ] [[package]] @@ -6560,16 +6414,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.5", + "windows-targets 0.53.3", ] [[package]] name = "windows-sys" -version = "0.61.2" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" dependencies = [ - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -6620,28 +6474,28 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.5" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "windows-link 0.1.3", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] name = "windows-threading" -version = "0.2.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -6664,9 +6518,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" @@ -6688,9 +6542,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" @@ -6712,9 +6566,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" [[package]] name = "windows_i686_gnullvm" @@ -6724,9 +6578,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] name = "windows_i686_msvc" @@ -6748,9 +6602,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" @@ -6772,9 +6626,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] name = "windows_x86_64_gnullvm" @@ -6796,9 +6650,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" @@ -6820,9 +6674,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winit" @@ -6833,14 +6687,14 @@ dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.10.0", + "bitflags 2.9.4", "block2", "bytemuck", "calloop", "cfg_aliases", "concurrent-queue", "core-foundation 0.9.4", - "core-graphics", + "core-graphics 0.23.2", "cursor-icon", "dpi", "js-sys", @@ -6878,9 +6732,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.14" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] @@ -6905,29 +6759,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "winscard" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b6ec4e6176df62589d1ac9950f6295be87ca06ee61a7c9a579a2bcc80efe34" -dependencies = [ - "bitflags 2.10.0", - "crypto-bigint", - "flate2", - "iso7816", - "iso7816-tlv", - "num-derive", - "num-traits", - "picky", - "picky-asn1-x509", - "rand_core 0.9.3", - "rsa", - "sha1 0.11.0-rc.2", - "time", - "tracing", - "uuid", -] - [[package]] name = "wit-bindgen" version = "0.46.0" @@ -6936,9 +6767,9 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -6983,12 +6814,12 @@ checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" [[package]] name = "x25519-dalek" -version = "3.0.0-pre.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a45998121837fd8c92655d2334aa8f3e5ef0645cdfda5b321b13760c548fd55" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek", - "rand_core 0.9.3", + "rand_core 0.6.4", "serde", "zeroize", ] @@ -6999,9 +6830,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" dependencies = [ - "const-oid 0.9.6", - "der 0.7.10", - "spki 0.7.3", + "const-oid", + "der", + "spki", "tls_codec", ] @@ -7017,7 +6848,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "dlib", "log", "once_cell", @@ -7063,10 +6894,11 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ + "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -7074,9 +6906,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", @@ -7086,27 +6918,27 @@ dependencies = [ [[package]] name = "yuv" -version = "0.8.9" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28f1bad143caadcfcaec93039dc9c40a30fc86f23d9e7cc03764a39fe51d9d43" +checksum = "c3bb136c6b36d2856e62f3121892ae59f32caf5b0a9ff184600f0f5f4d5ff075" dependencies = [ "num-traits", ] [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", @@ -7136,9 +6968,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.2" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -7156,9 +6988,9 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" dependencies = [ "displaydoc", "yoke", @@ -7167,9 +6999,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", @@ -7178,9 +7010,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 72904a94..ba8229bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,11 +34,12 @@ categories = ["network-programming"] # even for private dependencies. expect-test = "1" proptest = "1.4" -rstest = "0.26" +rstest = "0.25" # Note: we are trying to move away from using these crates. # They are being kept around for now for legacy compatibility, # but new usage should be avoided. +lazy_static = "1.4" # Legacy crate; prefer std::sync::LazyLock or LazyCell num-derive = "0.4" num-traits = "0.2" @@ -92,7 +93,6 @@ fn_to_numeric_cast_any = "warn" ptr_cast_constness = "warn" # == Correctness == # -as_conversions = "warn" cast_lossless = "warn" cast_possible_truncation = "warn" cast_possible_wrap = "warn" @@ -115,7 +115,6 @@ same_name_method = "warn" string_slice = "warn" suspicious_xor_used_as_pow = "warn" unused_result_ok = "warn" -missing_panics_doc = "warn" # == Style, readability == # semicolon_outside_block = "warn" # With semicolon-outside-block-ignore-multiline = true @@ -127,7 +126,6 @@ empty_enum_variants_with_brackets = "warn" deref_by_slicing = "warn" multiple_inherent_impl = "warn" map_with_unused_argument_over_ranges = "warn" -partial_pub_fields = "warn" trait_duplication_in_bounds = "warn" type_repetition_in_bounds = "warn" checked_conversions = "warn" @@ -141,12 +139,8 @@ unused_self = "warn" useless_let_if_seq = "warn" string_add = "warn" range_plus_one = "warn" -self_named_module_files = "warn" +# TODO: self_named_module_files = "warn" # TODO: partial_pub_fields = "warn" (should we enable only in pdu crates?) -redundant_type_annotations = "warn" -unnecessary_self_imports = "warn" -try_err = "warn" -rest_pat_in_fully_bound_structs = "warn" # == Compile-time / optimization == # doc_include_without_cfg = "warn" @@ -156,7 +150,6 @@ or_fun_call = "warn" rc_buffer = "warn" string_lit_chars_any = "warn" unnecessary_box_returns = "warn" -large_futures = "warn" # == Extra-pedantic clippy == # allow_attributes = "warn" diff --git a/benches/Cargo.toml b/benches/Cargo.toml index 19a87c6f..deb14ee8 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -17,7 +17,7 @@ qoiz = ["ironrdp/qoiz"] [dependencies] anyhow = "1.0.99" async-trait = "0.1.89" -bytesize = "2.3" +bytesize = "2.1.0" ironrdp = { path = "../crates/ironrdp", features = [ "server", "pdu", diff --git a/benches/src/perfenc.rs b/benches/src/perfenc.rs index 5abc94f3..fc486460 100644 --- a/benches/src/perfenc.rs +++ b/benches/src/perfenc.rs @@ -68,7 +68,7 @@ async fn main() -> Result<(), anyhow::Error> { let mut updates = DisplayUpdates::new(file, DesktopSize { width, height }, fps); while let Some(up) = updates.next_update().await? { if let DisplayUpdate::Bitmap(ref up) = up { - total_raw += u64::try_from(up.data.len())?; + total_raw += up.data.len() as u64; } else { eprintln!("Invalid update"); break; @@ -78,7 +78,7 @@ async fn main() -> Result<(), anyhow::Error> { let Some(frag) = iter.next().await else { break; }; - let len = u64::try_from(frag?.data.len())?; + let len = frag?.data.len() as u64; total_enc += len; } n_updates += 1; @@ -87,7 +87,6 @@ async fn main() -> Result<(), anyhow::Error> { } println!(); - #[expect(clippy::as_conversions, reason = "casting u64 to f64")] let ratio = total_enc as f64 / total_raw as f64; let percent = 100.0 - ratio * 100.0; println!("Encoder: {encoder:?}"); diff --git a/clippy.toml b/clippy.toml index 17e7e90f..dd6a9fe4 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,4 +1,4 @@ -msrv = "1.87" +msrv = "1.84" semicolon-outside-block-ignore-multiline = true accept-comment-above-statement = true accept-comment-above-attributes = true diff --git a/crates/iron-remote-desktop/CHANGELOG.md b/crates/iron-remote-desktop/CHANGELOG.md index 2f076f11..fa04f3b3 100644 --- a/crates/iron-remote-desktop/CHANGELOG.md +++ b/crates/iron-remote-desktop/CHANGELOG.md @@ -6,12 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.7.0](https://github.com/Devolutions/IronRDP/compare/iron-remote-desktop-v0.6.0...iron-remote-desktop-v0.7.0)] - 2025-09-29 - -### Bug Fixes - -- [**breaking**] Changed onClipboardChanged to not consume the input (#992) ([6127e13c83](https://github.com/Devolutions/IronRDP/commit/6127e13c836d06764d483b6b55188fd23a4314a2)) - ## [[0.6.0](https://github.com/Devolutions/IronRDP/compare/iron-remote-desktop-v0.5.0...iron-remote-desktop-v0.6.0)] - 2025-08-29 ### Features diff --git a/crates/iron-remote-desktop/Cargo.toml b/crates/iron-remote-desktop/Cargo.toml index ba5d8a90..7c082782 100644 --- a/crates/iron-remote-desktop/Cargo.toml +++ b/crates/iron-remote-desktop/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "iron-remote-desktop" -version = "0.7.0" +version = "0.6.0" readme = "README.md" description = "Helper crate for building WASM modules compatible with iron-remote-desktop WebComponent" edition.workspace = true diff --git a/crates/iron-remote-desktop/src/lib.rs b/crates/iron-remote-desktop/src/lib.rs index 5dd8dd60..48367f94 100644 --- a/crates/iron-remote-desktop/src/lib.rs +++ b/crates/iron-remote-desktop/src/lib.rs @@ -159,8 +159,8 @@ macro_rules! make_bridge { } #[wasm_bindgen(js_name = onClipboardPaste)] - pub async fn on_clipboard_paste(&self, content: &ClipboardData) -> Result<(), IronError> { - $crate::Session::on_clipboard_paste(&self.0, &content.0) + pub async fn on_clipboard_paste(&self, content: ClipboardData) -> Result<(), IronError> { + $crate::Session::on_clipboard_paste(&self.0, content.0) .await .map_err(IronError) } diff --git a/crates/iron-remote-desktop/src/session.rs b/crates/iron-remote-desktop/src/session.rs index d9f973d8..afe9f2d5 100644 --- a/crates/iron-remote-desktop/src/session.rs +++ b/crates/iron-remote-desktop/src/session.rs @@ -84,7 +84,7 @@ pub trait Session { fn on_clipboard_paste( &self, - content: &Self::ClipboardData, + content: Self::ClipboardData, ) -> impl core::future::Future>; fn resize( diff --git a/crates/ironrdp-acceptor/CHANGELOG.md b/crates/ironrdp-acceptor/CHANGELOG.md index 4918e46f..d915be30 100644 --- a/crates/ironrdp-acceptor/CHANGELOG.md +++ b/crates/ironrdp-acceptor/CHANGELOG.md @@ -6,17 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.8.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-acceptor-v0.7.0...ironrdp-acceptor-v0.8.0)] - 2025-12-18 - -### Bug Fixes - -- [**breaking**] Use static dispatch for NetworkClient trait ([#1043](https://github.com/Devolutions/IronRDP/issues/1043)) ([bca6d190a8](https://github.com/Devolutions/IronRDP/commit/bca6d190a870708468534d224ff225a658767a9a)) - - - Rename `AsyncNetworkClient` to `NetworkClient` - - Replace dynamic dispatch (`Option<&mut dyn ...>`) with static dispatch - using generics (`&mut N where N: NetworkClient`) - - Reorder `connect_finalize` parameters for consistency across crates - ## [[0.6.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-acceptor-v0.5.0...ironrdp-acceptor-v0.6.0)] - 2025-07-08 ### Features diff --git a/crates/ironrdp-acceptor/Cargo.toml b/crates/ironrdp-acceptor/Cargo.toml index a3c42b9d..a4ef47db 100644 --- a/crates/ironrdp-acceptor/Cargo.toml +++ b/crates/ironrdp-acceptor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-acceptor" -version = "0.8.0" +version = "0.7.0" readme = "README.md" description = "State machines to drive an RDP connection acceptance sequence" edition.workspace = true @@ -19,8 +19,8 @@ test = false ironrdp-core = { path = "../ironrdp-core", version = "0.1", features = ["alloc"] } # public ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6" } # public ironrdp-svc = { path = "../ironrdp-svc", version = "0.5" } # public -ironrdp-connector = { path = "../ironrdp-connector", version = "0.8" } # public -ironrdp-async = { path = "../ironrdp-async", version = "0.8" } # public +ironrdp-connector = { path = "../ironrdp-connector", version = "0.7" } # public +ironrdp-async = { path = "../ironrdp-async", version = "0.7" } # public tracing = { version = "0.1", features = ["log"] } [lints] diff --git a/crates/ironrdp-acceptor/src/channel_connection.rs b/crates/ironrdp-acceptor/src/channel_connection.rs index 62bd6cd3..2c6aa62e 100644 --- a/crates/ironrdp-acceptor/src/channel_connection.rs +++ b/crates/ironrdp-acceptor/src/channel_connection.rs @@ -4,8 +4,9 @@ use ironrdp_connector::{ reason_err, ConnectorError, ConnectorErrorExt as _, ConnectorResult, Sequence, State, Written, }; use ironrdp_core::WriteBuf; -use ironrdp_pdu::mcs; use ironrdp_pdu::x224::X224; +use ironrdp_pdu::{self as pdu}; +use pdu::mcs; use tracing::debug; #[derive(Debug)] @@ -56,13 +57,13 @@ impl State for ChannelConnectionState { } impl Sequence for ChannelConnectionSequence { - fn next_pdu_hint(&self) -> Option<&dyn ironrdp_pdu::PduHint> { + fn next_pdu_hint(&self) -> Option<&dyn pdu::PduHint> { match &self.state { ChannelConnectionState::Consumed => None, - ChannelConnectionState::WaitErectDomainRequest => Some(&ironrdp_pdu::X224_HINT), - ChannelConnectionState::WaitAttachUserRequest => Some(&ironrdp_pdu::X224_HINT), + ChannelConnectionState::WaitErectDomainRequest => Some(&pdu::X224_HINT), + ChannelConnectionState::WaitAttachUserRequest => Some(&pdu::X224_HINT), ChannelConnectionState::SendAttachUserConfirm => None, - ChannelConnectionState::WaitChannelJoinRequest { .. } => Some(&ironrdp_pdu::X224_HINT), + ChannelConnectionState::WaitChannelJoinRequest { .. } => Some(&pdu::X224_HINT), ChannelConnectionState::SendChannelJoinConfirm { .. } => None, ChannelConnectionState::AllJoined => None, } diff --git a/crates/ironrdp-acceptor/src/connection.rs b/crates/ironrdp-acceptor/src/connection.rs index 6643b941..ca27245c 100644 --- a/crates/ironrdp-acceptor/src/connection.rs +++ b/crates/ironrdp-acceptor/src/connection.rs @@ -123,9 +123,6 @@ impl Acceptor { } } - /// # Panics - /// - /// Panics if state is not [AcceptorState::SecurityUpgrade]. pub fn mark_security_upgrade_as_done(&mut self) { assert!(self.reached_security_upgrade().is_some()); self.step(&[], &mut WriteBuf::new()).expect("transition to next state"); @@ -136,9 +133,6 @@ impl Acceptor { matches!(self.state, AcceptorState::Credssp { .. }) } - /// # Panics - /// - /// Panics if state is not [AcceptorState::Credssp]. pub fn mark_credssp_as_done(&mut self) { assert!(self.should_perform_credssp()); let res = self.step(&[], &mut WriteBuf::new()).expect("transition to next state"); @@ -713,7 +707,7 @@ impl Sequence for Acceptor { AcceptorState::Accepted { channels, client_capabilities, - input_events: finalization.into_input_events(), + input_events: finalization.input_events, } } else { AcceptorState::ConnectionFinalization { diff --git a/crates/ironrdp-acceptor/src/credssp.rs b/crates/ironrdp-acceptor/src/credssp.rs index cf50ab56..f8840780 100644 --- a/crates/ironrdp-acceptor/src/credssp.rs +++ b/crates/ironrdp-acceptor/src/credssp.rs @@ -1,4 +1,4 @@ -use ironrdp_async::NetworkClient; +use ironrdp_async::AsyncNetworkClient; use ironrdp_connector::sspi::credssp::{ CredSspServer, CredentialsProxy, ServerError, ServerMode, ServerState, TsRequest, }; @@ -71,7 +71,7 @@ impl CredentialsProxy for CredentialsProxyImpl<'_> { pub(crate) async fn resolve_generator( generator: &mut CredsspProcessGenerator<'_>, - network_client: &mut impl NetworkClient, + network_client: &mut dyn AsyncNetworkClient, ) -> Result { let mut state = generator.start(); diff --git a/crates/ironrdp-acceptor/src/finalization.rs b/crates/ironrdp-acceptor/src/finalization.rs index 9961e87c..6192ebbf 100644 --- a/crates/ironrdp-acceptor/src/finalization.rs +++ b/crates/ironrdp-acceptor/src/finalization.rs @@ -1,7 +1,8 @@ use ironrdp_connector::{ConnectorError, ConnectorErrorExt as _, ConnectorResult, Sequence, State, Written}; use ironrdp_core::WriteBuf; -use ironrdp_pdu::rdp; use ironrdp_pdu::x224::X224; +use ironrdp_pdu::{self as pdu}; +use pdu::rdp; use tracing::debug; use crate::util::{self, wrap_share_data}; @@ -12,7 +13,7 @@ pub struct FinalizationSequence { user_channel_id: u16, io_channel_id: u16, - input_events: Vec>, + pub input_events: Vec>, } #[derive(Default, Debug)] @@ -59,13 +60,13 @@ impl State for FinalizationState { } impl Sequence for FinalizationSequence { - fn next_pdu_hint(&self) -> Option<&dyn ironrdp_pdu::PduHint> { + fn next_pdu_hint(&self) -> Option<&dyn pdu::PduHint> { match &self.state { FinalizationState::Consumed => None, - FinalizationState::WaitSynchronize => Some(&ironrdp_pdu::X224Hint), - FinalizationState::WaitControlCooperate => Some(&ironrdp_pdu::X224Hint), - FinalizationState::WaitRequestControl => Some(&ironrdp_pdu::X224Hint), - FinalizationState::WaitFontList => Some(&ironrdp_pdu::RdpHint), + FinalizationState::WaitSynchronize => Some(&pdu::X224Hint), + FinalizationState::WaitControlCooperate => Some(&pdu::X224Hint), + FinalizationState::WaitRequestControl => Some(&pdu::X224Hint), + FinalizationState::WaitFontList => Some(&pdu::RdpHint), FinalizationState::SendSynchronizeConfirm => None, FinalizationState::SendControlCooperateConfirm => None, FinalizationState::SendGrantedControlConfirm => None, @@ -190,10 +191,6 @@ impl FinalizationSequence { } } - pub fn into_input_events(self) -> Vec> { - self.input_events - } - pub fn is_done(&self) -> bool { self.state.is_terminal() } @@ -224,7 +221,7 @@ fn create_font_map() -> rdp::headers::ShareDataPdu { } fn decode_share_control(input: &[u8]) -> ConnectorResult { - let data_request = ironrdp_core::decode::>>(input) + let data_request = ironrdp_core::decode::>>(input) .map_err(ConnectorError::decode) .map(|p| p.0)?; let share_control = ironrdp_core::decode::(data_request.user_data.as_ref()) @@ -233,7 +230,7 @@ fn decode_share_control(input: &[u8]) -> ConnectorResult Result { - use ironrdp_pdu::rdp::headers::{ShareControlPdu, ShareDataPdu}; + use pdu::rdp::headers::{ShareControlPdu, ShareDataPdu}; let share_control = decode_share_control(input).map_err(|_| ())?; diff --git a/crates/ironrdp-acceptor/src/lib.rs b/crates/ironrdp-acceptor/src/lib.rs index 32bc2710..aea782a4 100644 --- a/crates/ironrdp-acceptor/src/lib.rs +++ b/crates/ironrdp-acceptor/src/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(doc, doc = include_str!("../README.md"))] #![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")] -use ironrdp_async::{single_sequence_step, Framed, FramedRead, FramedWrite, NetworkClient, StreamWrapper}; +use ironrdp_async::{single_sequence_step, AsyncNetworkClient, Framed, FramedRead, FramedWrite, StreamWrapper}; use ironrdp_connector::sspi::credssp::EarlyUserAuthResult; use ironrdp_connector::sspi::{AuthIdentity, KerberosServerConfig, Username}; use ironrdp_connector::{custom_err, general_err, ConnectorResult, ServerName}; @@ -51,17 +51,16 @@ where } } -pub async fn accept_credssp( +pub async fn accept_credssp( framed: &mut Framed, acceptor: &mut Acceptor, - network_client: &mut N, client_computer_name: ServerName, public_key: Vec, kerberos_config: Option, + network_client: Option<&mut dyn AsyncNetworkClient>, ) -> ConnectorResult<()> where S: FramedRead + FramedWrite, - N: NetworkClient, { let mut buf = WriteBuf::new(); @@ -69,11 +68,11 @@ where perform_credssp_step( framed, acceptor, - network_client, &mut buf, client_computer_name, public_key, kerberos_config, + network_client, ) .await } else { @@ -99,73 +98,34 @@ where } #[instrument(level = "trace", skip_all, ret)] -async fn perform_credssp_step( +async fn perform_credssp_step( framed: &mut Framed, acceptor: &mut Acceptor, - network_client: &mut N, buf: &mut WriteBuf, client_computer_name: ServerName, public_key: Vec, kerberos_config: Option, + network_client: Option<&mut dyn AsyncNetworkClient>, ) -> ConnectorResult<()> where S: FramedRead + FramedWrite, - N: NetworkClient, { assert!(acceptor.should_perform_credssp()); let AcceptorState::Credssp { protocol, .. } = acceptor.state else { unreachable!() }; - let result = credssp_loop( - framed, - acceptor, - network_client, - buf, - client_computer_name, - public_key, - kerberos_config, - ) - .await; - - if protocol.intersects(nego::SecurityProtocol::HYBRID_EX) { - trace!(?result, "HYBRID_EX"); - - let result = if result.is_ok() { - EarlyUserAuthResult::Success - } else { - EarlyUserAuthResult::AccessDenied - }; - - buf.clear(); - result - .to_buffer(&mut *buf) - .map_err(|e| ironrdp_connector::custom_err!("to_buffer", e))?; - let response = &buf[..result.buffer_len()]; - framed - .write_all(response) - .await - .map_err(|e| ironrdp_connector::custom_err!("write all", e))?; - } - - result?; - - acceptor.mark_credssp_as_done(); - - return Ok(()); - - async fn credssp_loop( + async fn credssp_loop( framed: &mut Framed, acceptor: &mut Acceptor, - network_client: &mut N, buf: &mut WriteBuf, client_computer_name: ServerName, public_key: Vec, kerberos_config: Option, + mut network_client: Option<&mut dyn AsyncNetworkClient>, ) -> ConnectorResult<()> where S: FramedRead + FramedWrite, - N: NetworkClient, { let creds = acceptor .creds @@ -204,7 +164,12 @@ where let result = { let mut generator = sequence.process_ts_request(ts_request); - resolve_generator(&mut generator, network_client).await + + if let Some(network_client_ref) = network_client.as_deref_mut() { + resolve_generator(&mut generator, network_client_ref).await + } else { + generator.resolve_to_result() + } }; // drop generator buf.clear(); @@ -219,7 +184,43 @@ where .map_err(|e| ironrdp_connector::custom_err!("write all", e))?; } } - Ok(()) } + + let result = credssp_loop( + framed, + acceptor, + buf, + client_computer_name, + public_key, + kerberos_config, + network_client, + ) + .await; + + if protocol.intersects(nego::SecurityProtocol::HYBRID_EX) { + trace!(?result, "HYBRID_EX"); + + let result = if result.is_ok() { + EarlyUserAuthResult::Success + } else { + EarlyUserAuthResult::AccessDenied + }; + + buf.clear(); + result + .to_buffer(&mut *buf) + .map_err(|e| ironrdp_connector::custom_err!("to_buffer", e))?; + let response = &buf[..result.buffer_len()]; + framed + .write_all(response) + .await + .map_err(|e| ironrdp_connector::custom_err!("write all", e))?; + } + + result?; + + acceptor.mark_credssp_as_done(); + + Ok(()) } diff --git a/crates/ironrdp-async/CHANGELOG.md b/crates/ironrdp-async/CHANGELOG.md index d98372c7..b83ee99e 100644 --- a/crates/ironrdp-async/CHANGELOG.md +++ b/crates/ironrdp-async/CHANGELOG.md @@ -6,23 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.8.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-async-v0.7.0...ironrdp-async-v0.8.0)] - 2025-12-18 - -### Bug Fixes - -- [**breaking**] Use static dispatch for NetworkClient trait ([#1043](https://github.com/Devolutions/IronRDP/issues/1043)) ([bca6d190a8](https://github.com/Devolutions/IronRDP/commit/bca6d190a870708468534d224ff225a658767a9a)) - - - Rename `AsyncNetworkClient` to `NetworkClient` - - Replace dynamic dispatch (`Option<&mut dyn ...>`) with static dispatch - using generics (`&mut N where N: NetworkClient`) - - Reorder `connect_finalize` parameters for consistency across crates - ## [[0.3.2](https://github.com/Devolutions/IronRDP/compare/ironrdp-async-v0.3.1...ironrdp-async-v0.3.2)] - 2025-03-12 ### Build - Bump ironrdp-pdu + + ## [[0.3.1](https://github.com/Devolutions/IronRDP/compare/ironrdp-async-v0.3.0...ironrdp-async-v0.3.1)] - 2025-03-12 ### Build diff --git a/crates/ironrdp-async/Cargo.toml b/crates/ironrdp-async/Cargo.toml index 1716abb4..31a81d01 100644 --- a/crates/ironrdp-async/Cargo.toml +++ b/crates/ironrdp-async/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-async" -version = "0.8.0" +version = "0.7.0" readme = "README.md" description = "Provides `Future`s wrapping the IronRDP state machines conveniently" edition.workspace = true @@ -16,7 +16,7 @@ doctest = false test = false [dependencies] -ironrdp-connector = { path = "../ironrdp-connector", version = "0.8" } # public +ironrdp-connector = { path = "../ironrdp-connector", version = "0.7" } # public ironrdp-core = { path = "../ironrdp-core", version = "0.1", features = ["alloc"] } # public ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6" } # public tracing = { version = "0.1", features = ["log"] } diff --git a/crates/ironrdp-async/src/connector.rs b/crates/ironrdp-async/src/connector.rs index 04f3d5a7..5f33c19b 100644 --- a/crates/ironrdp-async/src/connector.rs +++ b/crates/ironrdp-async/src/connector.rs @@ -2,14 +2,14 @@ use ironrdp_connector::credssp::{CredsspProcessGenerator, CredsspSequence, Kerbe use ironrdp_connector::sspi::credssp::ClientState; use ironrdp_connector::sspi::generator::GeneratorState; use ironrdp_connector::{ - general_err, ClientConnector, ClientConnectorState, ConnectionResult, ConnectorError, ConnectorResult, ServerName, - State as _, + custom_err, general_err, ClientConnector, ClientConnectorState, ConnectionResult, ConnectorError, ConnectorResult, + ServerName, State as _, }; use ironrdp_core::WriteBuf; use tracing::{debug, info, instrument, trace}; use crate::framed::{Framed, FramedRead, FramedWrite}; -use crate::{single_sequence_step, NetworkClient}; +use crate::{single_sequence_step, AsyncNetworkClient}; #[non_exhaustive] pub struct ShouldUpgrade; @@ -30,9 +30,6 @@ where Ok(ShouldUpgrade) } -/// # Panics -/// -/// Panics if connector state is not [ClientConnectorState::EnhancedSecurityUpgrade]. pub fn skip_connect_begin(connector: &mut ClientConnector) -> ShouldUpgrade { assert!(connector.should_perform_security_upgrade()); ShouldUpgrade @@ -49,29 +46,28 @@ pub fn mark_as_upgraded(_: ShouldUpgrade, connector: &mut ClientConnector) -> Up } #[instrument(skip_all)] -pub async fn connect_finalize( +pub async fn connect_finalize( _: Upgraded, - mut connector: ClientConnector, framed: &mut Framed, - network_client: &mut N, + mut connector: ClientConnector, server_name: ServerName, server_public_key: Vec, + network_client: Option<&mut dyn AsyncNetworkClient>, kerberos_config: Option, ) -> ConnectorResult where S: FramedRead + FramedWrite, - N: NetworkClient, { let mut buf = WriteBuf::new(); if connector.should_perform_credssp() { perform_credssp_step( - &mut connector, framed, - network_client, + &mut connector, &mut buf, server_name, server_public_key, + network_client, kerberos_config, ) .await?; @@ -92,7 +88,7 @@ where async fn resolve_generator( generator: &mut CredsspProcessGenerator<'_>, - network_client: &mut impl NetworkClient, + network_client: &mut dyn AsyncNetworkClient, ) -> ConnectorResult { let mut state = generator.start(); @@ -111,18 +107,17 @@ async fn resolve_generator( } #[instrument(level = "trace", skip_all)] -async fn perform_credssp_step( - connector: &mut ClientConnector, +async fn perform_credssp_step( framed: &mut Framed, - network_client: &mut N, + connector: &mut ClientConnector, buf: &mut WriteBuf, server_name: ServerName, server_public_key: Vec, + mut network_client: Option<&mut dyn AsyncNetworkClient>, kerberos_config: Option, ) -> ConnectorResult<()> where S: FramedRead + FramedWrite, - N: NetworkClient, { assert!(connector.should_perform_credssp()); @@ -143,8 +138,15 @@ where loop { let client_state = { let mut generator = sequence.process_ts_request(ts_request); - trace!("resolving network"); - resolve_generator(&mut generator, network_client).await? + + if let Some(network_client_ref) = network_client.as_deref_mut() { + trace!("resolving network"); + resolve_generator(&mut generator, network_client_ref).await? + } else { + generator + .resolve_to_result() + .map_err(|e| custom_err!("resolve without network client", e))? + } }; // drop generator buf.clear(); diff --git a/crates/ironrdp-async/src/framed.rs b/crates/ironrdp-async/src/framed.rs index 095a8328..214682e9 100644 --- a/crates/ironrdp-async/src/framed.rs +++ b/crates/ironrdp-async/src/framed.rs @@ -115,7 +115,6 @@ where if self.buf.len() >= length { return Ok(self.buf.split_to(length)); } else { - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked integer underflow)")] self.buf .reserve(length.checked_sub(self.buf.len()).expect("length > self.buf.len()")); } diff --git a/crates/ironrdp-async/src/lib.rs b/crates/ironrdp-async/src/lib.rs index 847200c0..b3677535 100644 --- a/crates/ironrdp-async/src/lib.rs +++ b/crates/ironrdp-async/src/lib.rs @@ -1,14 +1,15 @@ #![cfg_attr(doc, doc = include_str!("../README.md"))] #![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")] -use core::future::Future; - pub use bytes; mod connector; mod framed; mod session; +use core::future::Future; +use core::pin::Pin; + use ironrdp_connector::sspi::generator::NetworkRequest; use ironrdp_connector::ConnectorResult; @@ -16,6 +17,9 @@ pub use self::connector::*; pub use self::framed::*; // pub use self::session::*; -pub trait NetworkClient { - fn send(&mut self, network_request: &NetworkRequest) -> impl Future>>; +pub trait AsyncNetworkClient { + fn send<'a>( + &'a mut self, + network_request: &'a NetworkRequest, + ) -> Pin>> + 'a>>; } diff --git a/crates/ironrdp-bench/Cargo.toml b/crates/ironrdp-bench/Cargo.toml index ea35d2ce..3ab6a658 100644 --- a/crates/ironrdp-bench/Cargo.toml +++ b/crates/ironrdp-bench/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true publish = false [dev-dependencies] -criterion = "0.8" +criterion = "0.7" ironrdp-graphics.path = "../ironrdp-graphics" ironrdp-pdu.path = "../ironrdp-pdu" ironrdp-server = { path = "../ironrdp-server", features = ["__bench"] } diff --git a/crates/ironrdp-bench/benches/bench.rs b/crates/ironrdp-bench/benches/bench.rs index 4dc088ad..fed6123a 100644 --- a/crates/ironrdp-bench/benches/bench.rs +++ b/crates/ironrdp-bench/benches/bench.rs @@ -1,5 +1,3 @@ -#![expect(clippy::missing_panics_doc, reason = "panics in benches are allowed")] - use core::num::{NonZeroU16, NonZeroUsize}; use criterion::{criterion_group, criterion_main, Criterion}; diff --git a/crates/ironrdp-blocking/CHANGELOG.md b/crates/ironrdp-blocking/CHANGELOG.md index 02048123..b02d867a 100644 --- a/crates/ironrdp-blocking/CHANGELOG.md +++ b/crates/ironrdp-blocking/CHANGELOG.md @@ -6,17 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.8.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-blocking-v0.7.0...ironrdp-blocking-v0.8.0)] - 2025-12-18 - -### Bug Fixes - -- [**breaking**] Use static dispatch for NetworkClient trait ([#1043](https://github.com/Devolutions/IronRDP/issues/1043)) ([bca6d190a8](https://github.com/Devolutions/IronRDP/commit/bca6d190a870708468534d224ff225a658767a9a)) - - - Rename `AsyncNetworkClient` to `NetworkClient` - - Replace dynamic dispatch (`Option<&mut dyn ...>`) with static dispatch - using generics (`&mut N where N: NetworkClient`) - - Reorder `connect_finalize` parameters for consistency across crates - ## [[0.4.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-blocking-v0.3.1...ironrdp-blocking-v0.4.0)] - 2025-03-12 ### Build @@ -24,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bump ironrdp-pdu + ## [[0.3.1](https://github.com/Devolutions/IronRDP/compare/ironrdp-blocking-v0.3.0...ironrdp-blocking-v0.3.1)] - 2025-03-12 ### Build @@ -41,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use CDN URLs instead of the blob storage URLs for Devolutions logo (#631) ([dd249909a8](https://github.com/Devolutions/IronRDP/commit/dd249909a894004d4f728d30b3a4aa77a0f8193b)) + ## [[0.2.1](https://github.com/Devolutions/IronRDP/compare/ironrdp-blocking-v0.2.0...ironrdp-blocking-v0.2.1)] - 2024-12-14 ### Other diff --git a/crates/ironrdp-blocking/Cargo.toml b/crates/ironrdp-blocking/Cargo.toml index 557640c8..3ce5774e 100644 --- a/crates/ironrdp-blocking/Cargo.toml +++ b/crates/ironrdp-blocking/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-blocking" -version = "0.8.0" +version = "0.7.0" readme = "README.md" description = "Blocking I/O abstraction wrapping the IronRDP state machines conveniently" edition.workspace = true @@ -16,7 +16,7 @@ doctest = false test = false [dependencies] -ironrdp-connector = { path = "../ironrdp-connector", version = "0.8" } # public +ironrdp-connector = { path = "../ironrdp-connector", version = "0.7" } # public ironrdp-core = { path = "../ironrdp-core", version = "0.1", features = ["alloc"] } # public ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6" } # public tracing = { version = "0.1", features = ["log"] } diff --git a/crates/ironrdp-blocking/src/connector.rs b/crates/ironrdp-blocking/src/connector.rs index b50805ae..9375b66a 100644 --- a/crates/ironrdp-blocking/src/connector.rs +++ b/crates/ironrdp-blocking/src/connector.rs @@ -32,9 +32,6 @@ where Ok(ShouldUpgrade) } -/// # Panics -/// -/// Panics if connector state is not [ClientConnectorState::EnhancedSecurityUpgrade]. pub fn skip_connect_begin(connector: &mut ClientConnector) -> ShouldUpgrade { assert!(connector.should_perform_security_upgrade()); ShouldUpgrade @@ -53,11 +50,11 @@ pub fn mark_as_upgraded(_: ShouldUpgrade, connector: &mut ClientConnector) -> Up #[instrument(skip_all)] pub fn connect_finalize( _: Upgraded, - mut connector: ClientConnector, framed: &mut Framed, - network_client: &mut impl NetworkClient, + mut connector: ClientConnector, server_name: ServerName, server_public_key: Vec, + network_client: &mut impl NetworkClient, kerberos_config: Option, ) -> ConnectorResult where @@ -69,12 +66,12 @@ where if connector.should_perform_credssp() { perform_credssp_step( - &mut connector, framed, - network_client, + &mut connector, &mut buf, server_name, server_public_key, + network_client, kerberos_config, )?; } @@ -118,12 +115,12 @@ fn resolve_generator( #[instrument(level = "trace", skip_all)] fn perform_credssp_step( - connector: &mut ClientConnector, framed: &mut Framed, - network_client: &mut impl NetworkClient, + connector: &mut ClientConnector, buf: &mut WriteBuf, server_name: ServerName, server_public_key: Vec, + network_client: &mut impl NetworkClient, kerberos_config: Option, ) -> ConnectorResult<()> where diff --git a/crates/ironrdp-blocking/src/framed.rs b/crates/ironrdp-blocking/src/framed.rs index b08a94a4..885fe578 100644 --- a/crates/ironrdp-blocking/src/framed.rs +++ b/crates/ironrdp-blocking/src/framed.rs @@ -51,7 +51,6 @@ where if self.buf.len() >= length { return Ok(self.buf.split_to(length)); } else { - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked underflow)")] self.buf .reserve(length.checked_sub(self.buf.len()).expect("length > self.buf.len()")); } diff --git a/crates/ironrdp-client/Cargo.toml b/crates/ironrdp-client/Cargo.toml index 5a684444..fab17993 100644 --- a/crates/ironrdp-client/Cargo.toml +++ b/crates/ironrdp-client/Cargo.toml @@ -32,7 +32,7 @@ qoiz = ["ironrdp/qoiz"] [dependencies] # Protocols -ironrdp = { path = "../ironrdp", version = "0.14", features = [ +ironrdp = { path = "../ironrdp", version = "0.13", features = [ "session", "input", "graphics", @@ -45,11 +45,11 @@ ironrdp = { path = "../ironrdp", version = "0.14", features = [ "connector", ] } ironrdp-core = { path = "../ironrdp-core", version = "0.1", features = ["alloc"] } -ironrdp-cliprdr-native = { path = "../ironrdp-cliprdr-native", version = "0.5" } +ironrdp-cliprdr-native = { path = "../ironrdp-cliprdr-native", version = "0.4" } ironrdp-rdpsnd-native = { path = "../ironrdp-rdpsnd-native", version = "0.4" } -ironrdp-tls = { path = "../ironrdp-tls", version = "0.2" } +ironrdp-tls = { path = "../ironrdp-tls", version = "0.1" } ironrdp-mstsgu = { path = "../ironrdp-mstsgu" } -ironrdp-tokio = { path = "../ironrdp-tokio", version = "0.8", features = ["reqwest"] } +ironrdp-tokio = { path = "../ironrdp-tokio", version = "0.7", features = ["reqwest"] } ironrdp-rdcleanpath.path = "../ironrdp-rdcleanpath" ironrdp-dvc-pipe-proxy.path = "../ironrdp-dvc-pipe-proxy" ironrdp-propertyset.path = "../ironrdp-propertyset" @@ -72,7 +72,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] } # Async, futures tokio = { version = "1", features = ["full"] } tokio-util = { version = "0.7" } -tokio-tungstenite = "0.28" +tokio-tungstenite = "0.27" transport = { git = "https://github.com/Devolutions/devolutions-gateway", rev = "06e91dfe82751a6502eaf74b6a99663f06f0236d" } futures-util = { version = "0.3", features = ["sink"] } @@ -83,12 +83,12 @@ smallvec = "1.15" tap = "1" semver = "1" raw-window-handle = "0.6" -uuid = { version = "1.19" } +uuid = { version = "1.18" } x509-cert = { version = "0.2", default-features = false, features = ["std"] } url = "2" [target.'cfg(windows)'.dependencies] -windows = { version = "0.62", features = ["Win32_Foundation"] } +windows = { version = "0.61", features = ["Win32_Foundation"] } [lints] workspace = true diff --git a/crates/ironrdp-client/src/app.rs b/crates/ironrdp-client/src/app.rs index bcce8d4f..9f579c17 100644 --- a/crates/ironrdp-client/src/app.rs +++ b/crates/ironrdp-client/src/app.rs @@ -66,7 +66,6 @@ impl App { let Some((window, _)) = self.window.as_mut() else { return; }; - #[expect(clippy::as_conversions, reason = "casting f64 to u32")] let scale_factor = (window.scale_factor() * 100.0) as u32; let width = u16::try_from(size.width).expect("reasonable width"); @@ -223,10 +222,8 @@ impl ApplicationHandler for App { } WindowEvent::CursorMoved { position, .. } => { let win_size = window.inner_size(); - #[expect(clippy::as_conversions, reason = "casting f64 to u16")] - let x = (position.x / f64::from(win_size.width) * f64::from(self.buffer_size.0)) as u16; - #[expect(clippy::as_conversions, reason = "casting f64 to u16")] - let y = (position.y / f64::from(win_size.height) * f64::from(self.buffer_size.1)) as u16; + let x = (position.x / win_size.width as f64 * self.buffer_size.0 as f64) as u16; + let y = (position.y / win_size.height as f64 * self.buffer_size.1 as f64) as u16; let operation = ironrdp::input::Operation::MouseMove(ironrdp::input::MousePosition { x, y }); let input_events = self.input_database.apply(core::iter::once(operation)); @@ -242,7 +239,6 @@ impl ApplicationHandler for App { operations.push(ironrdp::input::Operation::WheelRotations( ironrdp::input::WheelRotations { is_vertical: false, - #[expect(clippy::as_conversions, reason = "casting f32 to i16")] rotation_units: (delta_x * 100.) as i16, }, )); @@ -252,7 +248,6 @@ impl ApplicationHandler for App { operations.push(ironrdp::input::Operation::WheelRotations( ironrdp::input::WheelRotations { is_vertical: true, - #[expect(clippy::as_conversions, reason = "casting f32 to i16")] rotation_units: (delta_y * 100.) as i16, }, )); @@ -263,7 +258,6 @@ impl ApplicationHandler for App { operations.push(ironrdp::input::Operation::WheelRotations( ironrdp::input::WheelRotations { is_vertical: false, - #[expect(clippy::as_conversions, reason = "casting f64 to i16")] rotation_units: delta.x as i16, }, )); @@ -273,7 +267,6 @@ impl ApplicationHandler for App { operations.push(ironrdp::input::Operation::WheelRotations( ironrdp::input::WheelRotations { is_vertical: true, - #[expect(clippy::as_conversions, reason = "casting f64 to i16")] rotation_units: delta.y as i16, }, )); diff --git a/crates/ironrdp-client/src/rdp.rs b/crates/ironrdp-client/src/rdp.rs index a6693fba..394050dd 100644 --- a/crates/ironrdp-client/src/rdp.rs +++ b/crates/ironrdp-client/src/rdp.rs @@ -229,24 +229,22 @@ async fn connect( // Ensure there is no leftover let (initial_stream, leftover_bytes) = framed.into_inner(); - let (upgraded_stream, tls_cert) = ironrdp_tls::upgrade(initial_stream, config.destination.name()) + let (upgraded_stream, server_public_key) = ironrdp_tls::upgrade(initial_stream, config.destination.name()) .await .map_err(|e| connector::custom_err!("TLS upgrade", e))?; let upgraded = ironrdp_tokio::mark_as_upgraded(should_upgrade, &mut connector); - let erased_stream: Box = Box::new(upgraded_stream); + let erased_stream = Box::new(upgraded_stream) as Box; let mut upgraded_framed = ironrdp_tokio::TokioFramed::new_with_leftover(erased_stream, leftover_bytes); - let server_public_key = ironrdp_tls::extract_tls_server_public_key(&tls_cert) - .ok_or_else(|| connector::general_err!("unable to extract tls server public key"))?; let connection_result = ironrdp_tokio::connect_finalize( upgraded, - connector, &mut upgraded_framed, - &mut ReqwestNetworkClient::new(), + connector, (&config.destination).into(), - server_public_key.to_owned(), + server_public_key, + Some(&mut ReqwestNetworkClient::new()), None, ) .await?; @@ -328,17 +326,17 @@ async fn connect_ws( let connection_result = ironrdp_tokio::connect_finalize( upgraded, - connector, &mut framed, - &mut ReqwestNetworkClient::new(), + connector, (&config.destination).into(), server_public_key, + Some(&mut ReqwestNetworkClient::new()), None, ) .await?; let (ws, leftover_bytes) = framed.into_inner(); - let erased_stream: Box = Box::new(ws); + let erased_stream = Box::new(ws) as Box; let upgraded_framed = ironrdp_tokio::TokioFramed::new_with_leftover(erased_stream, leftover_bytes); Ok((connection_result, upgraded_framed)) @@ -662,7 +660,7 @@ async fn active_session( desktop_size, enable_server_pointer, pointer_software_rendering, - } = connection_activation.connection_activation_state() + } = connection_activation.state { debug!(?desktop_size, "Deactivation-Reactivation Sequence completed"); // Update image size with the new desktop size. diff --git a/crates/ironrdp-cliprdr-native/CHANGELOG.md b/crates/ironrdp-cliprdr-native/CHANGELOG.md index 20bbaa96..27b65067 100644 --- a/crates/ironrdp-cliprdr-native/CHANGELOG.md +++ b/crates/ironrdp-cliprdr-native/CHANGELOG.md @@ -6,22 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.5.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-cliprdr-native-v0.4.0...ironrdp-cliprdr-native-v0.5.0)] - 2025-12-18 - -### Bug Fixes - -- Prevent window class registration error on multiple sessions ([#1047](https://github.com/Devolutions/IronRDP/issues/1047)) ([a2af587e60](https://github.com/Devolutions/IronRDP/commit/a2af587e60e869f0235703e21772d1fc6a7dadcd)) - - When starting a second clipboard session, `RegisterClassA` would fail - with `ERROR_CLASS_ALREADY_EXISTS` because window classes are global to - the process. Now checks if the class is already registered before - attempting registration, allowing multiple WinClipboard instances to - coexist. - -### Build - -- Bump windows from 0.61.3 to 0.62.1 ([#1010](https://github.com/Devolutions/IronRDP/issues/1010)) ([79e71c4f90](https://github.com/Devolutions/IronRDP/commit/79e71c4f90ea68b14fe45241c1cf3953027b22a2)) - ## [[0.4.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-cliprdr-native-v0.3.0...ironrdp-cliprdr-native-v0.4.0)] - 2025-08-29 ### Bug Fixes diff --git a/crates/ironrdp-cliprdr-native/Cargo.toml b/crates/ironrdp-cliprdr-native/Cargo.toml index be193e66..9e338410 100644 --- a/crates/ironrdp-cliprdr-native/Cargo.toml +++ b/crates/ironrdp-cliprdr-native/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-cliprdr-native" -version = "0.5.0" +version = "0.4.0" readme = "README.md" description = "Native CLIPRDR static channel backend implementations for IronRDP" edition.workspace = true @@ -16,12 +16,12 @@ doctest = false test = false [dependencies] -ironrdp-cliprdr = { path = "../ironrdp-cliprdr", version = "0.5" } # public +ironrdp-cliprdr = { path = "../ironrdp-cliprdr", version = "0.4" } # public ironrdp-core = { path = "../ironrdp-core", version = "0.1" } tracing = { version = "0.1", features = ["log"] } [target.'cfg(windows)'.dependencies] -windows = { version = "0.62", features = [ +windows = { version = "0.61", features = [ "Win32_Foundation", "Win32_Graphics_Gdi", "Win32_System_DataExchange", diff --git a/crates/ironrdp-cliprdr-native/src/windows/mod.rs b/crates/ironrdp-cliprdr-native/src/windows.rs similarity index 87% rename from crates/ironrdp-cliprdr-native/src/windows/mod.rs rename to crates/ironrdp-cliprdr-native/src/windows.rs index 87574ca5..b91241c5 100644 --- a/crates/ironrdp-cliprdr-native/src/windows/mod.rs +++ b/crates/ironrdp-cliprdr-native/src/windows.rs @@ -19,8 +19,7 @@ use windows::Win32::System::DataExchange::{AddClipboardFormatListener, RemoveCli use windows::Win32::System::LibraryLoader::GetModuleHandleA; use windows::Win32::UI::Shell::{RemoveWindowSubclass, SetWindowSubclass}; use windows::Win32::UI::WindowsAndMessaging::{ - CreateWindowExA, DefWindowProcA, GetClassInfoA, RegisterClassA, CW_USEDEFAULT, WINDOW_EX_STYLE, WM_USER, WNDCLASSA, - WS_POPUP, + CreateWindowExA, DefWindowProcA, RegisterClassA, CW_USEDEFAULT, WINDOW_EX_STYLE, WM_USER, WNDCLASSA, WS_POPUP, }; use self::clipboard_impl::{clipboard_subproc, WinClipboardImpl}; @@ -153,25 +152,17 @@ impl WinClipboard { // SAFETY: low-level WinAPI call let instance = unsafe { GetModuleHandleA(None)? }; let window_class = s!("IronRDPClipboardMonitor"); + let wc = WNDCLASSA { + hInstance: instance.into(), + lpszClassName: window_class, + lpfnWndProc: Some(wndproc), + ..Default::default() + }; - let mut existing_wc = WNDCLASSA::default(); - // SAFETY: `instance` is a valid module handle, `window_class` is a valid null-terminated string, - // and `existing_wc` is a valid mutable reference to a WNDCLASSA structure. - let class_exists = unsafe { GetClassInfoA(Some(instance.into()), window_class, &mut existing_wc).is_ok() }; - - if !class_exists { - let wc = WNDCLASSA { - hInstance: instance.into(), - lpszClassName: window_class, - lpfnWndProc: Some(wndproc), - ..Default::default() - }; - - // SAFETY: low-level WinAPI call - let atom = unsafe { RegisterClassA(&wc) }; - if atom == 0 { - return Err(WinCliprdrError::from(Error::from_thread())); - } + // SAFETY: low-level WinAPI call + let atom = unsafe { RegisterClassA(&wc) }; + if atom == 0 { + return Err(Error::from_win32())?; } // SAFETY: low-level WinAPI call @@ -193,7 +184,7 @@ impl WinClipboard { }; if window.is_invalid() { - return Err(WinCliprdrError::from(Error::from_thread())); + return Err(Error::from_win32())?; } // Init clipboard processing for WinAPI event loop // @@ -209,14 +200,8 @@ impl WinClipboard { // // SAFETY: `window` is a valid window handle, `clipboard_subproc` is in the static memory, // `ctx` is valid and its ownership is transferred to the subclass via `into_raw`. - let winapi_result = unsafe { - SetWindowSubclass( - window, - Some(clipboard_subproc), - 0, - Box::into_raw(ctx).expose_provenance(), - ) - }; + let winapi_result = + unsafe { SetWindowSubclass(window, Some(clipboard_subproc), 0, Box::into_raw(ctx) as usize) }; if winapi_result == FALSE { return Err(WinCliprdrError::WindowSubclass); diff --git a/crates/ironrdp-cliprdr-native/src/windows/clipboard_data_ref.rs b/crates/ironrdp-cliprdr-native/src/windows/clipboard_data_ref.rs index 06672142..b95d7b3c 100644 --- a/crates/ironrdp-cliprdr-native/src/windows/clipboard_data_ref.rs +++ b/crates/ironrdp-cliprdr-native/src/windows/clipboard_data_ref.rs @@ -27,7 +27,7 @@ impl<'a> ClipboardDataRef<'a> { }; // SAFETY: It is safe to call `GlobalLock` on the valid handle. - let data = unsafe { GlobalLock(handle) }.cast::().cast_const(); + let data = unsafe { GlobalLock(handle) } as *const u8; if data.is_null() { // Can't lock data handle, handle is not valid anymore (e.g. clipboard has changed) diff --git a/crates/ironrdp-cliprdr-native/src/windows/clipboard_impl.rs b/crates/ironrdp-cliprdr-native/src/windows/clipboard_impl.rs index 66632846..ba1dba7e 100644 --- a/crates/ironrdp-cliprdr-native/src/windows/clipboard_impl.rs +++ b/crates/ironrdp-cliprdr-native/src/windows/clipboard_impl.rs @@ -1,4 +1,3 @@ -use core::ptr::with_exposed_provenance_mut; use core::time::Duration; use std::collections::HashSet; use std::sync::mpsc; @@ -321,19 +320,17 @@ pub(crate) unsafe extern "system" fn clipboard_subproc( // SAFETY: `data` is a valid pointer, returned by `Box::into_raw`, transferred to OS earlier // via `SetWindowSubclass` call. - let _ = unsafe { Box::from_raw(with_exposed_provenance_mut::(data)) }; + let _ = unsafe { Box::from_raw(data as *mut WinClipboardImpl) }; return LRESULT(0); } // SAFETY: `data` is a valid pointer, returned by `Box::into_raw`, transferred to OS earlier // via `SetWindowSubclass` call. - let ctx = unsafe { &mut *(with_exposed_provenance_mut::(data)) }; + let ctx = unsafe { &mut *(data as *mut WinClipboardImpl) }; match msg { // We need to keep track of window state to distinguish between local and remote copy - WM_ACTIVATE | WM_ACTIVATEAPP => { - ctx.window_is_active = wparam.0 != usize::try_from(WA_INACTIVE).expect("WA_INACTIVE fits into usize") - } + WM_ACTIVATE | WM_ACTIVATEAPP => ctx.window_is_active = wparam.0 != WA_INACTIVE as usize, // `as` conversion is fine for constants // Sent by the OS when OS clipboard content is changed WM_CLIPBOARDUPDATE => { // SAFETY: `GetClipboardOwner` is always safe to call. @@ -350,9 +347,8 @@ pub(crate) unsafe extern "system" fn clipboard_subproc( } // Sent by the OS when delay-rendered data is requested for rendering. WM_RENDERFORMAT => { - ctx.handle_event(BackendEvent::RenderFormat(ClipboardFormatId::new( - u32::try_from(wparam.0).expect("should never truncate in practice"), - ))); + #[expect(clippy::cast_possible_truncation)] // should never truncate in practice + ctx.handle_event(BackendEvent::RenderFormat(ClipboardFormatId::new(wparam.0 as u32))); } // Sent by the OS when all delay-rendered data is requested for rendering. WM_RENDERALLFORMATS => { diff --git a/crates/ironrdp-cliprdr-native/src/windows/utils.rs b/crates/ironrdp-cliprdr-native/src/windows/utils.rs index 198ca81d..bd1120c8 100644 --- a/crates/ironrdp-cliprdr-native/src/windows/utils.rs +++ b/crates/ironrdp-cliprdr-native/src/windows/utils.rs @@ -26,7 +26,7 @@ impl GlobalMemoryBuffer { // - `dst` is valid for writes of `data.len()` bytes, we allocated enough above. // - Both `data` and `dst` are properly aligned: u8 alignment is 1 // - Memory regions are not overlapping, `dst` was allocated by us just above. - unsafe { core::ptr::copy_nonoverlapping(data.as_ptr(), dst.cast::(), data.len()) }; + unsafe { core::ptr::copy_nonoverlapping(data.as_ptr(), dst as *mut u8, data.len()) }; // SAFETY: We called `GlobalLock` on this handle just above. if let Err(error) = unsafe { GlobalUnlock(handle) } { diff --git a/crates/ironrdp-cliprdr/CHANGELOG.md b/crates/ironrdp-cliprdr/CHANGELOG.md index c9653f15..d96b4760 100644 --- a/crates/ironrdp-cliprdr/CHANGELOG.md +++ b/crates/ironrdp-cliprdr/CHANGELOG.md @@ -6,30 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.5.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-cliprdr-v0.4.0...ironrdp-cliprdr-v0.5.0)] - 2025-12-18 - -### Bug Fixes - -- Fixes the Cliprdr `SvcProcessor` impl to support handling a `TemporaryDirectory` Clipboard PDU ([#1031](https://github.com/Devolutions/IronRDP/issues/1031)) ([f2326ef046](https://github.com/Devolutions/IronRDP/commit/f2326ef046cc81fb0e8985f03382859085882e86)) - -- Allow servers to announce clipboard ownership ([#1053](https://github.com/Devolutions/IronRDP/issues/1053)) ([d587b0c4c1](https://github.com/Devolutions/IronRDP/commit/d587b0c4c114c49d30f52859f43b22f829456a01)) - - Servers can now send Format List PDU via initiate_copy() regardless of - internal state. The existing state machine was designed for clients - where clipboard initialization must complete before announcing - ownership. - - MS-RDPECLIP Section 2.2.3.1 specifies that Format List PDU is sent by - either client or server when the local clipboard is updated. Servers - should be able to announce clipboard changes immediately after channel - negotiation. - - This change enables RDP servers to properly announce clipboard ownership - by bypassing the Initialization/Ready state check when R::is_server() is - true. Client behavior remains unchanged. - -- [**breaking**] Removed the `PackedMetafile::data()` method in favor of making the `PackedMetafile::data` field public. - ## [[0.4.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-cliprdr-v0.3.0...ironrdp-cliprdr-v0.4.0)] - 2025-08-29 ### Bug Fixes diff --git a/crates/ironrdp-cliprdr/Cargo.toml b/crates/ironrdp-cliprdr/Cargo.toml index 3dd216da..e02cfefd 100644 --- a/crates/ironrdp-cliprdr/Cargo.toml +++ b/crates/ironrdp-cliprdr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-cliprdr" -version = "0.5.0" +version = "0.4.0" readme = "README.md" description = "CLIPRDR static channel for clipboard implemented as described in MS-RDPECLIP" edition.workspace = true diff --git a/crates/ironrdp-cliprdr/src/lib.rs b/crates/ironrdp-cliprdr/src/lib.rs index 41f5d62c..fa83f1ab 100644 --- a/crates/ironrdp-cliprdr/src/lib.rs +++ b/crates/ironrdp-cliprdr/src/lib.rs @@ -1,6 +1,10 @@ #![cfg_attr(doc, doc = include_str!("../README.md"))] #![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")] #![allow(clippy::arithmetic_side_effects)] // FIXME: remove +#![allow(clippy::cast_lossless)] // FIXME: remove +#![allow(clippy::cast_possible_truncation)] // FIXME: remove +#![allow(clippy::cast_possible_wrap)] // FIXME: remove +#![allow(clippy::cast_sign_loss)] // FIXME: remove pub mod backend; pub mod pdu; @@ -28,12 +32,16 @@ pub type CliprdrSvcMessages = SvcProcessorMessages>; #[derive(Debug)] enum ClipboardError { + UnimplementedPdu { pdu: &'static str }, FormatListRejected, } impl core::fmt::Display for ClipboardError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { + ClipboardError::UnimplementedPdu { pdu } => { + write!(f, "received clipboard PDU `{pdu}` is not implemented") + } ClipboardError::FormatListRejected => write!(f, "sent format list was rejected"), } } @@ -230,32 +238,26 @@ impl Cliprdr { pub fn initiate_copy(&self, available_formats: &[ClipboardFormat]) -> PduResult> { let mut pdus = Vec::new(); - if R::is_server() { - pdus.push(ClipboardPdu::FormatList( - self.build_format_list(available_formats).map_err(|e| encode_err!(e))?, - )); - } else { - match self.state { - CliprdrState::Ready => { - pdus.push(ClipboardPdu::FormatList( - self.build_format_list(available_formats).map_err(|e| encode_err!(e))?, - )); - } - CliprdrState::Initialization => { - // During initialization state, first copy action is synthetic and should be sent along with - // capabilities and temporary directory PDUs. - pdus.push(ClipboardPdu::Capabilities(self.capabilities.clone())); - pdus.push(ClipboardPdu::TemporaryDirectory( - ClientTemporaryDirectory::new(self.backend.temporary_directory()) - .map_err(|e| encode_err!(e))?, - )); - pdus.push(ClipboardPdu::FormatList( - self.build_format_list(available_formats).map_err(|e| encode_err!(e))?, - )); - } - _ => { - error!(?self.state, "Attempted to initiate copy in incorrect state"); - } + match (self.state, R::is_server()) { + // When user initiates copy, we should send format list to server. + (CliprdrState::Ready, _) => { + pdus.push(ClipboardPdu::FormatList( + self.build_format_list(available_formats).map_err(|e| encode_err!(e))?, + )); + } + (CliprdrState::Initialization, false) => { + // During initialization state, first copy action is synthetic and should be sent along with + // capabilities and temporary directory PDUs. + pdus.push(ClipboardPdu::Capabilities(self.capabilities.clone())); + pdus.push(ClipboardPdu::TemporaryDirectory( + ClientTemporaryDirectory::new(self.backend.temporary_directory()).map_err(|e| encode_err!(e))?, + )); + pdus.push(ClipboardPdu::FormatList( + self.build_format_list(available_formats).map_err(|e| encode_err!(e))?, + )); + } + _ => { + error!(?self.state, "Attempted to initiate copy in incorrect state"); } } @@ -335,10 +337,9 @@ impl SvcProcessor for Cliprdr { self.backend.on_file_contents_response(response); Ok(Vec::new()) } - ClipboardPdu::TemporaryDirectory(_) => { - // do nothing - Ok(Vec::new()) - } + _ => self.handle_error_transition(ClipboardError::UnimplementedPdu { + pdu: pdu.message_name(), + }), } } diff --git a/crates/ironrdp-cliprdr/src/pdu/file_contents.rs b/crates/ironrdp-cliprdr/src/pdu/file_contents.rs index 1651b1e1..0b329af9 100644 --- a/crates/ironrdp-cliprdr/src/pdu/file_contents.rs +++ b/crates/ironrdp-cliprdr/src/pdu/file_contents.rs @@ -94,13 +94,19 @@ impl<'a> FileContentsResponse<'a> { /// Read data as u64 size value pub fn data_as_size(&self) -> DecodeResult { - let chunk = self - .data - .as_ref() - .try_into() - .map_err(|_| invalid_field_err!("requestedFileContentsData", "not enough bytes for u64 size"))?; + if self.data.len() != 8 { + return Err(invalid_field_err!( + "requestedFileContentsData", + "Invalid data size for u64 size" + )); + } - Ok(u64::from_le_bytes(chunk)) + Ok(u64::from_le_bytes( + self.data + .as_ref() + .try_into() + .expect("data contains exactly eight u8 elements"), + )) } } diff --git a/crates/ironrdp-cliprdr/src/pdu/format_data/metafile.rs b/crates/ironrdp-cliprdr/src/pdu/format_data/metafile.rs index 433f2e81..4569687b 100644 --- a/crates/ironrdp-cliprdr/src/pdu/format_data/metafile.rs +++ b/crates/ironrdp-cliprdr/src/pdu/format_data/metafile.rs @@ -42,7 +42,7 @@ pub struct PackedMetafile<'a> { pub x_ext: u32, pub y_ext: u32, /// The variable sized contents of the metafile as specified in [MS-WMF] section 2 - pub data: Cow<'a, [u8]>, + data: Cow<'a, [u8]>, } impl PackedMetafile<'_> { @@ -62,6 +62,10 @@ impl PackedMetafile<'_> { data: data.into(), } } + + pub fn data(&self) -> &[u8] { + &self.data + } } impl Encode for PackedMetafile<'_> { diff --git a/crates/ironrdp-connector/CHANGELOG.md b/crates/ironrdp-connector/CHANGELOG.md index 888acabe..6fe86b40 100644 --- a/crates/ironrdp-connector/CHANGELOG.md +++ b/crates/ironrdp-connector/CHANGELOG.md @@ -6,14 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.8.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-connector-v0.7.1...ironrdp-connector-v0.8.0)] - 2025-12-18 - -### Build - -- Bump picky and sspi ([#1028](https://github.com/Devolutions/IronRDP/issues/1028)) ([5bd319126d](https://github.com/Devolutions/IronRDP/commit/5bd319126d32fbd8e505508e27ab2b1a18a83d04)) - - This fixes build issues with some dependencies. - ## [[0.7.1](https://github.com/Devolutions/IronRDP/compare/ironrdp-connector-v0.7.0...ironrdp-connector-v0.7.1)] - 2025-09-04 ### Features diff --git a/crates/ironrdp-connector/Cargo.toml b/crates/ironrdp-connector/Cargo.toml index 8119bab4..2ff693fb 100644 --- a/crates/ironrdp-connector/Cargo.toml +++ b/crates/ironrdp-connector/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-connector" -version = "0.8.0" +version = "0.7.1" readme = "README.md" description = "State machines to drive an RDP connection sequence" edition.workspace = true @@ -27,13 +27,13 @@ ironrdp-core = { path = "../ironrdp-core", version = "0.1" } # public ironrdp-error = { path = "../ironrdp-error", version = "0.1" } # public ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6", features = ["std"] } # public arbitrary = { version = "1", features = ["derive"], optional = true } # public -sspi = { version = "0.18", features = ["scard"] } +sspi = "0.16" # public url = "2.5" # public rand = { version = "0.9", features = ["std"] } # TODO: dependency injection? tracing = { version = "0.1", features = ["log"] } picky-asn1-der = "0.5" -picky-asn1-x509 = "0.15" -picky = "=7.0.0-rc.20" # FIXME: We are pinning with = because the candidate version number counts as the minor number by Cargo, and will be automatically bumped in the Cargo.lock. +picky-asn1-x509 = "0.14" +picky = "7.0.0-rc.17" [lints] workspace = true diff --git a/crates/ironrdp-connector/src/connection.rs b/crates/ironrdp-connector/src/connection.rs index 3018b1f7..231adb1a 100644 --- a/crates/ironrdp-connector/src/connection.rs +++ b/crates/ironrdp-connector/src/connection.rs @@ -176,9 +176,6 @@ impl ClientConnector { matches!(self.state, ClientConnectorState::EnhancedSecurityUpgrade { .. }) } - /// # Panics - /// - /// Panics if state is not [ClientConnectorState::EnhancedSecurityUpgrade]. pub fn mark_security_upgrade_as_done(&mut self) { assert!(self.should_perform_security_upgrade()); self.step(&[], &mut WriteBuf::new()).expect("transition to next state"); @@ -189,9 +186,6 @@ impl ClientConnector { matches!(self.state, ClientConnectorState::Credssp { .. }) } - /// # Panics - /// - /// Panics if state is not [ClientConnectorState::Credssp]. pub fn mark_credssp_as_done(&mut self) { assert!(self.should_perform_credssp()); let res = self.step(&[], &mut WriteBuf::new()).expect("transition to next state"); @@ -553,7 +547,7 @@ impl Sequence for ClientConnector { mut connection_activation, } => { let written = connection_activation.step(input, output)?; - match connection_activation.connection_activation_state() { + match connection_activation.state { ConnectionActivationState::ConnectionFinalization { .. } => ( written, ClientConnectorState::ConnectionFinalization { connection_activation }, @@ -570,10 +564,10 @@ impl Sequence for ClientConnector { } => { let written = connection_activation.step(input, output)?; - let next_state = if !connection_activation.connection_activation_state().is_terminal() { + let next_state = if !connection_activation.state.is_terminal() { ClientConnectorState::ConnectionFinalization { connection_activation } } else { - match connection_activation.connection_activation_state() { + match connection_activation.state { ConnectionActivationState::Finalized { io_channel_id, user_channel_id, @@ -699,9 +693,9 @@ fn create_gcc_blocks<'a>( desktop_physical_width: Some(0), // 0 per FreeRDP desktop_physical_height: Some(0), // 0 per FreeRDP desktop_orientation: if config.desktop_size.width > config.desktop_size.height { - Some(MonitorOrientation::Landscape.as_u16()) + Some(MonitorOrientation::Landscape as u16) } else { - Some(MonitorOrientation::Portrait.as_u16()) + Some(MonitorOrientation::Portrait as u16) }, desktop_scale_factor: Some(config.desktop_scale_factor), device_scale_factor: if config.desktop_scale_factor >= 100 && config.desktop_scale_factor <= 500 { diff --git a/crates/ironrdp-connector/src/connection_activation.rs b/crates/ironrdp-connector/src/connection_activation.rs index 110ba29d..9f0f1ed6 100644 --- a/crates/ironrdp-connector/src/connection_activation.rs +++ b/crates/ironrdp-connector/src/connection_activation.rs @@ -1,7 +1,7 @@ use core::mem; -use ironrdp_pdu::rdp; use ironrdp_pdu::rdp::capability_sets::CapabilitySet; +use ironrdp_pdu::rdp::{self}; use tracing::{debug, warn}; use crate::{ @@ -22,7 +22,7 @@ use crate::{ /// [Server Deactivate All PDU]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/8a29971a-df3c-48da-add2-8ed9a05edc89 #[derive(Debug, Clone)] pub struct ConnectionActivationSequence { - state: ConnectionActivationState, + pub state: ConnectionActivationState, config: Config, } @@ -37,11 +37,6 @@ impl ConnectionActivationSequence { } } - /// Returns the current state as a district type, rather than `&dyn State` provided by [`Self::state`]. - pub fn connection_activation_state(&self) -> ConnectionActivationState { - self.state - } - #[must_use] pub fn reset_clone(&self) -> Self { self.clone().reset() @@ -220,7 +215,7 @@ impl Sequence for ConnectionActivationSequence { } } -#[derive(Default, Debug, Copy, Clone)] +#[derive(Default, Debug, Clone)] pub enum ConnectionActivationState { #[default] Consumed, diff --git a/crates/ironrdp-connector/src/connection_finalization.rs b/crates/ironrdp-connector/src/connection_finalization.rs index cb626d99..6267822c 100644 --- a/crates/ironrdp-connector/src/connection_finalization.rs +++ b/crates/ironrdp-connector/src/connection_finalization.rs @@ -9,7 +9,7 @@ use tracing::{debug, warn}; use crate::{general_err, legacy, reason_err, ConnectorResult, Sequence, State, Written}; -#[derive(Default, Debug, Copy, Clone)] +#[derive(Default, Debug, Clone)] #[non_exhaustive] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub enum ConnectionFinalizationState { @@ -48,7 +48,7 @@ impl State for ConnectionFinalizationState { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub struct ConnectionFinalizationSequence { pub state: ConnectionFinalizationState, diff --git a/crates/ironrdp-connector/src/credssp.rs b/crates/ironrdp-connector/src/credssp.rs index 866ac508..9750b608 100644 --- a/crates/ironrdp-connector/src/credssp.rs +++ b/crates/ironrdp-connector/src/credssp.rs @@ -5,7 +5,6 @@ use picky_asn1_x509::{oids, Certificate, ExtensionView, GeneralName}; use sspi::credssp::{self, ClientState, CredSspClient}; use sspi::generator::{Generator, NetworkRequest}; use sspi::negotiate::ProtocolConfig; -use sspi::Secret; use sspi::Username; use tracing::debug; @@ -124,13 +123,11 @@ impl CredsspSequence { certificate: cert, reader_name: config.reader_name.clone(), card_name: None, - container_name: Some(config.container_name.clone()), + container_name: config.container_name.clone(), csp_name: config.csp_name.clone(), pin: pin.as_bytes().to_vec().into(), + private_key_file_index: None, private_key: Some(key.into()), - scard_type: sspi::SmartCardType::Emulated { - scard_pin: Secret::new(pin.as_bytes().to_vec()), - }, }; sspi::Credentials::SmartCard(Box::new(identity)) } diff --git a/crates/ironrdp-connector/src/lib.rs b/crates/ironrdp-connector/src/lib.rs index 1e1a7402..971e149a 100644 --- a/crates/ironrdp-connector/src/lib.rs +++ b/crates/ironrdp-connector/src/lib.rs @@ -406,7 +406,7 @@ pub trait ConnectorResultExt { impl ConnectorResultExt for ConnectorResult { fn with_context(self, context: &'static str) -> Self { self.map_err(|mut e| { - e.set_context(context); + e.context = context; e }) } diff --git a/crates/ironrdp-dvc/src/client.rs b/crates/ironrdp-dvc/src/client.rs index ed383d53..532b1000 100644 --- a/crates/ironrdp-dvc/src/client.rs +++ b/crates/ironrdp-dvc/src/client.rs @@ -116,8 +116,8 @@ impl SvcProcessor for DrdynvcClient { } DrdynvcServerPdu::Create(create_request) => { debug!("Got DVC Create Request PDU: {create_request:?}"); - let channel_id = create_request.channel_id(); - let channel_name = create_request.into_channel_name(); + let channel_name = create_request.channel_name; + let channel_id = create_request.channel_id; if !self.cap_handshake_done { debug!( @@ -156,9 +156,9 @@ impl SvcProcessor for DrdynvcClient { } DrdynvcServerPdu::Close(close_request) => { debug!("Got DVC Close Request PDU: {close_request:?}"); - self.dynamic_channels.remove_by_channel_id(close_request.channel_id()); + self.dynamic_channels.remove_by_channel_id(close_request.channel_id); - let close_response = DrdynvcClientPdu::Close(ClosePdu::new(close_request.channel_id())); + let close_response = DrdynvcClientPdu::Close(ClosePdu::new(close_request.channel_id)); debug!("Send DVC Close Response PDU: {close_response:?}"); responses.push(SvcMessage::from(close_response)); diff --git a/crates/ironrdp-dvc/src/complete_data.rs b/crates/ironrdp-dvc/src/complete_data.rs index d910aa4d..acb6d919 100644 --- a/crates/ironrdp-dvc/src/complete_data.rs +++ b/crates/ironrdp-dvc/src/complete_data.rs @@ -28,7 +28,7 @@ impl CompleteData { } fn process_data_first_pdu(&mut self, data_first: DataFirstPdu) -> DecodeResult>> { - let total_data_size: DecodeResult<_> = cast_length!("DataFirstPdu::length", data_first.length()); + let total_data_size: DecodeResult<_> = cast_length!("DataFirstPdu::length", data_first.length); let total_data_size = total_data_size?; if self.total_size != 0 || !self.data.is_empty() { error!("Incomplete DVC message, it will be skipped"); @@ -36,11 +36,11 @@ impl CompleteData { self.data.clear(); } - if total_data_size == data_first.data().len() { - Ok(Some(data_first.into_data())) + if total_data_size == data_first.data.len() { + Ok(Some(data_first.data)) } else { self.total_size = total_data_size; - self.data = data_first.into_data(); + self.data = data_first.data; Ok(None) } @@ -49,22 +49,22 @@ impl CompleteData { fn process_data_pdu(&mut self, mut data: DataPdu) -> DecodeResult>> { if self.total_size == 0 && self.data.is_empty() { // message is not fragmented - return Ok(Some(data.into_data())); + return Ok(Some(data.data)); } // The message is fragmented and needs to be reassembled. - match self.data.len().checked_add(data.data().len()) { + match self.data.len().checked_add(data.data.len()) { Some(actual_data_length) => { match actual_data_length.cmp(&(self.total_size)) { cmp::Ordering::Less => { // this is one of the fragmented messages, just append it - self.data.append(data.data_mut()); + self.data.append(&mut data.data); Ok(None) } cmp::Ordering::Equal => { // this is the last fragmented message, need to return the whole reassembled message self.total_size = 0; - self.data.append(data.data_mut()); + self.data.append(&mut data.data); Ok(Some(self.data.drain(..).collect())) } cmp::Ordering::Greater => { diff --git a/crates/ironrdp-dvc/src/lib.rs b/crates/ironrdp-dvc/src/lib.rs index 7baa918a..48294324 100644 --- a/crates/ironrdp-dvc/src/lib.rs +++ b/crates/ironrdp-dvc/src/lib.rs @@ -73,8 +73,6 @@ pub fn encode_dvc_messages( while off < total_length { let first = off == 0; - - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked underflow)")] let remaining_length = total_length.checked_sub(off).expect("never overflow"); let size = core::cmp::min(remaining_length, DrdynvcDataPdu::MAX_DATA_SIZE); let end = off diff --git a/crates/ironrdp-dvc/src/pdu.rs b/crates/ironrdp-dvc/src/pdu.rs index 3f0c461e..0b081b6d 100644 --- a/crates/ironrdp-dvc/src/pdu.rs +++ b/crates/ironrdp-dvc/src/pdu.rs @@ -200,7 +200,7 @@ impl Header { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_fixed_part_size!(in: dst); - dst.write_u8(((self.cmd.as_u8()) << 4) | (Into::::into(self.sp) << 2) | Into::::into(self.cb_id)); + dst.write_u8(((self.cmd as u8) << 4) | (Into::::into(self.sp) << 2) | Into::::into(self.cb_id)); Ok(()) } @@ -235,16 +235,6 @@ enum Cmd { SoftSyncResponse = 0x09, } -impl Cmd { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] - fn as_u8(self) -> u8 { - self as u8 - } -} - impl TryFrom for Cmd { type Error = DecodeError; @@ -292,12 +282,12 @@ impl From for String { #[derive(Debug, PartialEq)] pub struct DataFirstPdu { header: Header, - channel_id: DynamicChannelId, + pub channel_id: DynamicChannelId, /// Length is the *total* length of the data to be sent, including the length /// of the data that will be sent by subsequent DVC_DATA PDUs. - length: u32, + pub length: u32, /// Data is just the data to be sent in this PDU. - data: Vec, + pub data: Vec, } impl DataFirstPdu { @@ -332,18 +322,6 @@ impl DataFirstPdu { } } - pub fn length(&self) -> u32 { - self.length - } - - pub fn data(&self) -> &[u8] { - &self.data - } - - pub fn into_data(self) -> Vec { - self.data - } - fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult { let fixed_part_size = checked_sum(&[header.cb_id.size_of_val(), header.sp.size_of_val()])?; ensure_size!(in: src, size: fixed_part_size); @@ -456,8 +434,8 @@ impl From for u8 { #[derive(Debug, PartialEq)] pub struct DataPdu { header: Header, - channel_id: DynamicChannelId, - data: Vec, + pub channel_id: DynamicChannelId, + pub data: Vec, } impl DataPdu { @@ -469,18 +447,6 @@ impl DataPdu { } } - pub fn data(&self) -> &[u8] { - &self.data - } - - pub fn into_data(self) -> Vec { - self.data - } - - pub fn data_mut(&mut self) -> &mut Vec { - &mut self.data - } - fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult { ensure_size!(in: src, size: header.cb_id.size_of_val()); let channel_id = header.cb_id.decode_val(src)?; @@ -519,8 +485,8 @@ impl DataPdu { #[derive(Debug, PartialEq)] pub struct CreateResponsePdu { header: Header, - channel_id: DynamicChannelId, - creation_status: CreationStatus, + pub channel_id: DynamicChannelId, + pub creation_status: CreationStatus, } impl CreateResponsePdu { @@ -532,14 +498,6 @@ impl CreateResponsePdu { } } - pub fn channel_id(&self) -> DynamicChannelId { - self.channel_id - } - - pub fn creation_status(&self) -> CreationStatus { - self.creation_status - } - fn name() -> &'static str { "DYNVC_CREATE_RSP" } @@ -606,7 +564,7 @@ impl From for u32 { #[derive(Debug, PartialEq)] pub struct ClosePdu { header: Header, - channel_id: DynamicChannelId, + pub channel_id: DynamicChannelId, } impl ClosePdu { @@ -625,10 +583,6 @@ impl ClosePdu { } } - pub fn channel_id(&self) -> DynamicChannelId { - self.channel_id - } - fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult { ensure_size!(in: src, size: Self::headerless_size(&header)); let channel_id = header.cb_id.decode_val(src)?; @@ -712,7 +666,7 @@ impl CapsVersion { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_size!(in: dst, size: Self::size()); - dst.write_u16(u16::from(*self)); + dst.write_u16(*self as u16); Ok(()) } @@ -735,10 +689,6 @@ impl TryFrom for CapsVersion { } impl From for u16 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(version: CapsVersion) -> Self { version as u16 } @@ -848,8 +798,8 @@ impl CapabilitiesRequestPdu { #[derive(Debug, PartialEq)] pub struct CreateRequestPdu { header: Header, - channel_id: DynamicChannelId, - channel_name: String, + pub channel_id: DynamicChannelId, + pub channel_name: String, } impl CreateRequestPdu { @@ -861,18 +811,6 @@ impl CreateRequestPdu { } } - pub fn channel_id(&self) -> DynamicChannelId { - self.channel_id - } - - pub fn channel_name(&self) -> &str { - &self.channel_name - } - - pub fn into_channel_name(self) -> String { - self.channel_name - } - fn decode(header: Header, src: &mut ReadCursor<'_>) -> DecodeResult { ensure_size!(in: src, size: Self::headerless_fixed_part_size(&header)); let channel_id = header.cb_id.decode_val(src)?; diff --git a/crates/ironrdp-dvc/src/server.rs b/crates/ironrdp-dvc/src/server.rs index 1811f240..09c1700d 100644 --- a/crates/ironrdp-dvc/src/server.rs +++ b/crates/ironrdp-dvc/src/server.rs @@ -139,24 +139,22 @@ impl SvcProcessor for DrdynvcServer { } DrdynvcClientPdu::Create(create_resp) => { debug!("Got DVC Create Response PDU: {create_resp:?}"); - let id = create_resp.channel_id(); + let id = create_resp.channel_id; let c = self.channel_by_id(id).map_err(|e| decode_err!(e))?; if c.state != ChannelState::Creation { return Err(pdu_other_err!("invalid channel state")); } - if create_resp.creation_status() != CreationStatus::OK { - c.state = ChannelState::CreationFailed(create_resp.creation_status().into()); + if create_resp.creation_status != CreationStatus::OK { + c.state = ChannelState::CreationFailed(create_resp.creation_status.into()); return Ok(resp); } c.state = ChannelState::Opened; - let msg = c.processor.start(create_resp.channel_id())?; + let msg = c.processor.start(create_resp.channel_id)?; resp.extend(encode_dvc_messages(id, msg, ChannelFlags::SHOW_PROTOCOL).map_err(|e| encode_err!(e))?); } DrdynvcClientPdu::Close(close_resp) => { debug!("Got DVC Close Response PDU: {close_resp:?}"); - let c = self - .channel_by_id(close_resp.channel_id()) - .map_err(|e| decode_err!(e))?; + let c = self.channel_by_id(close_resp.channel_id).map_err(|e| decode_err!(e))?; if c.state != ChannelState::Opened { return Err(pdu_other_err!("invalid channel state")); } diff --git a/crates/ironrdp-error/src/lib.rs b/crates/ironrdp-error/src/lib.rs index 82316e74..4687bcff 100644 --- a/crates/ironrdp-error/src/lib.rs +++ b/crates/ironrdp-error/src/lib.rs @@ -23,8 +23,8 @@ impl Source for T where T: fmt::Display + fmt::Debug + Send + Sync + 'static #[derive(Debug)] pub struct Error { - context: &'static str, - kind: Kind, + pub context: &'static str, + pub kind: Kind, #[cfg(feature = "std")] source: Option>, #[cfg(all(not(feature = "std"), feature = "alloc"))] @@ -80,10 +80,6 @@ impl Error { &self.kind } - pub fn set_context(&mut self, context: &'static str) { - self.context = context; - } - pub fn report(&self) -> ErrorReport<'_, Kind> { ErrorReport(self) } diff --git a/crates/ironrdp-futures/CHANGELOG.md b/crates/ironrdp-futures/CHANGELOG.md index 3a35de72..d0173f76 100644 --- a/crates/ironrdp-futures/CHANGELOG.md +++ b/crates/ironrdp-futures/CHANGELOG.md @@ -6,15 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.6.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-futures-v0.5.0...ironrdp-futures-v0.6.0)] - 2025-12-18 - - ## [[0.1.3](https://github.com/Devolutions/IronRDP/compare/ironrdp-futures-v0.1.2...ironrdp-futures-v0.1.3)] - 2025-03-12 ### Build - Update dependencies (#695) ([c21fa44fd6](https://github.com/Devolutions/IronRDP/commit/c21fa44fd6f3c6a6b74788ff68e83133c1314caa)) + ## [[0.1.2](https://github.com/Devolutions/IronRDP/compare/ironrdp-futures-v0.1.1...ironrdp-futures-v0.1.2)] - 2025-01-28 ### Documentation diff --git a/crates/ironrdp-futures/Cargo.toml b/crates/ironrdp-futures/Cargo.toml index ed75e138..aa8e67ec 100644 --- a/crates/ironrdp-futures/Cargo.toml +++ b/crates/ironrdp-futures/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-futures" -version = "0.6.0" +version = "0.5.0" readme = "README.md" description = "`Framed*` traits implementation above futures’s traits" edition.workspace = true @@ -17,7 +17,7 @@ test = false [dependencies] futures-util = { version = "0.3", features = ["io"] } # public -ironrdp-async = { path = "../ironrdp-async", version = "0.8" } # public +ironrdp-async = { path = "../ironrdp-async", version = "0.7" } # public bytes = "1" # public [lints] diff --git a/crates/ironrdp-fuzzing/src/oracles/mod.rs b/crates/ironrdp-fuzzing/src/oracles/mod.rs index 2858316c..b04a6788 100644 --- a/crates/ironrdp-fuzzing/src/oracles/mod.rs +++ b/crates/ironrdp-fuzzing/src/oracles/mod.rs @@ -114,8 +114,8 @@ pub fn rdp6_decode_bitmap_stream_to_rgb24(input: &BitmapInput<'_>) { let _ = BitmapStreamDecoder::default().decode_bitmap_stream_to_rgb24( input.src, &mut out, - usize::from(input.width), - usize::from(input.height), + input.width as usize, + input.height as usize, ); } diff --git a/crates/ironrdp-graphics/CHANGELOG.md b/crates/ironrdp-graphics/CHANGELOG.md index 1a7bfd3c..41609a94 100644 --- a/crates/ironrdp-graphics/CHANGELOG.md +++ b/crates/ironrdp-graphics/CHANGELOG.md @@ -6,16 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.7.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-graphics-v0.6.0...ironrdp-graphics-v0.7.0)] - 2025-12-18 - -### Added - -- [**breaking**] `InvalidIntegralConversion` variant in `RlgrError` and `ZgfxError` - -### Build - -- Bump bytemuck from 1.23.2 to 1.24.0 ([#1008](https://github.com/Devolutions/IronRDP/issues/1008)) ([a24a1fa9e8](https://github.com/Devolutions/IronRDP/commit/a24a1fa9e8f1898b2fcdd41d87660ab9e38f89ed)) - ## [[0.6.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-graphics-v0.5.0...ironrdp-graphics-v0.6.0)] - 2025-06-27 ### Bug Fixes diff --git a/crates/ironrdp-graphics/Cargo.toml b/crates/ironrdp-graphics/Cargo.toml index 938612c1..43e4b5e5 100644 --- a/crates/ironrdp-graphics/Cargo.toml +++ b/crates/ironrdp-graphics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-graphics" -version = "0.7.0" +version = "0.6.0" readme = "README.md" description = "RDP image processing primitives" edition.workspace = true @@ -22,13 +22,14 @@ bitvec = "1.0" ironrdp-core = { path = "../ironrdp-core", version = "0.1" } # public ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6", features = ["std"] } # public byteorder = "1.5" # TODO: remove +lazy_static.workspace = true # Legacy crate; prefer std::sync::LazyLock or LazyCell num-derive.workspace = true # TODO: remove num-traits.workspace = true # TODO: remove yuv = { version = "0.8", features = ["rdp"] } [dev-dependencies] bmp = "0.5" -bytemuck = "1.24" +bytemuck = "1.23" expect-test.workspace = true [lints] diff --git a/crates/ironrdp-graphics/src/color_conversion.rs b/crates/ironrdp-graphics/src/color_conversion.rs index 2ec929b5..46f78ad6 100644 --- a/crates/ironrdp-graphics/src/color_conversion.rs +++ b/crates/ironrdp-graphics/src/color_conversion.rs @@ -40,10 +40,6 @@ pub fn ycbcr_to_rgba(input: YCbCrBuffer<'_>, output: &mut [u8]) -> io::Result<() rdp_yuv444_to_rgba(&planar, output, len).map_err(io::Error::other) } -/// # Panics -/// -/// - Panics if `width` > 64. -/// - Panics if `height` > 64. #[expect(clippy::too_many_arguments)] pub fn to_64x64_ycbcr_tile( input: &[u8], @@ -83,15 +79,10 @@ pub fn to_64x64_ycbcr_tile( /// Convert a 16-bit RDP color to RGB representation. Input value should be represented in /// little-endian format. pub fn rdp_16bit_to_rgb(color: u16) -> [u8; 3] { - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked integer underflow)")] - let out = { - let r = u8::try_from(((((color >> 11) & 0x1f) * 527) + 23) >> 6).expect("max possible value is 255"); - let g = u8::try_from(((((color >> 5) & 0x3f) * 259) + 33) >> 6).expect("max possible value is 255"); - let b = u8::try_from((((color & 0x1f) * 527) + 23) >> 6).expect("max possible value is 255"); - [r, g, b] - }; - - out + let r = (((((color >> 11) & 0x1f) * 527) + 23) >> 6) as u8; + let g = (((((color >> 5) & 0x3f) * 259) + 33) >> 6) as u8; + let b = ((((color & 0x1f) * 527) + 23) >> 6) as u8; + [r, g, b] } #[derive(Debug)] diff --git a/crates/ironrdp-graphics/src/dwt.rs b/crates/ironrdp-graphics/src/dwt.rs index 5e13b8df..6381cb54 100644 --- a/crates/ironrdp-graphics/src/dwt.rs +++ b/crates/ironrdp-graphics/src/dwt.rs @@ -22,21 +22,17 @@ fn dwt_vertical(buffer: &[i16], dwt: &mut [i16]) { let h_index = l_index + SUBBAND_WIDTH * total_width; let src_index = y * total_width + x; - dwt[h_index] = i32_to_i16_possible_truncation( - (i32::from(buffer[src_index + total_width]) - - ((i32::from(buffer[src_index]) - + i32::from(buffer[src_index + if n < SUBBAND_WIDTH - 1 { 2 * total_width } else { 0 }])) - >> 1)) - >> 1, - ); - dwt[l_index] = i32_to_i16_possible_truncation( - i32::from(buffer[src_index]) - + if n == 0 { - i32::from(dwt[h_index]) - } else { - (i32::from(dwt[h_index - total_width]) + i32::from(dwt[h_index])) >> 1 - }, - ); + dwt[h_index] = ((i32::from(buffer[src_index + total_width]) + - ((i32::from(buffer[src_index]) + + i32::from(buffer[src_index + if n < SUBBAND_WIDTH - 1 { 2 * total_width } else { 0 }])) + >> 1)) + >> 1) as i16; + dwt[l_index] = (i32::from(buffer[src_index]) + + if n == 0 { + i32::from(dwt[h_index]) + } else { + (i32::from(dwt[h_index - total_width]) + i32::from(dwt[h_index])) >> 1 + }) as i16; } } } @@ -61,20 +57,16 @@ fn dwt_horizontal(mut buffer: &mut [i16], dwt: &[i16 let x = n * 2; // HL - hl[n] = i32_to_i16_possible_truncation( - (i32::from(l_src[x + 1]) - - ((i32::from(l_src[x]) + i32::from(l_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1)) - >> 1, - ); + hl[n] = ((i32::from(l_src[x + 1]) + - ((i32::from(l_src[x]) + i32::from(l_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1)) + >> 1) as i16; // LL - ll[n] = i32_to_i16_possible_truncation( - i32::from(l_src[x]) - + if n == 0 { - i32::from(hl[n]) - } else { - (i32::from(hl[n - 1]) + i32::from(hl[n])) >> 1 - }, - ); + ll[n] = (i32::from(l_src[x]) + + if n == 0 { + i32::from(hl[n]) + } else { + (i32::from(hl[n - 1]) + i32::from(hl[n])) >> 1 + }) as i16; } // H @@ -82,20 +74,16 @@ fn dwt_horizontal(mut buffer: &mut [i16], dwt: &[i16 let x = n * 2; // HH - hh[n] = i32_to_i16_possible_truncation( - (i32::from(h_src[x + 1]) - - ((i32::from(h_src[x]) + i32::from(h_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1)) - >> 1, - ); + hh[n] = ((i32::from(h_src[x + 1]) + - ((i32::from(h_src[x]) + i32::from(h_src[if n < SUBBAND_WIDTH - 1 { x + 2 } else { x }])) >> 1)) + >> 1) as i16; // LH - lh[n] = i32_to_i16_possible_truncation( - i32::from(h_src[x]) - + if n == 0 { - i32::from(hh[n]) - } else { - (i32::from(hh[n - 1]) + i32::from(hh[n])) >> 1 - }, - ); + lh[n] = (i32::from(h_src[x]) + + if n == 0 { + i32::from(hh[n]) + } else { + (i32::from(hh[n - 1]) + i32::from(hh[n])) >> 1 + }) as i16; } hl = &mut hl[SUBBAND_WIDTH..]; @@ -136,30 +124,24 @@ fn inverse_horizontal(mut buffer: &[i16], temp_buffer: &mut [i16], subband_width for _ in 0..subband_width { // Even coefficients - l_dst[0] = i32_to_i16_possible_truncation(i32::from(ll[0]) - ((i32::from(hl[0]) + i32::from(hl[0]) + 1) >> 1)); - h_dst[0] = i32_to_i16_possible_truncation(i32::from(lh[0]) - ((i32::from(hh[0]) + i32::from(hh[0]) + 1) >> 1)); + l_dst[0] = (i32::from(ll[0]) - ((i32::from(hl[0]) + i32::from(hl[0]) + 1) >> 1)) as i16; + h_dst[0] = (i32::from(lh[0]) - ((i32::from(hh[0]) + i32::from(hh[0]) + 1) >> 1)) as i16; for n in 1..subband_width { let x = n * 2; - l_dst[x] = - i32_to_i16_possible_truncation(i32::from(ll[n]) - ((i32::from(hl[n - 1]) + i32::from(hl[n]) + 1) >> 1)); - h_dst[x] = - i32_to_i16_possible_truncation(i32::from(lh[n]) - ((i32::from(hh[n - 1]) + i32::from(hh[n]) + 1) >> 1)); + l_dst[x] = (i32::from(ll[n]) - ((i32::from(hl[n - 1]) + i32::from(hl[n]) + 1) >> 1)) as i16; + h_dst[x] = (i32::from(lh[n]) - ((i32::from(hh[n - 1]) + i32::from(hh[n]) + 1) >> 1)) as i16; } // Odd coefficients for n in 0..subband_width - 1 { let x = n * 2; - l_dst[x + 1] = i32_to_i16_possible_truncation( - i32::from(hl[n] << 1) + ((i32::from(l_dst[x]) + i32::from(l_dst[x + 2])) >> 1), - ); - h_dst[x + 1] = i32_to_i16_possible_truncation( - i32::from(hh[n] << 1) + ((i32::from(h_dst[x]) + i32::from(h_dst[x + 2])) >> 1), - ); + l_dst[x + 1] = (i32::from(hl[n] << 1) + ((i32::from(l_dst[x]) + i32::from(l_dst[x + 2])) >> 1)) as i16; + h_dst[x + 1] = (i32::from(hh[n] << 1) + ((i32::from(h_dst[x]) + i32::from(h_dst[x + 2])) >> 1)) as i16; } let n = subband_width - 1; let x = n * 2; - l_dst[x + 1] = i32_to_i16_possible_truncation(i32::from(hl[n] << 1) + i32::from(l_dst[x])); - h_dst[x + 1] = i32_to_i16_possible_truncation(i32::from(hh[n] << 1) + i32::from(h_dst[x])); + l_dst[x + 1] = (i32::from(hl[n] << 1) + i32::from(l_dst[x])) as i16; + h_dst[x + 1] = (i32::from(hh[n] << 1) + i32::from(h_dst[x])) as i16; hl = &hl[subband_width..]; lh = &lh[subband_width..]; @@ -175,9 +157,8 @@ fn inverse_vertical(mut buffer: &mut [i16], mut temp_buffer: &[i16], subband_wid let total_width = subband_width * 2; for _ in 0..total_width { - buffer[0] = i32_to_i16_possible_truncation( - i32::from(temp_buffer[0]) - ((i32::from(temp_buffer[subband_width * total_width]) * 2 + 1) >> 1), - ); + buffer[0] = + (i32::from(temp_buffer[0]) - ((i32::from(temp_buffer[subband_width * total_width]) * 2 + 1) >> 1)) as i16; let mut l = temp_buffer; let mut lh = &temp_buffer[(subband_width - 1) * total_width..]; @@ -190,28 +171,18 @@ fn inverse_vertical(mut buffer: &mut [i16], mut temp_buffer: &[i16], subband_wid h = &h[total_width..]; // Even coefficients - dst[2 * total_width] = - i32_to_i16_possible_truncation(i32::from(l[0]) - ((i32::from(lh[0]) + i32::from(h[0]) + 1) >> 1)); + dst[2 * total_width] = (i32::from(l[0]) - ((i32::from(lh[0]) + i32::from(h[0]) + 1) >> 1)) as i16; // Odd coefficients - dst[total_width] = i32_to_i16_possible_truncation( - i32::from(lh[0] << 1) + ((i32::from(dst[0]) + i32::from(dst[2 * total_width])) >> 1), - ); + dst[total_width] = + (i32::from(lh[0] << 1) + ((i32::from(dst[0]) + i32::from(dst[2 * total_width])) >> 1)) as i16; dst = &mut dst[2 * total_width..]; } - dst[total_width] = i32_to_i16_possible_truncation( - i32::from(lh[total_width] << 1) + ((i32::from(dst[0]) + i32::from(dst[0])) >> 1), - ); + dst[total_width] = (i32::from(lh[total_width] << 1) + ((i32::from(dst[0]) + i32::from(dst[0])) >> 1)) as i16; temp_buffer = &temp_buffer[1..]; buffer = &mut buffer[1..]; } } - -#[expect(clippy::as_conversions)] -#[expect(clippy::cast_possible_truncation)] -fn i32_to_i16_possible_truncation(value: i32) -> i16 { - value as i16 -} diff --git a/crates/ironrdp-graphics/src/lib.rs b/crates/ironrdp-graphics/src/lib.rs index 02d4104a..192c5bba 100644 --- a/crates/ironrdp-graphics/src/lib.rs +++ b/crates/ironrdp-graphics/src/lib.rs @@ -1,6 +1,10 @@ #![cfg_attr(doc, doc = include_str!("../README.md"))] #![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")] #![allow(clippy::arithmetic_side_effects)] // FIXME: remove +#![allow(clippy::cast_lossless)] // FIXME: remove +#![allow(clippy::cast_possible_truncation)] // FIXME: remove +#![allow(clippy::cast_possible_wrap)] // FIXME: remove +#![allow(clippy::cast_sign_loss)] // FIXME: remove pub mod color_conversion; pub mod diff; @@ -17,9 +21,6 @@ pub mod zgfx; mod utils; -/// # Panics -/// -/// Panics if `input.len()` is not 4096 (64 * 46). pub fn rfx_encode_component( input: &mut [i16], output: &mut [u8], diff --git a/crates/ironrdp-graphics/src/pointer.rs b/crates/ironrdp-graphics/src/pointer.rs index 26dbdd40..48b17927 100644 --- a/crates/ironrdp-graphics/src/pointer.rs +++ b/crates/ironrdp-graphics/src/pointer.rs @@ -260,12 +260,9 @@ impl DecodedPointer { } else if target.should_premultiply_alpha() { // Calculate premultiplied alpha via integer arithmetic let with_premultiplied_alpha = [ - u8::try_from((u16::from(color[0]) * u16::from(color[0])) >> 8) - .expect("(u16 >> 8) fits into u8"), - u8::try_from((u16::from(color[1]) * u16::from(color[1])) >> 8) - .expect("(u16 >> 8) fits into u8"), - u8::try_from((u16::from(color[2]) * u16::from(color[2])) >> 8) - .expect("(u16 >> 8) fits into u8"), + ((color[0] as u16 * color[0] as u16) >> 8) as u8, + ((color[1] as u16 * color[1] as u16) >> 8) as u8, + ((color[2] as u16 * color[2] as u16) >> 8) as u8, color[3], ]; bitmap_data.extend_from_slice(&with_premultiplied_alpha); diff --git a/crates/ironrdp-graphics/src/quantization.rs b/crates/ironrdp-graphics/src/quantization.rs index c4ab7d97..38c0f65b 100644 --- a/crates/ironrdp-graphics/src/quantization.rs +++ b/crates/ironrdp-graphics/src/quantization.rs @@ -11,7 +11,7 @@ pub fn decode(buffer: &mut [i16], quant: &Quant) { let (first_level, buffer) = buffer.split_at_mut(FIRST_LEVEL_SUBBANDS_COUNT * FIRST_LEVEL_SIZE); let (second_level, third_level) = buffer.split_at_mut(SECOND_LEVEL_SUBBANDS_COUNT * SECOND_LEVEL_SIZE); - let decode_chunk = |a: (&mut [i16], u8)| decode_block(a.0, i16::from(a.1) - 1); + let decode_chunk = |a: (&mut [i16], u8)| decode_block(a.0, a.1 as i16 - 1); first_level .chunks_mut(FIRST_LEVEL_SIZE) @@ -49,7 +49,7 @@ pub fn encode(buffer: &mut [i16], quant: &Quant) { let (first_level, buffer) = buffer.split_at_mut(FIRST_LEVEL_SUBBANDS_COUNT * FIRST_LEVEL_SIZE); let (second_level, third_level) = buffer.split_at_mut(SECOND_LEVEL_SUBBANDS_COUNT * SECOND_LEVEL_SIZE); - let encode_chunk = |a: (&mut [i16], u8)| encode_block(a.0, i16::from(a.1) - 1); + let encode_chunk = |a: (&mut [i16], u8)| encode_block(a.0, a.1 as i16 - 1); first_level .chunks_mut(FIRST_LEVEL_SIZE) diff --git a/crates/ironrdp-graphics/src/rdp6/bitmap_stream/decoder.rs b/crates/ironrdp-graphics/src/rdp6/bitmap_stream/decoder.rs index d5f07b67..0e26231e 100644 --- a/crates/ironrdp-graphics/src/rdp6/bitmap_stream/decoder.rs +++ b/crates/ironrdp-graphics/src/rdp6/bitmap_stream/decoder.rs @@ -195,9 +195,8 @@ impl<'a> BitmapStreamDecoderImpl<'a> { } fn write_aycocg_planes_to_rgb24(&self, params: AYCoCgParams, planes: &[u8], dst: &mut Vec) { - #![allow(clippy::similar_names, reason = "it’s hard to find better names for co, cg, etc")] - - let sample_shift = usize::from(params.chroma_subsampling); + #![allow(clippy::similar_names)] // It’s hard to find better names for co, cg, etc. + let sample_shift = params.chroma_subsampling as usize; let (y_offset, co_offset, cg_offset) = ( self.color_plane_offsets[0], @@ -266,13 +265,12 @@ fn ycocg_with_cll_to_rgb(cll: u8, y: u8, co: u8, cg: u8) -> Rgb { // |R| |1 1/2 -1/2| |Y | // |G| = |1 0 1/2| * |Co| // |B| |1 -1/2 -1/2| |Cg| - let chroma_shift = cll - 1; + let chroma_shift = (cll - 1) as usize; - let clip_i16 = - |v: i16| u8::try_from(v.clamp(0, 255)).expect("fits into u8 because the value is clamped to [0..256]"); + let clip_i16 = |v: i16| v.clamp(0, 255) as u8; - let co_signed = (co << chroma_shift).cast_signed(); - let cg_signed = (cg << chroma_shift).cast_signed(); + let co_signed = (co << chroma_shift) as i8; + let cg_signed = (cg << chroma_shift) as i8; let y = i16::from(y); let co = i16::from(co_signed); diff --git a/crates/ironrdp-graphics/src/rdp6/rle.rs b/crates/ironrdp-graphics/src/rdp6/rle.rs index 7e9a66fc..7f74cb57 100644 --- a/crates/ironrdp-graphics/src/rdp6/rle.rs +++ b/crates/ironrdp-graphics/src/rdp6/rle.rs @@ -93,9 +93,9 @@ impl RlePlaneDecoder { let raw_bytes_field = (control_byte >> 4) & 0x0F; let (run_length, raw_bytes_count) = match rle_bytes_field { - 1 => (16 + usize::from(raw_bytes_field), 0), - 2 => (32 + usize::from(raw_bytes_field), 0), - rle_control => (usize::from(rle_control), usize::from(raw_bytes_field)), + 1 => (16 + raw_bytes_field as usize, 0), + 2 => (32 + raw_bytes_field as usize, 0), + rle_control => (rle_control as usize, raw_bytes_field as usize), }; self.decoded_data_len = raw_bytes_count + run_length; @@ -207,8 +207,7 @@ impl RleEncoderScanlineIterator { } fn delta_value(prev: u8, next: u8) -> u8 { - let mut result = u8::try_from((i16::from(next) - i16::from(prev)) & 0xFF) - .expect("masking with 0xFF ensures that the value fits into u8"); + let mut result = (next as i16 - prev as i16) as u8; // bit magic from 3.1.9.2.1 of [MS-RDPEGDI]. if result < 128 { @@ -327,10 +326,7 @@ impl RlePlaneEncoder { raw = &raw[15..]; } - let raw_len = u8::try_from(raw.len()).expect("max value is guaranteed to be 15 due to the prior while loop"); - let run_capped = u8::try_from(cmp::min(run, 15)).expect("max value is guaranteed to be 15"); - - let control = (raw_len << 4) + run_capped; + let control = ((raw.len() as u8) << 4) + cmp::min(run, 15) as u8; ensure_size!(dst: dst, size: raw.len() + 1); @@ -356,8 +352,7 @@ impl RlePlaneEncoder { while run >= 16 { ensure_size!(dst: dst, size: 1); - let current = u8::try_from(cmp::min(run, MAX_DECODED_SEGMENT_SIZE)) - .expect("max value is guaranteed to be MAX_DECODED_SEGMENT_SIZE (47)"); + let current = cmp::min(run, MAX_DECODED_SEGMENT_SIZE) as u8; let c_raw_bytes = cmp::min(current / 16, 2); let n_run_length = current - c_raw_bytes * 16; @@ -366,7 +361,7 @@ impl RlePlaneEncoder { dst.write_u8(control); written += 1; - run -= usize::from(current); + run -= current as usize; } if run > 0 { diff --git a/crates/ironrdp-graphics/src/rectangle_processing.rs b/crates/ironrdp-graphics/src/rectangle_processing.rs index eaffb39e..53d69171 100644 --- a/crates/ironrdp-graphics/src/rectangle_processing.rs +++ b/crates/ironrdp-graphics/src/rectangle_processing.rs @@ -400,86 +400,88 @@ fn bands_internals_equal(first_band: &[InclusiveRectangle], second_band: &[Inclu #[cfg(test)] mod tests { - use std::sync::LazyLock; + use lazy_static::lazy_static; use super::*; - static REGION_FOR_RECTANGLES_INTERSECTION: LazyLock = LazyLock::new(|| Region { - extents: InclusiveRectangle { - left: 1, - top: 1, - right: 11, - bottom: 9, - }, - rectangles: vec![ - InclusiveRectangle { + lazy_static! { + static ref REGION_FOR_RECTANGLES_INTERSECTION: Region = Region { + extents: InclusiveRectangle { left: 1, top: 1, - right: 5, - bottom: 3, - }, - InclusiveRectangle { - left: 7, - top: 1, - right: 8, - bottom: 3, - }, - InclusiveRectangle { - left: 9, - top: 1, right: 11, - bottom: 3, - }, - InclusiveRectangle { - left: 7, - top: 3, - right: 11, - bottom: 4, - }, - InclusiveRectangle { - left: 3, - top: 4, - right: 6, - bottom: 6, - }, - InclusiveRectangle { - left: 7, - top: 4, - right: 11, - bottom: 6, - }, - InclusiveRectangle { - left: 1, - top: 6, - right: 3, - bottom: 8, - }, - InclusiveRectangle { - left: 4, - top: 6, - right: 5, - bottom: 8, - }, - InclusiveRectangle { - left: 6, - top: 6, - right: 10, - bottom: 8, - }, - InclusiveRectangle { - left: 4, - top: 8, - right: 5, bottom: 9, }, - InclusiveRectangle { - left: 6, - top: 8, - right: 10, - bottom: 9, - }, - ], - }); + rectangles: vec![ + InclusiveRectangle { + left: 1, + top: 1, + right: 5, + bottom: 3, + }, + InclusiveRectangle { + left: 7, + top: 1, + right: 8, + bottom: 3, + }, + InclusiveRectangle { + left: 9, + top: 1, + right: 11, + bottom: 3, + }, + InclusiveRectangle { + left: 7, + top: 3, + right: 11, + bottom: 4, + }, + InclusiveRectangle { + left: 3, + top: 4, + right: 6, + bottom: 6, + }, + InclusiveRectangle { + left: 7, + top: 4, + right: 11, + bottom: 6, + }, + InclusiveRectangle { + left: 1, + top: 6, + right: 3, + bottom: 8, + }, + InclusiveRectangle { + left: 4, + top: 6, + right: 5, + bottom: 8, + }, + InclusiveRectangle { + left: 6, + top: 6, + right: 10, + bottom: 8, + }, + InclusiveRectangle { + left: 4, + top: 8, + right: 5, + bottom: 9, + }, + InclusiveRectangle { + left: 6, + top: 8, + right: 10, + bottom: 9, + }, + ], + }; + } #[test] fn union_rectangle_sets_extents_and_single_rectangle_for_empty_region() { diff --git a/crates/ironrdp-graphics/src/rlgr.rs b/crates/ironrdp-graphics/src/rlgr.rs index 3fc33ffa..c73123ed 100644 --- a/crates/ironrdp-graphics/src/rlgr.rs +++ b/crates/ironrdp-graphics/src/rlgr.rs @@ -63,23 +63,17 @@ impl<'a> BitStream<'a> { } pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result { - #![expect( - clippy::as_conversions, - reason = "u32-to-usize and usize-to-u32 conversions, mostly fine, and hot loop" - )] + let mut k: u32 = 1; + let kr: u32 = 1; + let mut kp: u32 = k << LS_GR; + let mut krp: u32 = kr << LS_GR; if input.is_empty() { return Err(RlgrError::EmptyTile); } - let mut k: u32 = 1; - let kr: u32 = 1; - let mut kp: u32 = k << LS_GR; - let mut krp: u32 = kr << LS_GR; let mut bits = BitStream::new(tile); - let mut input = input.iter().peekable(); - while input.peek().is_some() { match CompressionMode::from(k) { CompressionMode::RunLength => { @@ -104,7 +98,7 @@ pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result< bits.output_bits(k as usize, nz); if let Some(val) = input.next() { - let mag = u32::from(val.unsigned_abs()); + let mag = val.unsigned_abs() as u32; bits.output_bit(1, *val < 0); code_gr(&mut bits, &mut krp, mag - 1); } @@ -112,11 +106,9 @@ pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result< k = kp >> LS_GR; } CompressionMode::GolombRice => { - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (prior check)")] let input_first = *input .next() .expect("value is guaranteed to be `Some` due to the prior check"); - match mode { EntropyAlgorithm::Rlgr1 => { let two_ms = get_2magsign(input_first); @@ -158,53 +150,37 @@ pub fn encode(mode: EntropyAlgorithm, input: &[i16], tile: &mut [u8]) -> Result< fn get_2magsign(val: i16) -> u32 { let sign = if val < 0 { 1 } else { 0 }; - (u32::from(val.unsigned_abs())) * 2 - sign + (val.unsigned_abs() as u32) * 2 - sign } fn code_gr(bits: &mut BitStream<'_>, krp: &mut u32, val: u32) { - #![expect( - clippy::as_conversions, - reason = "u32-to-usize and usize-to-u32 conversions, mostly fine, and hot loop" - )] - let kr = (*krp >> LS_GR) as usize; + let vk = (val >> kr) as usize; - let vk = val >> kr; - let vk_usize = vk as usize; - - bits.output_bit(vk_usize, true); + bits.output_bit(vk, true); bits.output_bit(1, false); - if kr != 0 { let remainder = val & ((1 << kr) - 1); bits.output_bits(kr, remainder); } - if vk == 0 { *krp = krp.saturating_sub(2); } else if vk > 1 { - *krp = min(*krp + vk, KP_MAX); + *krp = min(*krp + vk as u32, KP_MAX); } } pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Result<(), RlgrError> { - #![expect( - clippy::as_conversions, - clippy::cast_possible_truncation, - reason = "u32-to-usize and usize-to-u32 conversions, mostly fine, and hot loop" - )] - - if tile.is_empty() { - return Err(RlgrError::EmptyTile); - } - let mut k: u32 = 1; let mut kr: u32 = 1; let mut kp: u32 = k << LS_GR; let mut krp: u32 = kr << LS_GR; - let mut bits = Bits::new(BitSlice::from_slice(tile)); + if tile.is_empty() { + return Err(RlgrError::EmptyTile); + } + let mut bits = Bits::new(BitSlice::from_slice(tile)); while !bits.is_empty() && !output.is_empty() { match CompressionMode::from(k) { CompressionMode::RunLength => { @@ -223,7 +199,7 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re kp = kp.saturating_sub(DN_GR); k = kp >> LS_GR; - let magnitude = compute_rl_magnitude(sign_bit, code_remainder)?; + let magnitude = compute_rl_magnitude(sign_bit, code_remainder); let size = min(run as usize, output.len()); fill(&mut output[..size], 0); @@ -240,7 +216,7 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re match mode { EntropyAlgorithm::Rlgr1 => { - let magnitude = compute_rlgr1_magnitude(code_remainder, &mut k, &mut kp)?; + let magnitude = compute_rlgr1_magnitude(code_remainder, &mut k, &mut kp); write_byte!(output, magnitude); } EntropyAlgorithm::Rlgr3 => { @@ -256,10 +232,10 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re k = kp >> LS_GR; } - let magnitude = compute_rlgr3_magnitude(val1)?; + let magnitude = compute_rlgr3_magnitude(val1); write_byte!(output, magnitude); - let magnitude = compute_rlgr3_magnitude(val2)?; + let magnitude = compute_rlgr3_magnitude(val2); write_byte!(output, magnitude); } } @@ -267,7 +243,7 @@ pub fn decode(mode: EntropyAlgorithm, tile: &[u8], mut output: &mut [i16]) -> Re } } - // Fill remaining buffer with zeros. + // fill remaining buffer with zeros fill(output, 0); Ok(()) @@ -310,41 +286,37 @@ fn count_run(number_of_zeros: usize, k: &mut u32, kp: &mut u32) -> u32 { .sum() } -fn compute_rl_magnitude(sign_bit: u8, code_remainder: u32) -> Result { - let rl_magnitude = - i16::try_from(code_remainder + 1).map_err(|_| RlgrError::InvalidIntegralConversion("code remainder + 1"))?; - +fn compute_rl_magnitude(sign_bit: u8, code_remainder: u32) -> i16 { if sign_bit != 0 { - Ok(-rl_magnitude) + -((code_remainder + 1) as i16) } else { - Ok(rl_magnitude) + (code_remainder + 1) as i16 } } -fn compute_rlgr1_magnitude(code_remainder: u32, k: &mut u32, kp: &mut u32) -> Result { +fn compute_rlgr1_magnitude(code_remainder: u32, k: &mut u32, kp: &mut u32) -> i16 { if code_remainder == 0 { *kp = min(*kp + UQ_GR, KP_MAX); *k = *kp >> LS_GR; - Ok(0) + 0 } else { *kp = kp.saturating_sub(DQ_GR); *k = *kp >> LS_GR; if code_remainder % 2 != 0 { - Ok(-i16::try_from((code_remainder + 1) >> 1) - .map_err(|_| RlgrError::InvalidIntegralConversion("(code remainder + 1) >> 1"))?) + -(((code_remainder + 1) >> 1) as i16) } else { - i16::try_from(code_remainder >> 1).map_err(|_| RlgrError::InvalidIntegralConversion("code remainder >> 1")) + (code_remainder >> 1) as i16 } } } -fn compute_rlgr3_magnitude(val: u32) -> Result { +fn compute_rlgr3_magnitude(val: u32) -> i16 { if val % 2 != 0 { - Ok(-i16::try_from((val + 1) >> 1).map_err(|_| RlgrError::InvalidIntegralConversion("(val + 1) >> 1"))?) + -(((val + 1) >> 1) as i16) } else { - i16::try_from(val >> 1).map_err(|_| RlgrError::InvalidIntegralConversion("val >> 1")) + (val >> 1) as i16 } } @@ -361,17 +333,11 @@ fn compute_n_index(code_remainder: u32) -> usize { } fn update_parameters_according_to_number_of_ones(number_of_ones: usize, kr: &mut u32, krp: &mut u32) { - #![expect( - clippy::as_conversions, - clippy::cast_possible_truncation, - reason = "usize-to-u32 conversions, hot loop" - )] - if number_of_ones == 0 { *krp = (*krp).saturating_sub(2); *kr = *krp >> LS_GR; } else if number_of_ones > 1 { - *krp = min(*krp + (number_of_ones as u32), KP_MAX); + *krp = min(*krp + number_of_ones as u32, KP_MAX); *kr = *krp >> LS_GR; } } @@ -397,7 +363,6 @@ pub enum RlgrError { Io(io::Error), Yuv(YuvError), EmptyTile, - InvalidIntegralConversion(&'static str), } impl core::fmt::Display for RlgrError { @@ -406,7 +371,6 @@ impl core::fmt::Display for RlgrError { Self::Io(_) => write!(f, "IO error"), Self::Yuv(_) => write!(f, "YUV error"), Self::EmptyTile => write!(f, "the input tile is empty"), - Self::InvalidIntegralConversion(s) => write!(f, "invalid `{s}`: out of range integral type conversion"), } } } @@ -417,7 +381,6 @@ impl core::error::Error for RlgrError { Self::Io(error) => Some(error), Self::Yuv(error) => Some(error), Self::EmptyTile => None, - Self::InvalidIntegralConversion(_) => None, } } } diff --git a/crates/ironrdp-graphics/src/zgfx/control_messages.rs b/crates/ironrdp-graphics/src/zgfx/control_messages.rs index 9e696c03..52231929 100644 --- a/crates/ironrdp-graphics/src/zgfx/control_messages.rs +++ b/crates/ironrdp-graphics/src/zgfx/control_messages.rs @@ -23,14 +23,12 @@ impl<'a> SegmentedDataPdu<'a> { match descriptor { SegmentedDescriptor::Single => Ok(SegmentedDataPdu::Single(BulkEncodedData::from_buffer(buffer)?)), SegmentedDescriptor::Multipart => { - let segment_count = usize::from(buffer.read_u16::()?); - let uncompressed_size = usize::try_from(buffer.read_u32::()?) - .map_err(|_| ZgfxError::InvalidIntegralConversion("segments uncompressed size"))?; + let segment_count = buffer.read_u16::()? as usize; + let uncompressed_size = buffer.read_u32::()? as usize; let mut segments = Vec::with_capacity(segment_count); for _ in 0..segment_count { - let size = usize::try_from(buffer.read_u32::()?) - .map_err(|_| ZgfxError::InvalidIntegralConversion("segment data size"))?; + let size = buffer.read_u32::()? as usize; let (segment_data, new_buffer) = buffer.split_at(size); buffer = new_buffer; @@ -86,7 +84,7 @@ bitflags! { #[cfg(test)] mod test { - use std::sync::LazyLock; + use lazy_static::lazy_static; use super::*; @@ -113,30 +111,29 @@ mod test { 0x02, // the third segment: data ]; - static SINGLE_SEGMENTED_DATA_PDU: LazyLock> = LazyLock::new(|| { - SegmentedDataPdu::Single(BulkEncodedData { + lazy_static! { + static ref SINGLE_SEGMENTED_DATA_PDU: SegmentedDataPdu<'static> = SegmentedDataPdu::Single(BulkEncodedData { compression_flags: CompressionFlags::COMPRESSED, data: &SINGLE_SEGMENTED_DATA_PDU_BUFFER[2..], - }) - }); - static MULTIPART_SEGMENTED_DATA_PDU: LazyLock> = - LazyLock::new(|| SegmentedDataPdu::Multipart { + }); + static ref MULTIPART_SEGMENTED_DATA_PDU: SegmentedDataPdu<'static> = SegmentedDataPdu::Multipart { uncompressed_size: 0x2B, segments: vec![ BulkEncodedData { compression_flags: CompressionFlags::empty(), - data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[12..12 + 16], + data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[12..12 + 16] }, BulkEncodedData { compression_flags: CompressionFlags::empty(), - data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[33..33 + 13], + data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[33..33 + 13] }, BulkEncodedData { compression_flags: CompressionFlags::COMPRESSED, - data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[51..], + data: &MULTIPART_SEGMENTED_DATA_PDU_BUFFER[51..] }, ], - }); + }; + } #[test] fn from_buffer_correctly_parses_zgfx_single_segmented_data_pdu() { diff --git a/crates/ironrdp-graphics/src/zgfx/mod.rs b/crates/ironrdp-graphics/src/zgfx/mod.rs index 688e655d..90aaa3a2 100644 --- a/crates/ironrdp-graphics/src/zgfx/mod.rs +++ b/crates/ironrdp-graphics/src/zgfx/mod.rs @@ -4,7 +4,6 @@ mod circular_buffer; mod control_messages; use std::io::{self, Write as _}; -use std::sync::LazyLock; use bitvec::bits; use bitvec::field::BitField as _; @@ -79,8 +78,8 @@ impl Decompressor { let mut bits = BitSlice::from_slice(encoded_data); // The value of the last byte indicates the number of unused bits in the final byte - bits = &bits - [..8 * (encoded_data.len() - 1) - usize::from(*encoded_data.last().expect("encoded_data is not empty"))]; + bits = + &bits[..8 * (encoded_data.len() - 1) - *encoded_data.last().expect("encoded_data is not empty") as usize]; let mut bits = Bits::new(bits); let mut bytes_written = 0; @@ -135,15 +134,14 @@ fn handle_match( distance_base: u32, history: &mut FixedCircularBuffer, output: &mut Vec, -) -> Result { +) -> io::Result { // Each token has been assigned a different base distance // and number of additional value bits to be added to compute the full distance. - let distance = usize::try_from(distance_base + bits.split_to(distance_value_size).load_be::()) - .map_err(|_| ZgfxError::InvalidIntegralConversion("token's full distance"))?; + let distance = (distance_base + bits.split_to(distance_value_size).load_be::()) as usize; if distance == 0 { - read_unencoded_bytes(bits, history, output).map_err(ZgfxError::from) + read_unencoded_bytes(bits, history, output) } else { read_encoded_bytes(bits, distance, history, output) } @@ -157,7 +155,7 @@ fn read_unencoded_bytes( // A match distance of zero is a special case, // which indicates that an unencoded run of bytes follows. // The count of bytes is encoded as a 15-bit value - let length = bits.split_to(15).load_be::(); + let length = bits.split_to(15).load_be::() as usize; if bits.remaining_bits_of_last_byte() > 0 { let pad_to_byte_boundary = 8 - bits.remaining_bits_of_last_byte(); @@ -180,7 +178,7 @@ fn read_encoded_bytes( distance: usize, history: &mut FixedCircularBuffer, output: &mut Vec, -) -> Result { +) -> io::Result { // A match length prefix follows the token and indicates // how many additional bits will be needed to get the full length // (the number of bytes to be copied). @@ -193,12 +191,9 @@ fn read_encoded_bytes( 3 } else { - let length = bits.split_to(length_token_size + 1).load_be::(); + let length = bits.split_to(length_token_size + 1).load_be::() as usize; - let length_token_size = u32::try_from(length_token_size) - .map_err(|_| ZgfxError::InvalidIntegralConversion("length of the token size"))?; - - let base = 2usize.pow(length_token_size + 1); + let base = 2u32.pow(length_token_size as u32 + 1) as usize; base + length }; @@ -228,8 +223,8 @@ enum TokenType { }, } -static TOKEN_TABLE: LazyLock<[Token; 40]> = LazyLock::new(|| { - [ +lazy_static::lazy_static! { + static ref TOKEN_TABLE: [Token; 40] = [ Token { prefix: bits![static u8, Msb0; 0], ty: TokenType::NullLiteral, @@ -432,8 +427,8 @@ static TOKEN_TABLE: LazyLock<[Token; 40]> = LazyLock::new(|| { distance_base: 17_094_304, }, }, - ] -}); + ]; +} #[derive(Debug)] pub enum ZgfxError { @@ -445,7 +440,6 @@ pub enum ZgfxError { uncompressed_size: usize, }, TokenBitsNotFound, - InvalidIntegralConversion(&'static str), } impl core::fmt::Display for ZgfxError { @@ -462,7 +456,6 @@ impl core::fmt::Display for ZgfxError { "decompressed size of segments ({decompressed_size}) does not equal to uncompressed size ({uncompressed_size})", ), Self::TokenBitsNotFound => write!(f, "token bits not found"), - Self::InvalidIntegralConversion(type_name) => write!(f, "invalid `{type_name}`: out of range integral type conversion"), } } } @@ -475,7 +468,6 @@ impl core::error::Error for ZgfxError { Self::InvalidSegmentedDescriptor => None, Self::InvalidDecompressedSize { .. } => None, Self::TokenBitsNotFound => None, - Self::InvalidIntegralConversion(_) => None, } } } diff --git a/crates/ironrdp-input/src/lib.rs b/crates/ironrdp-input/src/lib.rs index 42292a38..d40d9e53 100644 --- a/crates/ironrdp-input/src/lib.rs +++ b/crates/ironrdp-input/src/lib.rs @@ -24,10 +24,6 @@ pub enum MouseButton { } impl MouseButton { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] pub fn as_idx(self) -> usize { self as usize } @@ -82,11 +78,7 @@ impl Scancode { pub const fn from_u16(scancode: u16) -> Self { let extended = scancode & 0xE000 == 0xE000; - #[expect( - clippy::as_conversions, - clippy::cast_possible_truncation, - reason = "truncating on purpose" - )] + #[expect(clippy::cast_possible_truncation)] // truncating on purpose let code = scancode as u8; Self { code, extended } @@ -94,7 +86,6 @@ impl Scancode { pub fn as_idx(self) -> usize { if self.extended { - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (integer upcast)")] usize::from(self.code).checked_add(256).expect("never overflow") } else { usize::from(self.code) @@ -352,7 +343,6 @@ impl Database { let mut events = SmallVec::new(); for idx in self.mouse_buttons.iter_ones() { - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked integer downcast)")] let button = MouseButton::from_idx(idx).expect("in-range index"); let event = match MouseButtonFlags::from(button) { @@ -375,12 +365,9 @@ impl Database { // The keyboard bit array size is 512. for idx in self.keyboard.iter_ones() { let (scancode, extended) = if idx >= 256 { - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked integer underflow)")] let extended_code = idx.checked_sub(256).expect("never underflow"); - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked integer downcast)")] (u8::try_from(extended_code).expect("always in the range"), true) } else { - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked integer downcast)")] (u8::try_from(idx).expect("always in the range"), false) }; diff --git a/crates/ironrdp-mstsgu/Cargo.toml b/crates/ironrdp-mstsgu/Cargo.toml index b194f467..fdd83edb 100644 --- a/crates/ironrdp-mstsgu/Cargo.toml +++ b/crates/ironrdp-mstsgu/Cargo.toml @@ -30,12 +30,12 @@ hyper-util = { version = "0.1", features = ["tokio"] } hyper = { version = "1.7", features = ["client", "http1"] } ironrdp-core = { path = "../ironrdp-core", version = "0.1", features = ["std"] } ironrdp-error = { path = "../ironrdp-error", version = "0.1" } -ironrdp-tls = { path = "../ironrdp-tls", version = "0.2" } +ironrdp-tls = { path = "../ironrdp-tls", version = "0.1" } log = "0.4" -tokio-tungstenite = { version = "0.28" } +tokio-tungstenite = { version = "0.27" } tokio-util = { version = "0.7" } tokio = { version = "1.43", features = ["macros", "rt"] } -uuid = { version = "1.19", features = ["v4"] } +uuid = { version = "1.16", features = ["v4"] } [lints] workspace = true diff --git a/crates/ironrdp-mstsgu/src/lib.rs b/crates/ironrdp-mstsgu/src/lib.rs index b8b27c84..0eb078e5 100644 --- a/crates/ironrdp-mstsgu/src/lib.rs +++ b/crates/ironrdp-mstsgu/src/lib.rs @@ -144,7 +144,7 @@ impl GwClient { .header(hyper::header::SEC_WEBSOCKET_VERSION, "13") .header(hyper::header::SEC_WEBSOCKET_KEY, generate_key()) .body(http_body_util::Empty::::new()) - .map_err(|e| custom_err!("failed to build request", e))?; + .expect("Failed to build request"); let stream = hyper_util::rt::tokio::TokioIo::new(stream); let (mut sender, mut conn) = hyper::client::conn::http1::handshake(stream) @@ -200,7 +200,8 @@ impl GwClient { let work = tokio::spawn(async move { let iv = Duration::from_secs(15 * 60); - let mut keepalive_interval = tokio::time::interval_at(tokio::time::Instant::now() + iv, iv); + let mut keepalive_interval: tokio::time::Interval = + tokio::time::interval_at(tokio::time::Instant::now() + iv, iv); loop { let mut wsbuf = [0u8; 8192]; @@ -221,8 +222,7 @@ impl GwClient { let mut cur = ReadCursor::new(&msg); let hdr = PktHdr::decode(&mut cur).map_err(|e| custom_err!("Header Decode", e))?; - let header_length = usize::try_from(hdr.length).map_err(|_| Error::new("PktHdr too big", GwErrorKind::Decode))?; - assert!(cur.len() >= header_length - hdr.size()); + assert!(cur.len() >= hdr.length as usize - hdr.size()); match hdr.ty { PktTy::Keepalive => { continue; @@ -288,10 +288,7 @@ impl GwConn { let mut cur = ReadCursor::new(&msg); let hdr = PktHdr::decode(&mut cur).map_err(|_| Error::new("PktHdr", GwErrorKind::Decode))?; - - let header_length = - usize::try_from(hdr.length).map_err(|_| Error::new("PktHdr too big", GwErrorKind::Decode))?; - if cur.len() != header_length - hdr.size() { + if cur.len() != hdr.length as usize - hdr.size() { return Err(Error::new("read_packet", GwErrorKind::PacketEof)); } @@ -319,7 +316,7 @@ impl GwConn { async fn tunnel(&mut self) -> Result<(), Error> { let req = TunnelReqPkt { // Havent seen any server working without this. - caps: HttpCapsTy::MessagingConsentSign.as_u32(), + caps: HttpCapsTy::MessagingConsentSign as u32, fields_present: 0, ..TunnelReqPkt::default() }; @@ -354,7 +351,7 @@ impl GwConn { let resp: TunnelAuthRespPkt = TunnelAuthRespPkt::decode(&mut cur).map_err(|_| Error::new("TunnelAuth", GwErrorKind::Decode))?; - if resp.error_code() != 0 { + if resp.error_code != 0 { return Err(Error::new("TunnelAuth", GwErrorKind::Connect)); } Ok(()) @@ -373,7 +370,7 @@ impl GwConn { let mut cur: ReadCursor<'_> = ReadCursor::new(&bytes); let resp: ChannelResp = ChannelResp::decode(&mut cur).map_err(|_| Error::new("ChannelResp", GwErrorKind::Decode))?; - if resp.error_code() != 0 { + if resp.error_code != 0 { return Err(Error::new("ChannelCreate", GwErrorKind::Connect)); } assert!(cur.eof()); diff --git a/crates/ironrdp-mstsgu/src/proto.rs b/crates/ironrdp-mstsgu/src/proto.rs index 4efcf08d..494c7eff 100644 --- a/crates/ironrdp-mstsgu/src/proto.rs +++ b/crates/ironrdp-mstsgu/src/proto.rs @@ -37,16 +37,6 @@ pub(crate) enum PktTy { Keepalive = 0x0D, } -impl PktTy { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] - fn as_u16(self) -> u16 { - self as u16 - } -} - impl TryFrom for PktTy { type Error = (); @@ -76,7 +66,7 @@ impl TryFrom for PktTy { #[derive(Default, Debug)] pub(crate) struct PktHdr { pub ty: PktTy, - pub _reserved: u16, + _reserved: u16, pub length: u32, } @@ -88,7 +78,7 @@ impl Encode for PktHdr { fn encode(&self, dst: &mut WriteCursor<'_>) -> ironrdp_core::EncodeResult<()> { ensure_size!(in: dst, size: self.size()); - dst.write_u16(self.ty.as_u16()); + dst.write_u16(self.ty as u16); dst.write_u16(self._reserved); dst.write_u32(self.length); @@ -193,7 +183,7 @@ impl Decode<'_> for HandshakeRespPkt { pub(crate) struct TunnelReqPkt { pub caps: u32, pub fields_present: u16, - pub _reserved: u16, + pub(crate) _reserved: u16, } impl Encode for TunnelReqPkt { @@ -225,7 +215,6 @@ impl Encode for TunnelReqPkt { /// 2.2.5.3.9 HTTP_CAPABILITY_TYPE Enumeration #[repr(u32)] #[expect(dead_code)] -#[derive(Copy, Clone)] pub(crate) enum HttpCapsTy { QuarSOH = 1, IdleTimeout = 2, @@ -235,19 +224,8 @@ pub(crate) enum HttpCapsTy { UdpTransport = 0x20, } -impl HttpCapsTy { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] - pub(crate) fn as_u32(self) -> u32 { - self as u32 - } -} - /// 2.2.5.3.8 HTTP_TUNNEL_RESPONSE_FIELDS_PRESENT_FLAGS #[repr(u16)] -#[derive(Copy, Clone)] enum HttpTunnelResponseFields { TunnelID = 1, Caps = 2, @@ -256,16 +234,6 @@ enum HttpTunnelResponseFields { Consent = 0x10, } -impl HttpTunnelResponseFields { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] - fn as_u16(self) -> u16 { - self as u16 - } -} - /// 2.2.10.20 HTTP_TUNNEL_RESPONSE Structure #[derive(Debug, Default)] pub(crate) struct TunnelRespPkt { @@ -298,26 +266,26 @@ impl Decode<'_> for TunnelRespPkt { ..TunnelRespPkt::default() }; - if pkt.fields_present & (HttpTunnelResponseFields::TunnelID.as_u16()) != 0 { + if pkt.fields_present & (HttpTunnelResponseFields::TunnelID as u16) != 0 { ensure_size!(in: src, size: 4); pkt.tunnel_id = Some(src.read_u32()); } - if pkt.fields_present & (HttpTunnelResponseFields::Caps.as_u16()) != 0 { + if pkt.fields_present & (HttpTunnelResponseFields::Caps as u16) != 0 { ensure_size!(in: src, size: 4); pkt.caps_flags = Some(src.read_u32()); } - if pkt.fields_present & (HttpTunnelResponseFields::Soh.as_u16()) != 0 { + if pkt.fields_present & (HttpTunnelResponseFields::Soh as u16) != 0 { ensure_size!(in: src, size: 2 + 2); pkt.nonce = Some(src.read_u16()); - let len = usize::from(src.read_u16()); - ensure_size!(in: src, size: len); - pkt.server_cert = src.read_slice(len).to_vec(); + let len = src.read_u16(); + ensure_size!(in: src, size: len as usize); + pkt.server_cert = src.read_slice(len as usize).to_vec(); } - if pkt.fields_present & (HttpTunnelResponseFields::Consent.as_u16()) != 0 { + if pkt.fields_present & (HttpTunnelResponseFields::Consent as u16) != 0 { ensure_size!(in: src, size: 2); - let len = usize::from(src.read_u16()); - ensure_size!(in: src, size: len); - pkt.consent_msg = src.read_slice(len).to_vec(); + let len = src.read_u16(); + ensure_size!(in: src, size: len as usize); + pkt.consent_msg = src.read_slice(len as usize).to_vec(); } Ok(pkt) @@ -362,12 +330,12 @@ impl Decode<'_> for ExtendedAuthPkt { fn decode(src: &mut ReadCursor<'_>) -> ironrdp_core::DecodeResult { ensure_size!(in: src, size: 4 + 2); let error_code = src.read_u32(); - let len = usize::from(src.read_u16()); - ensure_size!(in: src, size: len); + let len = src.read_u16(); + ensure_size!(in: src, size: len as usize); Ok(ExtendedAuthPkt { error_code, - blob: src.read_slice(len).to_vec(), + blob: src.read_slice(len as usize).to_vec(), }) } } @@ -416,17 +384,13 @@ impl Encode for TunnelAuthPkt { /// 2.2.10.16 HTTP_TUNNEL_AUTH_RESPONSE Structure #[derive(Debug)] pub(crate) struct TunnelAuthRespPkt { - error_code: u32, + pub error_code: u32, _fields_present: u16, _reserved: u16, } impl TunnelAuthRespPkt { const FIXED_PART_SIZE: usize = 4 /* error_code */ + 2 /* fields_present */ + 2 /* _reserved */; - - pub(crate) fn error_code(&self) -> u32 { - self.error_code - } } impl Decode<'_> for TunnelAuthRespPkt { @@ -491,7 +455,7 @@ impl Encode for ChannelPkt { /// 2.2.10.4 HTTP_CHANNEL_RESPONSE #[derive(Default, Debug)] pub(crate) struct ChannelResp { - error_code: u32, + pub error_code: u32, fields_present: u16, _reserved: u16, @@ -503,10 +467,6 @@ pub(crate) struct ChannelResp { impl ChannelResp { const FIXED_PART_SIZE: usize = 4 /* error_code */ + 2 /* fields_present */ + 2 /* _reserved */; - - pub(crate) fn error_code(&self) -> u32 { - self.error_code - } } impl Decode<'_> for ChannelResp { @@ -529,9 +489,9 @@ impl Decode<'_> for ChannelResp { } if resp.fields_present & 4 != 0 { ensure_size!(in: src, size: 2); - let len = usize::from(src.read_u16()); - ensure_size!(in: src, size: len); - resp.authn_cookie = src.read_slice(len).to_vec(); + let len = src.read_u16(); + ensure_size!(in: src, size: len as usize); + resp.authn_cookie = src.read_slice(len as usize).to_vec(); } Ok(resp) } @@ -570,10 +530,10 @@ impl Encode for DataPkt<'_> { impl<'a> Decode<'a> for DataPkt<'a> { fn decode(src: &mut ReadCursor<'a>) -> ironrdp_core::DecodeResult { ensure_size!(in: src, size: 2); - let len = usize::from(src.read_u16()); - ensure_size!(in: src, size: len); + let len = src.read_u16(); + ensure_size!(in: src, size: len as usize); Ok(DataPkt { - data: src.read_slice(len), + data: src.read_slice(len as usize), }) } } diff --git a/crates/ironrdp-pdu/Cargo.toml b/crates/ironrdp-pdu/Cargo.toml index cbe31ad8..ff8a9d94 100644 --- a/crates/ironrdp-pdu/Cargo.toml +++ b/crates/ironrdp-pdu/Cargo.toml @@ -44,6 +44,7 @@ pkcs1 = "0.7" [dev-dependencies] expect-test.workspace = true +lazy_static.workspace = true # TODO: remove in favor of https://doc.rust-lang.org/std/sync/struct.OnceLock.html [lints] workspace = true diff --git a/crates/ironrdp-pdu/src/basic_output/mod.rs b/crates/ironrdp-pdu/src/basic_output.rs similarity index 100% rename from crates/ironrdp-pdu/src/basic_output/mod.rs rename to crates/ironrdp-pdu/src/basic_output.rs diff --git a/crates/ironrdp-pdu/src/basic_output/bitmap/mod.rs b/crates/ironrdp-pdu/src/basic_output/bitmap.rs similarity index 87% rename from crates/ironrdp-pdu/src/basic_output/bitmap/mod.rs rename to crates/ironrdp-pdu/src/basic_output/bitmap.rs index f1bd153a..52b5163a 100644 --- a/crates/ironrdp-pdu/src/basic_output/bitmap/mod.rs +++ b/crates/ironrdp-pdu/src/basic_output/bitmap.rs @@ -7,8 +7,8 @@ use core::fmt::{self, Debug}; use bitflags::bitflags; use ironrdp_core::{ - cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, - ReadCursor, WriteCursor, + ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, + WriteCursor, }; use crate::geometry::InclusiveRectangle; @@ -41,9 +41,11 @@ impl Encode for BitmapUpdateData<'_> { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_size!(in: dst, size: self.size()); - let rectangle_count = cast_length!("number of rectangles", self.rectangles.len())?; + if self.rectangles.len() > u16::MAX as usize { + return Err(invalid_field_err!("numberRectangles", "rectangle count is too big")); + } - Self::encode_header(rectangle_count, dst)?; + Self::encode_header(self.rectangles.len() as u16, dst)?; for bitmap_data in self.rectangles.iter() { bitmap_data.encode(dst)?; @@ -72,10 +74,10 @@ impl<'de> Decode<'de> for BitmapUpdateData<'de> { return Err(invalid_field_err!("updateType", "invalid update type")); } - let rectangle_count = usize::from(src.read_u16()); - let mut rectangles = Vec::with_capacity(rectangle_count); + let rectangles_number = src.read_u16() as usize; + let mut rectangles = Vec::with_capacity(rectangles_number); - for _ in 0..rectangle_count { + for _ in 0..rectangles_number { rectangles.push(BitmapData::decode(src)?); } @@ -109,14 +111,16 @@ impl Encode for BitmapData<'_> { ensure_size!(in: dst, size: self.size()); let encoded_bitmap_data_length = self.encoded_bitmap_data_length(); - let encoded_bitmap_data_length = cast_length!("bitmap data length", encoded_bitmap_data_length)?; + if encoded_bitmap_data_length > u16::MAX as usize { + return Err(invalid_field_err!("bitmapLength", "bitmap data length is too big")); + } self.rectangle.encode(dst)?; dst.write_u16(self.width); dst.write_u16(self.height); dst.write_u16(self.bits_per_pixel); dst.write_u16(self.compression_flags.bits()); - dst.write_u16(encoded_bitmap_data_length); + dst.write_u16(encoded_bitmap_data_length as u16); if let Some(compressed_data_header) = &self.compressed_data_header { compressed_data_header.encode(dst)?; }; @@ -146,25 +150,25 @@ impl<'de> Decode<'de> for BitmapData<'de> { // A 16-bit, unsigned integer. The size in bytes of the data in the bitmapComprHdr // and bitmapDataStream fields. - let encoded_bitmap_data_length = usize::from(src.read_u16()); + let encoded_bitmap_data_length = src.read_u16(); - ensure_size!(in: src, size: encoded_bitmap_data_length); + ensure_size!(in: src, size: encoded_bitmap_data_length as usize); let (compressed_data_header, buffer_length) = if compression_flags.contains(Compression::BITMAP_COMPRESSION) && !compression_flags.contains(Compression::NO_BITMAP_COMPRESSION_HDR) { // Check if encoded_bitmap_data_length is at least CompressedDataHeader::ENCODED_SIZE - if encoded_bitmap_data_length < CompressedDataHeader::ENCODED_SIZE { + if encoded_bitmap_data_length < CompressedDataHeader::ENCODED_SIZE as u16 { return Err(invalid_field_err!( "cbCompEncodedBitmapDataLength", "length is less than CompressedDataHeader::ENCODED_SIZE" )); } - let buffer_length = encoded_bitmap_data_length - CompressedDataHeader::ENCODED_SIZE; + let buffer_length = encoded_bitmap_data_length as usize - CompressedDataHeader::ENCODED_SIZE; (Some(CompressedDataHeader::decode(src)?), buffer_length) } else { - (None, encoded_bitmap_data_length) + (None, encoded_bitmap_data_length as usize) }; let bitmap_data = src.read_slice(buffer_length); diff --git a/crates/ironrdp-pdu/src/basic_output/bitmap/rdp6.rs b/crates/ironrdp-pdu/src/basic_output/bitmap/rdp6.rs index bcc1c2e0..dc8b5a54 100644 --- a/crates/ironrdp-pdu/src/basic_output/bitmap/rdp6.rs +++ b/crates/ironrdp-pdu/src/basic_output/bitmap/rdp6.rs @@ -56,7 +56,7 @@ impl Encode for BitmapStreamHeader { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_size!(in: dst, size: self.size()); - let mut header = (u8::from(self.enable_rle_compression) << 4) | (u8::from(!self.use_alpha) << 5); + let mut header = ((self.enable_rle_compression as u8) << 4) | ((!self.use_alpha as u8) << 5); match self.color_plane_definition { ColorPlaneDefinition::Argb => { @@ -68,7 +68,7 @@ impl Encode for BitmapStreamHeader { .. } => { // Add cll and cs flags to header - header |= (color_loss_level & 0x07) | (u8::from(use_chroma_subsampling) << 3); + header |= (color_loss_level & 0x07) | ((use_chroma_subsampling as u8) << 3); } } diff --git a/crates/ironrdp-pdu/src/basic_output/bitmap/tests.rs b/crates/ironrdp-pdu/src/basic_output/bitmap/tests.rs index db490f4b..5adfa030 100644 --- a/crates/ironrdp-pdu/src/basic_output/bitmap/tests.rs +++ b/crates/ironrdp-pdu/src/basic_output/bitmap/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode}; +use lazy_static::lazy_static; use super::*; @@ -32,29 +31,31 @@ const BITMAP_BUFFER: [u8; 114] = [ 0x55, 0xad, 0x10, 0x10, 0xa8, 0xd8, 0x60, 0x12, ]; -static BITMAP: LazyLock> = LazyLock::new(|| BitmapUpdateData { - rectangles: { - let vec = vec![BitmapData { - rectangle: InclusiveRectangle { - left: 1792, - top: 1024, - right: 1855, - bottom: 1079, - }, - width: 64, - height: 56, - bits_per_pixel: 16, - compression_flags: Compression::BITMAP_COMPRESSION, - compressed_data_header: Some(CompressedDataHeader { - main_body_size: 80, - scan_width: 28, - uncompressed_size: 4, - }), - bitmap_data: &BITMAP_BUFFER[30..], - }]; - vec - }, -}); +lazy_static! { + static ref BITMAP: BitmapUpdateData<'static> = BitmapUpdateData { + rectangles: { + let vec = vec![BitmapData { + rectangle: InclusiveRectangle { + left: 1792, + top: 1024, + right: 1855, + bottom: 1079, + }, + width: 64, + height: 56, + bits_per_pixel: 16, + compression_flags: Compression::BITMAP_COMPRESSION, + compressed_data_header: Some(CompressedDataHeader { + main_body_size: 80, + scan_width: 28, + uncompressed_size: 4, + }), + bitmap_data: &BITMAP_BUFFER[30..], + }]; + vec + } + }; +} #[test] fn from_buffer_bitmap_data_parsses_correctly() { diff --git a/crates/ironrdp-pdu/src/basic_output/fast_path/mod.rs b/crates/ironrdp-pdu/src/basic_output/fast_path.rs similarity index 93% rename from crates/ironrdp-pdu/src/basic_output/fast_path/mod.rs rename to crates/ironrdp-pdu/src/basic_output/fast_path.rs index c0c11aac..20a15dc0 100644 --- a/crates/ironrdp-pdu/src/basic_output/fast_path/mod.rs +++ b/crates/ironrdp-pdu/src/basic_output/fast_path.rs @@ -4,8 +4,8 @@ mod tests; use bit_field::BitField as _; use bitflags::bitflags; use ironrdp_core::{ - cast_length, decode_cursor, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeError, - DecodeResult, Encode, EncodeResult, InvalidFieldErr as _, ReadCursor, WriteCursor, + decode_cursor, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeError, DecodeResult, Encode, + EncodeResult, InvalidFieldErr as _, ReadCursor, WriteCursor, }; use num_derive::FromPrimitive; use num_traits::FromPrimitive as _; @@ -19,10 +19,6 @@ use crate::rdp::headers::{CompressionFlags, SHARE_DATA_HEADER_COMPRESSION_MASK}; /// Implements the Fast-Path RDP message header PDU. /// TS_FP_UPDATE_PDU -#[expect( - clippy::partial_pub_fields, - reason = "this structure is used in the match expression in the integration tests" -)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct FastPathHeader { pub flags: EncryptionFlags, @@ -46,7 +42,7 @@ impl FastPathHeader { // it may then be +2 if > 0x7f let len = self.data_length + Self::FIXED_PART_SIZE + 1; - Self::FIXED_PART_SIZE + per::sizeof_length(len) + Self::FIXED_PART_SIZE + per::sizeof_length(len as u16) } } @@ -60,13 +56,15 @@ impl Encode for FastPathHeader { dst.write_u8(header); let length = self.data_length + self.size(); - let length = cast_length!("length", length)?; + if length > u16::MAX as usize { + return Err(invalid_field_err!("length", "fastpath PDU length is too big")); + } if self.forced_long_length { // Preserve same layout for header as received - per::write_long_length(dst, length); + per::write_long_length(dst, length as u16); } else { - per::write_length(dst, length); + per::write_length(dst, length as u16); } Ok(()) @@ -95,15 +93,14 @@ impl<'de> Decode<'de> for FastPathHeader { let (length, sizeof_length) = per::read_length(src).map_err(|e| { DecodeError::invalid_field("", "length", "Invalid encoded fast path PDU length").with_source(e) })?; - let length = usize::from(length); - if length < sizeof_length + Self::FIXED_PART_SIZE { + if (length as usize) < sizeof_length + Self::FIXED_PART_SIZE { return Err(invalid_field_err!( "length", "received fastpath PDU length is smaller than header size" )); } - let data_length = length - sizeof_length - Self::FIXED_PART_SIZE; - // Detect case, when received packet has non-optimal packet length packing. + let data_length = length as usize - sizeof_length - Self::FIXED_PART_SIZE; + // Detect case, when received packet has non-optimal packet length packing let forced_long_length = per::sizeof_length(length) != sizeof_length; Ok(FastPathHeader { @@ -134,7 +131,9 @@ impl Encode for FastPathUpdatePdu<'_> { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_size!(in: dst, size: self.size()); - let data_len = cast_length!("data length", self.data.len())?; + if self.data.len() > u16::MAX as usize { + return Err(invalid_field_err!("data", "fastpath PDU data is too big")); + } let mut header = 0u8; header.set_bits(0..4, self.update_code.as_u8()); @@ -149,7 +148,7 @@ impl Encode for FastPathUpdatePdu<'_> { dst.write_u8(compression_flags_with_type); } - dst.write_u16(data_len); + dst.write_u16(self.data.len() as u16); dst.write_slice(self.data); Ok(()) @@ -201,7 +200,7 @@ impl<'de> Decode<'de> for FastPathUpdatePdu<'de> { (None, None) }; - let data_length = usize::from(src.read_u16()); + let data_length = src.read_u16() as usize; ensure_size!(in: src, size: data_length); let data = src.read_slice(data_length); diff --git a/crates/ironrdp-pdu/src/basic_output/fast_path/tests.rs b/crates/ironrdp-pdu/src/basic_output/fast_path/tests.rs index 04c84d2d..5885aa2d 100644 --- a/crates/ironrdp-pdu/src/basic_output/fast_path/tests.rs +++ b/crates/ironrdp-pdu/src/basic_output/fast_path/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode}; +use lazy_static::lazy_static; use super::*; @@ -30,13 +29,15 @@ const FAST_PATH_HEADER_WITH_FORCED_LONG_LEN_PDU: FastPathHeader = FastPathHeader forced_long_length: true, }; -static FAST_PATH_UPDATE_PDU: LazyLock> = LazyLock::new(|| FastPathUpdatePdu { - fragmentation: Fragmentation::Single, - update_code: UpdateCode::SurfaceCommands, - compression_flags: None, - compression_type: None, - data: &FAST_PATH_UPDATE_PDU_BUFFER[3..], -}); +lazy_static! { + static ref FAST_PATH_UPDATE_PDU: FastPathUpdatePdu<'static> = FastPathUpdatePdu { + fragmentation: Fragmentation::Single, + update_code: UpdateCode::SurfaceCommands, + compression_flags: None, + compression_type: None, + data: &FAST_PATH_UPDATE_PDU_BUFFER[3..], + }; +} #[test] fn from_buffer_correctly_parses_fast_path_header_with_short_length() { diff --git a/crates/ironrdp-pdu/src/basic_output/pointer/mod.rs b/crates/ironrdp-pdu/src/basic_output/pointer.rs similarity index 87% rename from crates/ironrdp-pdu/src/basic_output/pointer/mod.rs rename to crates/ironrdp-pdu/src/basic_output/pointer.rs index 04bd62c6..285a4243 100644 --- a/crates/ironrdp-pdu/src/basic_output/pointer/mod.rs +++ b/crates/ironrdp-pdu/src/basic_output/pointer.rs @@ -1,6 +1,6 @@ use ironrdp_core::{ - cast_int, cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, - EncodeResult, ReadCursor, WriteCursor, + ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, + WriteCursor, }; // Represents `TS_POINT16` described in [MS-RDPBCGR] 2.2.9.1.1.4.1 @@ -69,24 +69,21 @@ macro_rules! check_masks_alignment { ($and_mask:expr, $xor_mask:expr, $pointer_height:expr, $large_ptr:expr) => {{ const AND_MASK_SIZE_FIELD: &str = "lengthAndMask"; const XOR_MASK_SIZE_FIELD: &str = "lengthXorMask"; - const U32_MAX: usize = 0xFFFFFFFF; - - let pointer_height: usize = cast_int!("pointer height", $pointer_height)?; let check_mask = |mask: &[u8], field: &'static str| { if $pointer_height == 0 { return Err(invalid_field_err!(field, "pointer height cannot be zero")); } - if $large_ptr && (mask.len() > U32_MAX) { + if $large_ptr && (mask.len() > u32::MAX as usize) { return Err(invalid_field_err!(field, "pointer mask is too big for u32 size")); } - if !$large_ptr && (mask.len() > usize::from(u16::MAX)) { + if !$large_ptr && (mask.len() > u16::MAX as usize) { return Err(invalid_field_err!(field, "pointer mask is too big for u16 size")); } - if (mask.len() % pointer_height) != 0 { + if (mask.len() % $pointer_height as usize) != 0 { return Err(invalid_field_err!(field, "pointer mask have incomplete scanlines")); } - if (mask.len() / pointer_height) % 2 != 0 { + if (mask.len() / $pointer_height as usize) % 2 != 0 { return Err(invalid_field_err!( field, "pointer mask scanlines should be aligned to 16 bits" @@ -111,8 +108,8 @@ impl Encode for ColorPointerAttribute<'_> { dst.write_u16(self.width); dst.write_u16(self.height); - dst.write_u16(cast_length!("and mask length", self.and_mask.len())?); - dst.write_u16(cast_length!("xor mask length", self.xor_mask.len())?); + dst.write_u16(self.and_mask.len() as u16); + dst.write_u16(self.xor_mask.len() as u16); // Note that masks are written in reverse order. It is not a mistake, that is how the // message is defined in [MS-RDPBCGR] dst.write_slice(self.xor_mask); @@ -138,15 +135,15 @@ impl<'a> Decode<'a> for ColorPointerAttribute<'a> { let hot_spot = Point16::decode(src)?; let width = src.read_u16(); let height = src.read_u16(); - // Convert to usize during the addition to prevent overflow and match expected type - let length_and_mask = usize::from(src.read_u16()); - let length_xor_mask = usize::from(src.read_u16()); + let length_and_mask = src.read_u16(); + let length_xor_mask = src.read_u16(); - let expected_masks_size = length_and_mask + length_xor_mask; + // Convert to usize during the addition to prevent overflow and match expected type + let expected_masks_size = (length_and_mask as usize) + (length_xor_mask as usize); ensure_size!(in: src, size: expected_masks_size); - let xor_mask = src.read_slice(length_xor_mask); - let and_mask = src.read_slice(length_and_mask); + let xor_mask = src.read_slice(length_xor_mask as usize); + let and_mask = src.read_slice(length_and_mask as usize); check_masks_alignment!(and_mask, xor_mask, height, false)?; @@ -273,8 +270,8 @@ impl Encode for LargePointerAttribute<'_> { dst.write_u16(self.width); dst.write_u16(self.height); - dst.write_u32(cast_length!("and mask length", self.and_mask.len())?); - dst.write_u32(cast_length!("xor mask length", self.xor_mask.len())?); + dst.write_u32(self.and_mask.len() as u32); + dst.write_u32(self.xor_mask.len() as u32); // See comment in `ColorPointerAttribute::encode` about encoding order dst.write_slice(self.xor_mask); dst.write_slice(self.and_mask); @@ -301,8 +298,8 @@ impl<'a> Decode<'a> for LargePointerAttribute<'a> { let width = src.read_u16(); let height = src.read_u16(); // Convert to usize to prevent overflow during addition - let length_and_mask = cast_length!("and mask length", src.read_u32())?; - let length_xor_mask = cast_length!("xor mask length", src.read_u32())?; + let length_and_mask = src.read_u32() as usize; + let length_xor_mask = src.read_u32() as usize; let expected_masks_size = length_and_mask + length_xor_mask; ensure_size!(in: src, size: expected_masks_size); diff --git a/crates/ironrdp-pdu/src/basic_output/surface_commands/mod.rs b/crates/ironrdp-pdu/src/basic_output/surface_commands.rs similarity index 93% rename from crates/ironrdp-pdu/src/basic_output/surface_commands/mod.rs rename to crates/ironrdp-pdu/src/basic_output/surface_commands.rs index 4f9a6bb4..a3de9cfc 100644 --- a/crates/ironrdp-pdu/src/basic_output/surface_commands/mod.rs +++ b/crates/ironrdp-pdu/src/basic_output/surface_commands.rs @@ -3,10 +3,10 @@ mod tests; use bitflags::bitflags; use ironrdp_core::{ - cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, - ReadCursor, WriteCursor, + ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, + WriteCursor, }; -use num_derive::FromPrimitive; +use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::FromPrimitive as _; use crate::geometry::ExclusiveRectangle; @@ -126,7 +126,7 @@ impl Encode for FrameMarkerPdu { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_fixed_part_size!(in: dst); - dst.write_u16(self.frame_action.as_u16()); + dst.write_u16(self.frame_action as u16); dst.write_u32(self.frame_id.unwrap_or(0)); Ok(()) @@ -197,7 +197,9 @@ impl Encode for ExtendedBitmapDataPdu<'_> { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_size!(in: dst, size: self.size()); - let data_len = cast_length!("bitmap data length", self.data.len())?; + if self.data.len() > u32::MAX as usize { + return Err(invalid_field_err!("bitmapDataLength", "bitmap data is too big")); + } dst.write_u8(self.bpp); let flags = if self.header.is_some() { @@ -210,7 +212,7 @@ impl Encode for ExtendedBitmapDataPdu<'_> { dst.write_u8(self.codec_id); dst.write_u16(self.width); dst.write_u16(self.height); - dst.write_u32(data_len); + dst.write_u32(self.data.len() as u32); if let Some(header) = &self.header { header.encode(dst)?; } @@ -238,7 +240,7 @@ impl<'de> Decode<'de> for ExtendedBitmapDataPdu<'de> { let codec_id = src.read_u8(); let width = src.read_u16(); let height = src.read_u16(); - let data_length = cast_length!("bitmap data length", src.read_u32())?; + let data_length = src.read_u32() as usize; let expected_remaining_size = if flags.contains(BitmapDataFlags::COMPRESSED_BITMAP_HEADER_PRESENT) { data_length + BitmapDataHeader::ENCODED_SIZE @@ -350,23 +352,13 @@ impl From<&SurfaceCommand<'_>> for SurfaceCommandType { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)] #[repr(u16)] pub enum FrameAction { Begin = 0x00, End = 0x01, } -impl FrameAction { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] - pub fn as_u16(self) -> u16 { - self as u16 - } -} - bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] struct BitmapDataFlags: u8 { diff --git a/crates/ironrdp-pdu/src/basic_output/surface_commands/tests.rs b/crates/ironrdp-pdu/src/basic_output/surface_commands/tests.rs index db1db71b..fd2e6830 100644 --- a/crates/ironrdp-pdu/src/basic_output/surface_commands/tests.rs +++ b/crates/ironrdp-pdu/src/basic_output/surface_commands/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode}; +use lazy_static::lazy_static; use super::*; @@ -76,8 +75,8 @@ const FRAME_MARKER_PDU: SurfaceCommand<'_> = SurfaceCommand::FrameMarker(FrameMa frame_id: Some(5), }); -static SURFACE_BITS_PDU: LazyLock> = LazyLock::new(|| { - SurfaceCommand::StreamSurfaceBits(SurfaceBitsPdu { +lazy_static! { + static ref SURFACE_BITS_PDU: SurfaceCommand<'static> = SurfaceCommand::StreamSurfaceBits(SurfaceBitsPdu { destination: ExclusiveRectangle { left: 0, top: 0, @@ -92,8 +91,8 @@ static SURFACE_BITS_PDU: LazyLock> = LazyLock::new(|| { header: None, data: &SURFACE_BITS_BUFFER[22..], }, - }) -}); + }); +} #[test] fn from_buffer_correctly_parses_surface_command_frame_marker() { diff --git a/crates/ironrdp-pdu/src/ber.rs b/crates/ironrdp-pdu/src/ber.rs index bda4e0fc..b01b49ab 100644 --- a/crates/ironrdp-pdu/src/ber.rs +++ b/crates/ironrdp-pdu/src/ber.rs @@ -3,25 +3,13 @@ use ironrdp_core::{cast_length, ensure_size, invalid_field_err, ReadCursor, Writ use crate::{DecodeResult, EncodeResult}; #[repr(u8)] -#[derive(Copy, Clone)] pub(crate) enum Pc { Primitive = 0x00, Construct = 0x20, } -impl Pc { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] - fn as_u8(self) -> u8 { - self as u8 - } -} - #[repr(u8)] #[expect(unused)] -#[derive(Copy, Clone)] enum Class { Universal = 0x00, Application = 0x40, @@ -29,19 +17,8 @@ enum Class { Private = 0xC0, } -impl Class { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] - fn as_u8(self) -> u8 { - self as u8 - } -} - #[repr(u8)] #[expect(unused)] -#[derive(Copy, Clone)] enum Tag { Mask = 0x1F, Boolean = 0x01, @@ -53,16 +30,6 @@ enum Tag { Sequence = 0x10, } -impl Tag { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] - fn as_u8(self) -> u8 { - self as u8 - } -} - pub(crate) const SIZEOF_ENUMERATED: usize = 3; pub(crate) const SIZEOF_BOOL: usize = 3; @@ -79,7 +46,7 @@ pub(crate) fn sizeof_sequence_tag(length: u16) -> usize { } pub(crate) fn sizeof_octet_string(length: u16) -> usize { - 1 + sizeof_length(length) + usize::from(length) + 1 + sizeof_length(length) + length as usize } pub(crate) fn sizeof_integer(value: u32) -> usize { @@ -104,7 +71,7 @@ pub(crate) fn read_sequence_tag(stream: &mut ReadCursor<'_>) -> DecodeResult, tagnum: u8, le ensure_size!(in: stream, size: sizeof_application_tag(tagnum, length)); let taglen = if tagnum > 0x1E { - stream.write_u8(Class::Application.as_u8() | Pc::Construct.as_u8() | TAG_MASK); + stream.write_u8(Class::Application as u8 | Pc::Construct as u8 | TAG_MASK); stream.write_u8(tagnum); 2 } else { - stream.write_u8(Class::Application.as_u8() | Pc::Construct.as_u8() | (TAG_MASK & tagnum)); + stream.write_u8(Class::Application as u8 | Pc::Construct as u8 | (TAG_MASK & tagnum)); 1 }; @@ -131,14 +98,14 @@ pub(crate) fn read_application_tag(stream: &mut ReadCursor<'_>, tagnum: u8) -> D let identifier = stream.read_u8(); if tagnum > 0x1E { - if identifier != Class::Application.as_u8() | Pc::Construct.as_u8() | TAG_MASK { + if identifier != Class::Application as u8 | Pc::Construct as u8 | TAG_MASK { return Err(invalid_field_err!("identifier", "invalid application tag identifier")); } ensure_size!(in: stream, size: 1); if stream.read_u8() != tagnum { return Err(invalid_field_err!("tagnum", "invalid application tag identifier")); } - } else if identifier != Class::Application.as_u8() | Pc::Construct.as_u8() | (TAG_MASK & tagnum) { + } else if identifier != Class::Application as u8 | Pc::Construct as u8 | (TAG_MASK & tagnum) { return Err(invalid_field_err!("identifier", "invalid application tag identifier")); } @@ -179,22 +146,20 @@ pub(crate) fn write_integer(stream: &mut WriteCursor<'_>, value: u32) -> EncodeR if value < 0x0000_0080 { write_length(stream, 1)?; ensure_size!(in: stream, size: 1); - stream.write_u8(u8::try_from(value).expect("value is guaranteed to fit into u8 due to the prior check")); + stream.write_u8(value as u8); Ok(3) } else if value < 0x0000_8000 { write_length(stream, 2)?; ensure_size!(in: stream, size: 2); - stream.write_u16_be(u16::try_from(value).expect("value is guaranteed to fit into u16 due to the prior check")); + stream.write_u16_be(value as u16); Ok(4) } else if value < 0x0080_0000 { write_length(stream, 3)?; ensure_size!(in: stream, size: 3); - stream.write_u8(u8::try_from(value >> 16).expect("value is guaranteed to fit into u8 due to the prior check")); - stream.write_u16_be( - u16::try_from(value & 0xFFFF).expect("masking with 0xFFFF ensures that the value fits into u16"), - ); + stream.write_u8((value >> 16) as u8); + stream.write_u16_be((value & 0xFFFF) as u16); Ok(5) } else { @@ -286,7 +251,7 @@ pub(crate) fn read_octet_string_tag(stream: &mut ReadCursor<'_>) -> DecodeResult fn write_universal_tag(stream: &mut WriteCursor<'_>, tag: Tag, pc: Pc) -> EncodeResult { ensure_size!(in: stream, size: 1); - let identifier = Class::Universal.as_u8() | pc.as_u8() | (TAG_MASK & tag.as_u8()); + let identifier = Class::Universal as u8 | pc as u8 | (TAG_MASK & tag as u8); stream.write_u8(identifier); Ok(1) @@ -297,7 +262,7 @@ fn read_universal_tag(stream: &mut ReadCursor<'_>, tag: Tag, pc: Pc) -> DecodeRe let identifier = stream.read_u8(); - if identifier != Class::Universal.as_u8() | pc.as_u8() | (TAG_MASK & tag.as_u8()) { + if identifier != Class::Universal as u8 | pc as u8 | (TAG_MASK & tag as u8) { Err(invalid_field_err!("identifier", "invalid universal tag identifier")) } else { Ok(()) @@ -314,11 +279,11 @@ fn write_length(stream: &mut WriteCursor<'_>, length: u16) -> EncodeResult 0x7F { stream.write_u8(0x80 ^ 0x1); - stream.write_u8(u8::try_from(length).expect("length is guaranteed to fit into u8 due to the prior check")); + stream.write_u8(length as u8); Ok(2) } else { - stream.write_u8(u8::try_from(length).expect("length is guaranteed to fit into u8 due to the prior check")); + stream.write_u8(length as u8); Ok(1) } diff --git a/crates/ironrdp-pdu/src/codecs/mod.rs b/crates/ironrdp-pdu/src/codecs.rs similarity index 100% rename from crates/ironrdp-pdu/src/codecs/mod.rs rename to crates/ironrdp-pdu/src/codecs.rs diff --git a/crates/ironrdp-pdu/src/codecs/rfx/mod.rs b/crates/ironrdp-pdu/src/codecs/rfx.rs similarity index 99% rename from crates/ironrdp-pdu/src/codecs/rfx/mod.rs rename to crates/ironrdp-pdu/src/codecs/rfx.rs index 992cdbf3..2d9a2f02 100644 --- a/crates/ironrdp-pdu/src/codecs/rfx/mod.rs +++ b/crates/ironrdp-pdu/src/codecs/rfx.rs @@ -208,7 +208,7 @@ impl<'de> Decode<'de> for BlockHeader { let ty = src.read_u16(); let ty = BlockType::from_u16(ty).ok_or_else(|| invalid_field_err!("blockType", "Invalid block type"))?; - let data_length: usize = cast_length!("block length", src.read_u32())?; + let data_length = src.read_u32() as usize; data_length .checked_sub(Self::FIXED_PART_SIZE) .ok_or_else(|| invalid_field_err!("blockLen", "Invalid block length"))?; diff --git a/crates/ironrdp-pdu/src/codecs/rfx/data_messages.rs b/crates/ironrdp-pdu/src/codecs/rfx/data_messages.rs index d7da57b2..d85d9cdd 100644 --- a/crates/ironrdp-pdu/src/codecs/rfx/data_messages.rs +++ b/crates/ironrdp-pdu/src/codecs/rfx/data_messages.rs @@ -304,7 +304,7 @@ impl Encode for TileSetPdu<'_> { dst.write_u16(properties); dst.write_u8(cast_length!("numQuant", self.quants.len())?); - dst.write_u8(u8::try_from(TILE_SIZE).expect("TILE_SIZE value fits into u8")); + dst.write_u8(TILE_SIZE as u8); dst.write_u16(cast_length!("numTiles", self.tiles.len())?); let tiles_data_size = self.tiles.iter().map(|t| Block::Tile(t.clone()).size()).sum::(); @@ -384,7 +384,7 @@ impl<'de> Decode<'de> for TileSetPdu<'de> { } let number_of_tiles = usize::from(src.read_u16()); - let _tiles_data_size = src.read_u32(); + let _tiles_data_size = src.read_u32() as usize; let quants = iter::repeat_with(|| Quant::decode(src)) .take(number_of_quants) @@ -544,32 +544,24 @@ impl Encode for Quant { impl<'de> Decode<'de> for Quant { fn decode(src: &mut ReadCursor<'de>) -> DecodeResult { - #![allow( - clippy::similar_names, - reason = "it’s hard to do better than ll3, lh3, etc without going overly verbose" - )] - + #![allow(clippy::similar_names)] // It’s hard to do better than ll3, lh3, etc without going overly verbose. ensure_fixed_part_size!(in: src); - let ll3lh3 = src.read_u8(); - let ll3 = ll3lh3.get_bits(0..4); - let lh3 = ll3lh3.get_bits(4..8); + let level3 = src.read_u16(); + let ll3 = level3.get_bits(0..4) as u8; + let lh3 = level3.get_bits(4..8) as u8; + let hl3 = level3.get_bits(8..12) as u8; + let hh3 = level3.get_bits(12..16) as u8; - let hl3hh3 = src.read_u8(); - let hl3 = hl3hh3.get_bits(0..4); - let hh3 = hl3hh3.get_bits(4..8); + let level2_with_lh1 = src.read_u16(); + let lh2 = level2_with_lh1.get_bits(0..4) as u8; + let hl2 = level2_with_lh1.get_bits(4..8) as u8; + let hh2 = level2_with_lh1.get_bits(8..12) as u8; + let lh1 = level2_with_lh1.get_bits(12..16) as u8; - let lh2hl2 = src.read_u8(); - let lh2 = lh2hl2.get_bits(0..4); - let hl2 = lh2hl2.get_bits(4..8); - - let hh2lh1 = src.read_u8(); - let hh2 = hh2lh1.get_bits(0..4); - let lh1 = hh2lh1.get_bits(4..8); - - let hl1hh1 = src.read_u8(); - let hl1 = hl1hh1.get_bits(0..4); - let hh1 = hl1hh1.get_bits(4..8); + let level1 = src.read_u8(); + let hl1 = level1.get_bits(0..4); + let hh1 = level1.get_bits(4..8); Ok(Self { ll3, diff --git a/crates/ironrdp-pdu/src/crypto/mod.rs b/crates/ironrdp-pdu/src/crypto.rs similarity index 100% rename from crates/ironrdp-pdu/src/crypto/mod.rs rename to crates/ironrdp-pdu/src/crypto.rs diff --git a/crates/ironrdp-pdu/src/crypto/rc4.rs b/crates/ironrdp-pdu/src/crypto/rc4.rs index abcafcf0..3123e197 100644 --- a/crates/ironrdp-pdu/src/crypto/rc4.rs +++ b/crates/ironrdp-pdu/src/crypto/rc4.rs @@ -11,12 +11,12 @@ impl Rc4 { pub(crate) fn new(key: &[u8]) -> Self { // key scheduling let mut state = State::default(); - for (i, item) in (0..=255).zip(state.iter_mut()) { - *item = i; + for (i, item) in state.iter_mut().enumerate().take(256) { + *item = i as u8; } let mut j = 0usize; for i in 0..256 { - j = (j + usize::from(state[i]) + usize::from(key[i % key.len()])) % 256; + j = (j + state[i] as usize + key[i % key.len()] as usize) % 256; state.swap(i, j); } @@ -28,9 +28,9 @@ impl Rc4 { let mut output = Vec::with_capacity(message.len()); while output.capacity() > output.len() { self.i = (self.i + 1) % 256; - self.j = (self.j + usize::from(self.state[self.i])) % 256; + self.j = (self.j + self.state[self.i] as usize) % 256; self.state.swap(self.i, self.j); - let idx_k = (usize::from(self.state[self.i]) + usize::from(self.state[self.j])) % 256; + let idx_k = (self.state[self.i] as usize + self.state[self.j] as usize) % 256; let k = self.state[idx_k]; let idx_msg = output.len(); output.push(k ^ message[idx_msg]); diff --git a/crates/ironrdp-pdu/src/gcc/mod.rs b/crates/ironrdp-pdu/src/gcc.rs similarity index 100% rename from crates/ironrdp-pdu/src/gcc/mod.rs rename to crates/ironrdp-pdu/src/gcc.rs diff --git a/crates/ironrdp-pdu/src/gcc/cluster_data.rs b/crates/ironrdp-pdu/src/gcc/cluster_data.rs index 56753a12..bda5357d 100644 --- a/crates/ironrdp-pdu/src/gcc/cluster_data.rs +++ b/crates/ironrdp-pdu/src/gcc/cluster_data.rs @@ -56,8 +56,9 @@ impl<'de> Decode<'de> for ClientClusterData { let flags = RedirectionFlags::from_bits(flags_with_version & !REDIRECTION_VERSION_MASK) .ok_or_else(|| invalid_field_err!("flags", "invalid redirection flags"))?; - let redirection_version = RedirectionVersion::from_u32((flags_with_version & REDIRECTION_VERSION_MASK) >> 2) - .ok_or_else(|| invalid_field_err!("redirVersion", "invalid redirection version"))?; + let redirection_version = + RedirectionVersion::from_u8(((flags_with_version & REDIRECTION_VERSION_MASK) >> 2) as u8) + .ok_or_else(|| invalid_field_err!("redirVersion", "invalid redirection version"))?; Ok(Self { flags, diff --git a/crates/ironrdp-pdu/src/gcc/conference_create.rs b/crates/ironrdp-pdu/src/gcc/conference_create.rs index 4d3cce3c..9c5e3ee4 100644 --- a/crates/ironrdp-pdu/src/gcc/conference_create.rs +++ b/crates/ironrdp-pdu/src/gcc/conference_create.rs @@ -114,9 +114,9 @@ impl Encode for ConferenceCreateRequest { per::CHOICE_SIZE + CONFERENCE_REQUEST_OBJECT_ID.len() - + per::sizeof_length(usize::from(req_length)) + + per::sizeof_length(req_length) + CONFERENCE_REQUEST_CONNECT_PDU_SIZE - + per::sizeof_length(usize::from(length)) + + per::sizeof_length(length) + gcc_blocks_buffer_length } } @@ -286,9 +286,9 @@ impl Encode for ConferenceCreateResponse { per::CHOICE_SIZE + CONFERENCE_REQUEST_OBJECT_ID.len() - + per::sizeof_length(usize::from(req_length)) + + per::sizeof_length(req_length) + CONFERENCE_RESPONSE_CONNECT_PDU_SIZE - + per::sizeof_length(usize::from(length)) + + per::sizeof_length(length) + gcc_blocks_buffer_length } } diff --git a/crates/ironrdp-pdu/src/gcc/core_data/mod.rs b/crates/ironrdp-pdu/src/gcc/core_data.rs similarity index 100% rename from crates/ironrdp-pdu/src/gcc/core_data/mod.rs rename to crates/ironrdp-pdu/src/gcc/core_data.rs diff --git a/crates/ironrdp-pdu/src/gcc/monitor_data.rs b/crates/ironrdp-pdu/src/gcc/monitor_data.rs index 643d3421..f6cb021b 100644 --- a/crates/ironrdp-pdu/src/gcc/monitor_data.rs +++ b/crates/ironrdp-pdu/src/gcc/monitor_data.rs @@ -49,13 +49,13 @@ impl<'de> Decode<'de> for ClientMonitorData { ensure_fixed_part_size!(in: src); let _flags = src.read_u32(); // is unused - let monitor_count = cast_length!("number of monitors", src.read_u32())?; + let monitor_count = src.read_u32(); - if monitor_count > MONITOR_COUNT_MAX { + if monitor_count > MONITOR_COUNT_MAX as u32 { return Err(invalid_field_err!("nMonitors", "too many monitors")); } - let mut monitors = Vec::with_capacity(monitor_count); + let mut monitors = Vec::with_capacity(monitor_count as usize); for _ in 0..monitor_count { monitors.push(Monitor::decode(src)?); } diff --git a/crates/ironrdp-pdu/src/gcc/monitor_extended_data.rs b/crates/ironrdp-pdu/src/gcc/monitor_extended_data.rs index 334c327c..f7fc7f9e 100644 --- a/crates/ironrdp-pdu/src/gcc/monitor_extended_data.rs +++ b/crates/ironrdp-pdu/src/gcc/monitor_extended_data.rs @@ -95,7 +95,7 @@ impl Encode for ExtendedMonitorInfo { dst.write_u32(self.physical_width); dst.write_u32(self.physical_height); - dst.write_u32(u32::from(self.orientation.as_u16())); + dst.write_u32(self.orientation.as_u32()); dst.write_u32(self.desktop_scale_factor); dst.write_u32(self.device_scale_factor); @@ -132,7 +132,7 @@ impl<'de> Decode<'de> for ExtendedMonitorInfo { } } -#[repr(u16)] +#[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive)] pub enum MonitorOrientation { Landscape = 0, @@ -146,7 +146,7 @@ impl MonitorOrientation { clippy::as_conversions, reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" )] - pub fn as_u16(self) -> u16 { - self as u16 + fn as_u32(self) -> u32 { + self as u32 } } diff --git a/crates/ironrdp-pdu/src/gcc/network_data.rs b/crates/ironrdp-pdu/src/gcc/network_data.rs index 2ea457e1..33b6d387 100644 --- a/crates/ironrdp-pdu/src/gcc/network_data.rs +++ b/crates/ironrdp-pdu/src/gcc/network_data.rs @@ -25,8 +25,6 @@ const SERVER_CHANNEL_SIZE: usize = 2; /// is using all the code values from 0 to 255, as such any u8 value is a valid ANSI character. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ChannelName { - /// INVARIANT: A null-terminated 8-byte array. - /// INVARIANT: Contains at most seven ANSI characters. inner: Cow<'static, [u8; Self::SIZE]>, } @@ -81,16 +79,14 @@ impl ChannelName { self.inner.as_ref() } + /// Get a &str if this channel name is a valid ASCII string. pub fn as_str(&self) -> Option<&str> { if self.inner.iter().all(u8::is_ascii) { - #[expect(clippy::missing_panics_doc, reason = "never panics per invariant on self.inner")] let terminator_idx = self .inner .iter() .position(|c| *c == 0) .expect("null-terminated ASCII string"); - - #[expect(clippy::missing_panics_doc, reason = "never panics per invariant on self.inner")] Some(str::from_utf8(&self.inner[..terminator_idx]).expect("ASCII characters")) } else { None diff --git a/crates/ironrdp-pdu/src/input/fast_path.rs b/crates/ironrdp-pdu/src/input/fast_path.rs index abbe7816..0f4e7d1b 100644 --- a/crates/ironrdp-pdu/src/input/fast_path.rs +++ b/crates/ironrdp-pdu/src/input/fast_path.rs @@ -51,7 +51,9 @@ impl Encode for FastPathInputHeader { fn size(&self) -> usize { let num_events_length = if self.num_events < 16 { 0 } else { 1 }; - Self::FIXED_PART_SIZE + per::sizeof_length(self.data_length + num_events_length + 1) + num_events_length + Self::FIXED_PART_SIZE + + per::sizeof_length(self.data_length as u16 + num_events_length as u16 + 1) + + num_events_length } } @@ -76,7 +78,7 @@ impl<'de> Decode<'de> for FastPathInputHeader { 0 }; - let data_length = usize::from(length) - sizeof_length - 1 - num_events_length; + let data_length = length as usize - sizeof_length - 1 - num_events_length; Ok(FastPathInputHeader { flags, @@ -108,7 +110,7 @@ impl FastpathInputEventType { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum FastPathInputEvent { KeyboardEvent(KeyboardFlags, u8), UnicodeKeyboardEvent(KeyboardFlags, u16), @@ -253,31 +255,10 @@ bitflags! { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct FastPathInput( - /// INVARIANT: (1..=255).contains(len()) = at least one, and at most 255 elements. - Vec, -); +pub struct FastPathInput(pub Vec); impl FastPathInput { const NAME: &'static str = "FastPathInput"; - - pub fn new(input_events: Vec) -> DecodeResult { - // Ensure the invariant on `input_events.len()` is respected. - if !(1..=255usize).contains(&input_events.len()) { - return Err(invalid_field_err!("nEvents", "invalid number of input events")); - } - - Ok(Self(input_events)) - } - - pub fn single(input_event: FastPathInputEvent) -> Self { - // A single element upholds the invariant. - Self(vec![input_event]) - } - - pub fn input_events(&self) -> &[FastPathInputEvent] { - &self.0 - } } impl Encode for FastPathInput { @@ -290,7 +271,7 @@ impl Encode for FastPathInput { let data_length = self.0.iter().map(Encode::size).sum::(); let header = FastPathInputHeader { - num_events: u8::try_from(self.0.len()).expect("per invariant (1..=255).contains(num_events.len())"), + num_events: self.0.len() as u8, flags: EncryptionFlags::empty(), data_length, }; @@ -310,8 +291,7 @@ impl Encode for FastPathInput { fn size(&self) -> usize { let data_length = self.0.iter().map(Encode::size).sum::(); let header = FastPathInputHeader { - num_events: u8::try_from(self.0.len()) - .expect("INVARIANT: num_events is within the range of 1 to 255, inclusive"), + num_events: self.0.len() as u8, flags: EncryptionFlags::empty(), data_length, }; @@ -326,6 +306,6 @@ impl<'de> Decode<'de> for FastPathInput { .take(usize::from(header.num_events)) .collect::, _>>()?; - Self::new(events) + Ok(Self(events)) } } diff --git a/crates/ironrdp-pdu/src/input/mod.rs b/crates/ironrdp-pdu/src/input/mod.rs index a85b5195..0cdafdd6 100644 --- a/crates/ironrdp-pdu/src/input/mod.rs +++ b/crates/ironrdp-pdu/src/input/mod.rs @@ -1,8 +1,8 @@ use std::io; use ironrdp_core::{ - cast_length, ensure_fixed_part_size, ensure_size, invalid_field_err, read_padding, write_padding, Decode, - DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor, + ensure_fixed_part_size, ensure_size, invalid_field_err, read_padding, write_padding, Decode, DecodeResult, Encode, + EncodeResult, ReadCursor, WriteCursor, }; use num_derive::FromPrimitive; use num_traits::FromPrimitive as _; @@ -38,7 +38,7 @@ impl Encode for InputEventPdu { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_size!(in: dst, size: self.size()); - dst.write_u16(cast_length!("input events count", self.0.len())?); + dst.write_u16(self.0.len() as u16); write_padding!(dst, 2); for event in self.0.iter() { diff --git a/crates/ironrdp-pdu/src/input/mouse.rs b/crates/ironrdp-pdu/src/input/mouse.rs index 3125739e..6f8fc159 100644 --- a/crates/ironrdp-pdu/src/input/mouse.rs +++ b/crates/ironrdp-pdu/src/input/mouse.rs @@ -1,7 +1,7 @@ use bitflags::bitflags; use ironrdp_core::{ensure_fixed_part_size, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor}; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct MousePdu { pub flags: PointerFlags, pub number_of_wheel_rotation_units: i16, @@ -25,14 +25,7 @@ impl Encode for MousePdu { PointerFlags::empty().bits() }; - #[expect( - clippy::as_conversions, - clippy::cast_sign_loss, - clippy::cast_possible_truncation, - reason = "truncation intended" - )] - let truncated_wheel_rotation_units = self.number_of_wheel_rotation_units as u8; - let wheel_rotations_bits = u16::from(truncated_wheel_rotation_units); + let wheel_rotations_bits = u16::from(self.number_of_wheel_rotation_units as u8); // truncate let flags = self.flags.bits() | wheel_negative_bit | wheel_rotations_bits; @@ -60,12 +53,7 @@ impl<'de> Decode<'de> for MousePdu { let flags = PointerFlags::from_bits_truncate(flags_raw); - #[expect( - clippy::as_conversions, - clippy::cast_possible_truncation, - reason = "truncation intended" - )] - let wheel_rotations_bits = flags_raw as u8; + let wheel_rotations_bits = flags_raw as u8; // truncate let number_of_wheel_rotation_units = if flags.contains(PointerFlags::WHEEL_NEGATIVE) { -i16::from(wheel_rotations_bits) diff --git a/crates/ironrdp-pdu/src/input/mouse_rel.rs b/crates/ironrdp-pdu/src/input/mouse_rel.rs index a1812519..47f1068d 100644 --- a/crates/ironrdp-pdu/src/input/mouse_rel.rs +++ b/crates/ironrdp-pdu/src/input/mouse_rel.rs @@ -1,7 +1,7 @@ use bitflags::bitflags; use ironrdp_core::{ensure_fixed_part_size, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor}; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct MouseRelPdu { pub flags: PointerRelFlags, pub x_delta: i16, diff --git a/crates/ironrdp-pdu/src/input/mouse_x.rs b/crates/ironrdp-pdu/src/input/mouse_x.rs index 500e97c7..10937cf8 100644 --- a/crates/ironrdp-pdu/src/input/mouse_x.rs +++ b/crates/ironrdp-pdu/src/input/mouse_x.rs @@ -1,7 +1,7 @@ use bitflags::bitflags; use ironrdp_core::{ensure_fixed_part_size, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor}; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct MouseXPdu { pub flags: PointerXFlags, pub x_position: u16, diff --git a/crates/ironrdp-pdu/src/lib.rs b/crates/ironrdp-pdu/src/lib.rs index 6d2a387d..c6e2dadc 100644 --- a/crates/ironrdp-pdu/src/lib.rs +++ b/crates/ironrdp-pdu/src/lib.rs @@ -1,6 +1,10 @@ #![cfg_attr(doc, doc = include_str!("../README.md"))] #![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")] #![allow(clippy::arithmetic_side_effects)] // FIXME: remove +#![allow(clippy::cast_lossless)] // FIXME: remove +#![allow(clippy::cast_possible_truncation)] // FIXME: remove +#![allow(clippy::cast_possible_wrap)] // FIXME: remove +#![allow(clippy::cast_sign_loss)] // FIXME: remove use core::fmt; @@ -100,10 +104,6 @@ impl Action { } } - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] pub fn as_u8(self) -> u8 { self as u8 } diff --git a/crates/ironrdp-pdu/src/mcs.rs b/crates/ironrdp-pdu/src/mcs.rs index 41ba30a6..ca2c8ff4 100644 --- a/crates/ironrdp-pdu/src/mcs.rs +++ b/crates/ironrdp-pdu/src/mcs.rs @@ -232,10 +232,6 @@ impl DomainMcsPdu { } } - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn as_u8(self) -> u8 { self as u8 } @@ -626,7 +622,11 @@ impl<'de> McsPdu<'de> for SendDataRequest<'de> { } fn mcs_size(&self) -> usize { - per::CHOICE_SIZE + per::U16_SIZE * 2 + 1 + per::sizeof_length(self.user_data.len()) + self.user_data.len() + per::CHOICE_SIZE + + per::U16_SIZE * 2 + + 1 + + per::sizeof_length(u16::try_from(self.user_data.len()).unwrap_or(u16::MAX)) + + self.user_data.len() } } @@ -703,7 +703,11 @@ impl<'de> McsPdu<'de> for SendDataIndication<'de> { } fn mcs_size(&self) -> usize { - per::CHOICE_SIZE + per::U16_SIZE * 2 + 1 + per::sizeof_length(self.user_data.len()) + self.user_data.len() + per::CHOICE_SIZE + + per::U16_SIZE * 2 + + 1 + + per::sizeof_length(u16::try_from(self.user_data.len()).unwrap_or(u16::MAX)) + + self.user_data.len() } } @@ -719,11 +723,7 @@ pub enum DisconnectReason { } impl DisconnectReason { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] - fn as_u8(self) -> u8 { + pub fn as_u8(self) -> u8 { self as u8 } @@ -944,7 +944,7 @@ mod legacy { use std::io; - use ironrdp_core::{cast_int, Decode, DecodeResult, Encode}; + use ironrdp_core::{Decode, DecodeResult, Encode}; use thiserror::Error; use super::{ @@ -977,15 +977,11 @@ mod legacy { const NAME: &'static str = "ConnectInitial"; fn fields_buffer_ber_length(&self) -> usize { - // Can't rewrite in `as`-less way, because it's used in `Encode::size` which doesn't return an error. - #[expect(clippy::cast_possible_truncation, clippy::as_conversions)] - { - ber::sizeof_octet_string(self.calling_domain_selector.len() as u16) - + ber::sizeof_octet_string(self.called_domain_selector.len() as u16) - + ber::SIZEOF_BOOL - + (self.target_parameters.size() + self.min_parameters.size() + self.max_parameters.size()) - + ber::sizeof_octet_string(self.conference_create_request.size() as u16) - } + ber::sizeof_octet_string(self.calling_domain_selector.len() as u16) + + ber::sizeof_octet_string(self.called_domain_selector.len() as u16) + + ber::SIZEOF_BOOL + + (self.target_parameters.size() + self.min_parameters.size() + self.max_parameters.size()) + + ber::sizeof_octet_string(self.conference_create_request.size() as u16) } } @@ -993,8 +989,7 @@ mod legacy { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_size!(in: dst, size: self.size()); - let field_buffer_ber_length = cast_length!("field_buffer_ber_length", self.fields_buffer_ber_length())?; - ber::write_application_tag(dst, MCS_TYPE_CONNECT_INITIAL, field_buffer_ber_length)?; + ber::write_application_tag(dst, MCS_TYPE_CONNECT_INITIAL, self.fields_buffer_ber_length() as u16)?; ber::write_octet_string(dst, self.calling_domain_selector.as_ref())?; ber::write_octet_string(dst, self.called_domain_selector.as_ref())?; ber::write_bool(dst, self.upward_flag)?; @@ -1013,12 +1008,9 @@ mod legacy { fn size(&self) -> usize { let fields_buffer_ber_length = self.fields_buffer_ber_length(); - // Can't rewrite in `as`-less way, because it's used in `Encode::size` which doesn't return an error. - #[expect(clippy::cast_possible_truncation, clippy::as_conversions)] - let fields_buffer_ber_length_u16 = fields_buffer_ber_length as u16; fields_buffer_ber_length - + ber::sizeof_application_tag(MCS_TYPE_CONNECT_INITIAL, fields_buffer_ber_length_u16) + + ber::sizeof_application_tag(MCS_TYPE_CONNECT_INITIAL, fields_buffer_ber_length as u16) } } @@ -1050,14 +1042,10 @@ mod legacy { const NAME: &'static str = "ConnectResponse"; fn fields_buffer_ber_length(&self) -> usize { - // Can't rewrite in `as`-less way, because it's used in `Encode::size` which doesn't return an error. - #[expect(clippy::cast_possible_truncation, clippy::as_conversions)] - { - ber::SIZEOF_ENUMERATED - + ber::sizeof_integer(self.called_connect_id) - + self.domain_parameters.size() - + ber::sizeof_octet_string(self.conference_create_response.size() as u16) - } + ber::SIZEOF_ENUMERATED + + ber::sizeof_integer(self.called_connect_id) + + self.domain_parameters.size() + + ber::sizeof_octet_string(self.conference_create_response.size() as u16) } } @@ -1065,8 +1053,7 @@ mod legacy { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_size!(in: dst, size: self.size()); - let field_buffer_ber_length = cast_length!("field_buffer_ber_length", self.fields_buffer_ber_length())?; - ber::write_application_tag(dst, MCS_TYPE_CONNECT_RESPONSE, field_buffer_ber_length)?; + ber::write_application_tag(dst, MCS_TYPE_CONNECT_RESPONSE, self.fields_buffer_ber_length() as u16)?; ber::write_enumerated(dst, 0)?; ber::write_integer(dst, self.called_connect_id)?; self.domain_parameters.encode(dst)?; @@ -1082,11 +1069,9 @@ mod legacy { fn size(&self) -> usize { let fields_buffer_ber_length = self.fields_buffer_ber_length(); - // Can't rewrite in `as`-less way, because it's used in `Encode::size` which doesn't return an error. - #[expect(clippy::cast_possible_truncation, clippy::as_conversions)] - let fields_buffer_ber_length_u16 = fields_buffer_ber_length as u16; + fields_buffer_ber_length - + ber::sizeof_application_tag(MCS_TYPE_CONNECT_RESPONSE, fields_buffer_ber_length_u16) + + ber::sizeof_application_tag(MCS_TYPE_CONNECT_RESPONSE, fields_buffer_ber_length as u16) } } @@ -1094,7 +1079,7 @@ mod legacy { fn decode(src: &mut ReadCursor<'de>) -> DecodeResult { ber::read_application_tag(src, MCS_TYPE_CONNECT_RESPONSE)?; ber::read_enumerated(src, RESULT_ENUM_LENGTH)?; - let called_connect_id = cast_int!("called_connect_id", ber::read_integer(src)?)?; + let called_connect_id = ber::read_integer(src)? as u32; let domain_parameters = DomainParameters::decode(src)?; let _user_data_buffer_length = ber::read_octet_string_tag(src)?; let conference_create_response = ConferenceCreateResponse::decode(src)?; @@ -1146,25 +1131,22 @@ mod legacy { fn size(&self) -> usize { let fields_buffer_ber_length = self.fields_buffer_ber_length(); - // Can't rewrite in `as`-less way, because it's used in `Encode::size` which doesn't return an error. - #[expect(clippy::cast_possible_truncation, clippy::as_conversions)] - let fields_buffer_ber_length_u16 = fields_buffer_ber_length as u16; // FIXME: maybe size should return PduResult... - fields_buffer_ber_length + ber::sizeof_sequence_tag(fields_buffer_ber_length_u16) + fields_buffer_ber_length + ber::sizeof_sequence_tag(fields_buffer_ber_length as u16) } } impl<'de> Decode<'de> for DomainParameters { fn decode(src: &mut ReadCursor<'de>) -> DecodeResult { ber::read_sequence_tag(src)?; - let max_channel_ids = cast_int!("max_channel_ids", ber::read_integer(src)?)?; - let max_user_ids = cast_int!("max_user_ids", ber::read_integer(src)?)?; - let max_token_ids = cast_int!("max_token_ids", ber::read_integer(src)?)?; - let num_priorities = cast_int!("num_priorities", ber::read_integer(src)?)?; - let min_throughput = cast_int!("min_throughput", ber::read_integer(src)?)?; - let max_height = cast_int!("max_height", ber::read_integer(src)?)?; - let max_mcs_pdu_size = cast_int!("max_mcs_pdu_size", ber::read_integer(src)?)?; - let protocol_version = cast_int!("protocol_version", ber::read_integer(src)?)?; + let max_channel_ids = ber::read_integer(src)? as u32; + let max_user_ids = ber::read_integer(src)? as u32; + let max_token_ids = ber::read_integer(src)? as u32; + let num_priorities = ber::read_integer(src)? as u32; + let min_throughput = ber::read_integer(src)? as u32; + let max_height = ber::read_integer(src)? as u32; + let max_mcs_pdu_size = ber::read_integer(src)? as u32; + let protocol_version = ber::read_integer(src)? as u32; Ok(Self { max_channel_ids, diff --git a/crates/ironrdp-pdu/src/per.rs b/crates/ironrdp-pdu/src/per.rs index 5538a6e2..a1d2e002 100644 --- a/crates/ironrdp-pdu/src/per.rs +++ b/crates/ironrdp-pdu/src/per.rs @@ -114,7 +114,7 @@ pub(crate) fn write_long_length(dst: &mut WriteCursor<'_>, length: u16) { dst.write_u16_be(length | 0x8000) } -pub(crate) fn sizeof_length(length: usize) -> usize { +pub(crate) fn sizeof_length(length: u16) -> usize { if length > 0x7f { 2 } else { @@ -243,10 +243,7 @@ pub(crate) fn read_object_id(src: &mut ReadCursor<'_>) -> Result<[u8; OBJECT_ID_ } pub(crate) fn write_object_id(dst: &mut WriteCursor<'_>, object_ids: [u8; OBJECT_ID_SIZE]) { - write_length( - dst, - u16::try_from(OBJECT_ID_SIZE).expect("OBJECT_ID_SIZE fits into u16") - 1, - ); + write_length(dst, OBJECT_ID_SIZE as u16 - 1); let first_two_tuples = object_ids[0] * 40 + object_ids[1]; dst.write_u8(first_two_tuples); @@ -341,8 +338,8 @@ pub(crate) mod legacy { Ok(2) } - pub(crate) fn write_short_length(mut stream: impl io::Write, length: u8) -> io::Result { - stream.write_u8(length)?; + pub(crate) fn write_short_length(mut stream: impl io::Write, length: u16) -> io::Result { + stream.write_u8(length as u8)?; Ok(1) } @@ -350,12 +347,6 @@ pub(crate) mod legacy { if length > 0x7f { write_long_length(stream, length) } else { - #[expect( - clippy::as_conversions, - clippy::cast_possible_truncation, - reason = "cast is valid due to prior check" - )] - let length = length as u8; write_short_length(stream, length) } } @@ -422,25 +413,12 @@ pub(crate) mod legacy { pub(crate) fn write_u32(mut stream: impl io::Write, value: u32) -> io::Result { if value <= 0xff { let size = write_length(&mut stream, 1)?; - - #[expect( - clippy::as_conversions, - clippy::cast_possible_truncation, - reason = "cast is valid due to prior check" - )] - let value = value as u8; - stream.write_u8(value)?; + stream.write_u8(value as u8)?; Ok(size + 1) } else if value <= 0xffff { let size = write_length(&mut stream, 2)?; - #[expect( - clippy::as_conversions, - clippy::cast_possible_truncation, - reason = "cast is valid due to prior check" - )] - let value = value as u16; - stream.write_u16::(value)?; + stream.write_u16::(value as u16)?; Ok(size + 2) } else { @@ -510,10 +488,7 @@ pub(crate) mod legacy { } pub(crate) fn write_object_id(mut stream: impl io::Write, object_ids: [u8; OBJECT_ID_SIZE]) -> io::Result { - let object_oid_size: u16 = OBJECT_ID_SIZE - .try_into() - .expect("OBJECT_ID_SIZE is known to fit into u16"); - let size = write_length(&mut stream, object_oid_size - 1)?; + let size = write_length(&mut stream, OBJECT_ID_SIZE as u16 - 1)?; let first_two_tuples = object_ids[0] * 40 + object_ids[1]; stream.write_u8(first_two_tuples)?; @@ -528,7 +503,7 @@ pub(crate) mod legacy { pub(crate) fn read_octet_string(mut stream: impl io::Read, min: usize) -> io::Result> { let (read_length, _) = read_length(&mut stream)?; - let mut read_octet_string = vec![0; min + usize::from(read_length)]; + let mut read_octet_string = vec![0; min + read_length as usize]; stream.read_exact(read_octet_string.as_mut())?; Ok(read_octet_string) @@ -541,9 +516,7 @@ pub(crate) mod legacy { min }; - let length = u16::try_from(length) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid octet string length"))?; - let size = write_length(&mut stream, length)?; + let size = write_length(&mut stream, length as u16)?; stream.write_all(octet_string)?; Ok(size + octet_string.len()) @@ -554,7 +527,7 @@ pub(crate) mod legacy { let length = (read_length + min).div_ceil(2); - let mut read_numeric_string = vec![0; usize::from(length)]; + let mut read_numeric_string = vec![0; length as usize]; stream.read_exact(read_numeric_string.as_mut())?; Ok(()) @@ -563,9 +536,7 @@ pub(crate) mod legacy { pub(crate) fn write_numeric_string(mut stream: impl io::Write, num_str: &[u8], min: usize) -> io::Result { let length = if num_str.len() >= min { num_str.len() - min } else { min }; - let length = u16::try_from(length) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid numeric string length"))?; - let mut size = write_length(&mut stream, length)?; + let mut size = write_length(&mut stream, length as u16)?; let magic_transform = |elem| (elem - 0x30) % 10; diff --git a/crates/ironrdp-pdu/src/rdp/mod.rs b/crates/ironrdp-pdu/src/rdp.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/mod.rs rename to crates/ironrdp-pdu/src/rdp.rs diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets.rs similarity index 99% rename from crates/ironrdp-pdu/src/rdp/capability_sets/mod.rs rename to crates/ironrdp-pdu/src/rdp/capability_sets.rs index 2662e95b..35737ac3 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets.rs @@ -215,9 +215,9 @@ impl<'de> Decode<'de> for DemandActive { fn decode(src: &mut ReadCursor<'de>) -> DecodeResult { ensure_fixed_part_size!(in: src); - let source_descriptor_length = usize::from(src.read_u16()); + let source_descriptor_length = src.read_u16() as usize; // The combined size in bytes of the numberCapabilities, pad2Octets, and capabilitySets fields. - let _combined_capabilities_length = usize::from(src.read_u16()); + let _combined_capabilities_length = src.read_u16() as usize; ensure_size!(in: src, size: source_descriptor_length); let source_descriptor = utils::decode_string( @@ -227,7 +227,7 @@ impl<'de> Decode<'de> for DemandActive { )?; ensure_size!(in: src, size: 2 + 2); - let capability_sets_count = usize::from(src.read_u16()); + let capability_sets_count = src.read_u16() as usize; let _padding = src.read_u16(); let mut capability_sets = Vec::with_capacity(capability_sets_count); @@ -509,7 +509,7 @@ impl<'de> Decode<'de> for CapabilitySet { ) })?; - let length = usize::from(src.read_u16()); + let length = src.read_u16() as usize; if length < CAPABILITY_SET_TYPE_FIELD_SIZE + CAPABILITY_SET_LENGTH_FIELD_SIZE { return Err(invalid_field_err!("len", "invalid capability set length")); diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap/tests.rs index 78b8fa10..a1ba6b06 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; @@ -20,25 +19,28 @@ const BITMAP_BUFFER: [u8; 24] = [ 0x00, 0x00, // pad2octetsB ]; -static BITMAP: LazyLock = LazyLock::new(|| Bitmap { - pref_bits_per_pix: 24, - desktop_width: 1280, - desktop_height: 1024, - desktop_resize_flag: true, - drawing_flags: BitmapDrawingFlags::ALLOW_SKIP_ALPHA, -}); +lazy_static! { + pub static ref BITMAP: Bitmap = Bitmap { + pref_bits_per_pix: 24, + desktop_width: 1280, + desktop_height: 1024, + desktop_resize_flag: true, + drawing_flags: BitmapDrawingFlags::ALLOW_SKIP_ALPHA, + }; +} #[test] fn from_buffer_correctly_parses_bitmap_capset() { let buffer = BITMAP_BUFFER.as_ref(); - let bitmap = LazyLock::force(&BITMAP); - assert_eq!(bitmap, &decode(buffer).unwrap()); + assert_eq!(*BITMAP, decode(buffer).unwrap()); } #[test] fn to_buffer_correctly_serializes_bitmap_capset() { - let buffer = encode_vec(LazyLock::force(&BITMAP)).unwrap(); + let capset = BITMAP.clone(); + + let buffer = encode_vec(&capset).unwrap(); assert_eq!(buffer, BITMAP_BUFFER.as_ref()); } diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_cache/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_cache.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_cache/mod.rs rename to crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_cache.rs diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_cache/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_cache/tests.rs index abd58ab8..6ee14e9e 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_cache/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_cache/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; @@ -36,56 +35,58 @@ const BITMAP_CACHE_REV2_BUFFER: [u8; 36] = [ const CELL_INFO_BUFFER: [u8; 4] = [0xfb, 0x09, 0x00, 0x80]; -static BITMAP_CACHE: LazyLock = LazyLock::new(|| BitmapCache { - caches: [ - CacheEntry { - entries: 200, - max_cell_size: 512, - }, - CacheEntry { - entries: 600, - max_cell_size: 2048, - }, - CacheEntry { - entries: 1000, - max_cell_size: 8192, - }, - ], -}); -static BITMAP_CACHE_REV2: LazyLock = LazyLock::new(|| BitmapCacheRev2 { - cache_flags: CacheFlags::PERSISTENT_KEYS_EXPECTED_FLAG | CacheFlags::ALLOW_CACHE_WAITING_LIST_FLAG, - num_cell_caches: 3, - cache_cell_info: [ - CellInfo { - num_entries: 120, - is_cache_persistent: false, - }, - CellInfo { - num_entries: 120, - is_cache_persistent: false, - }, - CellInfo { - num_entries: 2555, - is_cache_persistent: true, - }, - CellInfo { - num_entries: 0, - is_cache_persistent: false, - }, - CellInfo { - num_entries: 0, - is_cache_persistent: false, - }, - ], -}); -static CELL_INFO: LazyLock = LazyLock::new(|| CellInfo { - num_entries: 2555, - is_cache_persistent: true, -}); -static CACHE_ENTRY: LazyLock = LazyLock::new(|| CacheEntry { - entries: 0x64, - max_cell_size: 0x32, -}); +lazy_static! { + pub static ref BITMAP_CACHE: BitmapCache = BitmapCache { + caches: [ + CacheEntry { + entries: 200, + max_cell_size: 512 + }, + CacheEntry { + entries: 600, + max_cell_size: 2048 + }, + CacheEntry { + entries: 1000, + max_cell_size: 8192 + } + ], + }; + pub static ref BITMAP_CACHE_REV2: BitmapCacheRev2 = BitmapCacheRev2 { + cache_flags: CacheFlags::PERSISTENT_KEYS_EXPECTED_FLAG | CacheFlags::ALLOW_CACHE_WAITING_LIST_FLAG, + num_cell_caches: 3, + cache_cell_info: [ + CellInfo { + num_entries: 120, + is_cache_persistent: false + }, + CellInfo { + num_entries: 120, + is_cache_persistent: false + }, + CellInfo { + num_entries: 2555, + is_cache_persistent: true + }, + CellInfo { + num_entries: 0, + is_cache_persistent: false + }, + CellInfo { + num_entries: 0, + is_cache_persistent: false + } + ], + }; + pub static ref CELL_INFO: CellInfo = CellInfo { + num_entries: 2555, + is_cache_persistent: true + }; + pub static ref CACHE_ENTRY: CacheEntry = CacheEntry { + entries: 0x64, + max_cell_size: 0x32, + }; +} #[test] fn from_buffer_correctly_parses_bitmap_cache_capset() { @@ -96,7 +97,9 @@ fn from_buffer_correctly_parses_bitmap_cache_capset() { #[test] fn to_buffer_correctly_serializes_bitmap_cache_capset() { - let buffer = encode_vec(&*BITMAP_CACHE).unwrap(); + let bitmap_cache = BITMAP_CACHE.clone(); + + let buffer = encode_vec(&bitmap_cache).unwrap(); assert_eq!(buffer, BITMAP_CACHE_BUFFER.as_ref()); } @@ -115,7 +118,9 @@ fn from_buffer_correctly_parses_bitmap_cache_rev2_capset() { #[test] fn to_buffer_correctly_serializes_bitmap_cache_rev2_capset() { - let buffer = encode_vec(&*BITMAP_CACHE_REV2).unwrap(); + let bitmap_cache = BITMAP_CACHE_REV2.clone(); + + let buffer = encode_vec(&bitmap_cache).unwrap(); assert_eq!(buffer, BITMAP_CACHE_REV2_BUFFER.as_ref()); } diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs.rs similarity index 98% rename from crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs/mod.rs rename to crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs.rs index f588bc42..cb42178f 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs.rs @@ -141,10 +141,10 @@ impl<'de> Decode<'de> for BitmapCodecs { fn decode(src: &mut ReadCursor<'de>) -> DecodeResult { ensure_fixed_part_size!(in: src); - let codec_count = src.read_u8(); + let codecs_count = src.read_u8(); - let mut codecs = Vec::with_capacity(usize::from(codec_count)); - for _ in 0..codec_count { + let mut codecs = Vec::with_capacity(codecs_count as usize); + for _ in 0..codecs_count { codecs.push(Codec::decode(src)?); } @@ -552,7 +552,7 @@ impl<'de> Decode<'de> for RfxCapset { let num_icaps = src.read_u16(); let _icaps_len = src.read_u16(); - let mut icaps_data = Vec::with_capacity(usize::from(num_icaps)); + let mut icaps_data = Vec::with_capacity(num_icaps as usize); for _ in 0..num_icaps { icaps_data.push(RfxICap::decode(src)?); } @@ -637,10 +637,6 @@ pub enum EntropyBits { } impl EntropyBits { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn as_u8(self) -> u8 { self as u8 } diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs/tests.rs index 0828f2d6..e9055f25 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/bitmap_codecs/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode_cursor, encode_vec, DecodeErrorKind}; +use lazy_static::lazy_static; use super::*; @@ -169,27 +168,14 @@ const BITMAP_CODECS_BUFFER: [u8; 91] = [ 0x03, // color loss level ]; -static GUID: LazyLock = LazyLock::new(|| { - Guid( - 0xca8d_1bb9, - 0x000f, - 0x154f, - 0x58, - 0x9f, - 0xae, - 0x2d, - 0x1a, - 0x87, - 0xe2, - 0xd6, - ) -}); -static RFX_ICAP: LazyLock = LazyLock::new(|| RfxICap { - flags: RfxICapFlags::CODEC_MODE, - entropy_bits: EntropyBits::Rlgr3, -}); -static RFX_CAPSET: LazyLock = LazyLock::new(|| { - RfxCapset(vec![ +lazy_static! { + #[rustfmt::skip] + pub static ref GUID: Guid = Guid(0xca8d_1bb9, 0x000f, 0x154f, 0x58, 0x9f, 0xae, 0x2d, 0x1a, 0x87, 0xe2, 0xd6); + pub static ref RFX_ICAP: RfxICap = RfxICap { + flags: RfxICapFlags::CODEC_MODE, + entropy_bits: EntropyBits::Rlgr3, + }; + pub static ref RFX_CAPSET: RfxCapset = RfxCapset(vec![ RfxICap { flags: RfxICapFlags::empty(), entropy_bits: EntropyBits::Rlgr1, @@ -197,11 +183,9 @@ static RFX_CAPSET: LazyLock = LazyLock::new(|| { RfxICap { flags: RfxICapFlags::CODEC_MODE, entropy_bits: EntropyBits::Rlgr3, - }, - ]) -}); -static RFX_CAPS: LazyLock = LazyLock::new(|| { - RfxCaps(RfxCapset(vec![ + } + ]); + pub static ref RFX_CAPS: RfxCaps = RfxCaps(RfxCapset(vec![ RfxICap { flags: RfxICapFlags::empty(), entropy_bits: EntropyBits::Rlgr1, @@ -209,30 +193,9 @@ static RFX_CAPS: LazyLock = LazyLock::new(|| { RfxICap { flags: RfxICapFlags::CODEC_MODE, entropy_bits: EntropyBits::Rlgr3, - }, - ])) -}); -static RFX_CLIENT_CAPS_CONTAINER: LazyLock = LazyLock::new(|| RfxClientCapsContainer { - capture_flags: CaptureFlags::CARDP_CAPS_CAPTURE_NON_CAC, - caps_data: RfxCaps(RfxCapset(vec![ - RfxICap { - flags: RfxICapFlags::empty(), - entropy_bits: EntropyBits::Rlgr1, - }, - RfxICap { - flags: RfxICapFlags::CODEC_MODE, - entropy_bits: EntropyBits::Rlgr3, - }, - ])), -}); -static NSCODEC: LazyLock = LazyLock::new(|| NsCodec { - is_dynamic_fidelity_allowed: true, - is_subsampling_allowed: true, - color_loss_level: 3, -}); -static CODEC: LazyLock = LazyLock::new(|| Codec { - id: 3, - property: CodecProperty::RemoteFx(RemoteFxContainer::ClientContainer(RfxClientCapsContainer { + } + ])); + pub static ref RFX_CLIENT_CAPS_CONTAINER: RfxClientCapsContainer = RfxClientCapsContainer { capture_flags: CaptureFlags::CARDP_CAPS_CAPTURE_NON_CAC, caps_data: RfxCaps(RfxCapset(vec![ RfxICap { @@ -242,19 +205,18 @@ static CODEC: LazyLock = LazyLock::new(|| Codec { RfxICap { flags: RfxICapFlags::CODEC_MODE, entropy_bits: EntropyBits::Rlgr3, - }, + } ])), - })), -}); -static CODEC_SERVER_MODE: LazyLock = LazyLock::new(|| Codec { - id: 0, - property: CodecProperty::ImageRemoteFx(RemoteFxContainer::ServerContainer(4)), -}); -static BITMAP_CODECS: LazyLock = LazyLock::new(|| { - BitmapCodecs(vec![ - Codec { - id: 3, - property: CodecProperty::RemoteFx(RemoteFxContainer::ClientContainer(RfxClientCapsContainer { + }; + pub static ref NSCODEC: NsCodec = NsCodec { + is_dynamic_fidelity_allowed: true, + is_subsampling_allowed: true, + color_loss_level: 3, + }; + pub static ref CODEC: Codec = Codec { + id: 3, + property: CodecProperty::RemoteFx(RemoteFxContainer::ClientContainer( + RfxClientCapsContainer { capture_flags: CaptureFlags::CARDP_CAPS_CAPTURE_NON_CAC, caps_data: RfxCaps(RfxCapset(vec![ RfxICap { @@ -264,9 +226,33 @@ static BITMAP_CODECS: LazyLock = LazyLock::new(|| { RfxICap { flags: RfxICapFlags::CODEC_MODE, entropy_bits: EntropyBits::Rlgr3, - }, + } ])), - })), + } + )), + }; + pub static ref CODEC_SERVER_MODE: Codec = Codec { + id: 0, + property: CodecProperty::ImageRemoteFx(RemoteFxContainer::ServerContainer(4)), + }; + pub static ref BITMAP_CODECS: BitmapCodecs = BitmapCodecs(vec![ + Codec { + id: 3, + property: CodecProperty::RemoteFx(RemoteFxContainer::ClientContainer( + RfxClientCapsContainer { + capture_flags: CaptureFlags::CARDP_CAPS_CAPTURE_NON_CAC, + caps_data: RfxCaps(RfxCapset(vec![ + RfxICap { + flags: RfxICapFlags::empty(), + entropy_bits: EntropyBits::Rlgr1, + }, + RfxICap { + flags: RfxICapFlags::CODEC_MODE, + entropy_bits: EntropyBits::Rlgr3, + } + ])), + } + )) }, Codec { id: 1, @@ -274,10 +260,10 @@ static BITMAP_CODECS: LazyLock = LazyLock::new(|| { is_dynamic_fidelity_allowed: true, is_subsampling_allowed: true, color_loss_level: 3, - }), + }) }, - ]) -}); + ]); +} #[test] fn from_buffer_correctly_parses_guid() { diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/brush/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/brush.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/capability_sets/brush/mod.rs rename to crates/ironrdp-pdu/src/rdp/capability_sets/brush.rs diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/brush/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/brush/tests.rs index 75d9612a..3941e4f9 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/brush/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/brush/tests.rs @@ -1,14 +1,15 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; const BRUSH_BUFFER: [u8; 4] = [0x01, 0x00, 0x00, 0x00]; -static BRUSH: LazyLock = LazyLock::new(|| Brush { - support_level: SupportLevel::Color8x8, -}); +lazy_static! { + pub static ref BRUSH: Brush = Brush { + support_level: SupportLevel::Color8x8, + }; +} #[test] fn from_buffer_successfully_parses_brush_capset() { diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/general/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/general.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/capability_sets/general/mod.rs rename to crates/ironrdp-pdu/src/rdp/capability_sets/general.rs diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/general/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/general/tests.rs index 55b09cbf..76458295 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/general/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/general/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; @@ -18,18 +17,20 @@ const GENERAL_CAPSET_BUFFER: [u8; 20] = [ 0x00, // suppressOutputSupport ]; -static CAPSET_GENERAL: LazyLock = LazyLock::new(|| General { - major_platform_type: MajorPlatformType::WINDOWS, - minor_platform_type: MinorPlatformType::WINDOWS_NT, - protocol_version: PROTOCOL_VER, - extra_flags: GeneralExtraFlags::FASTPATH_OUTPUT_SUPPORTED - | GeneralExtraFlags::LONG_CREDENTIALS_SUPPORTED - | GeneralExtraFlags::AUTORECONNECT_SUPPORTED - | GeneralExtraFlags::ENC_SALTED_CHECKSUM - | GeneralExtraFlags::NO_BITMAP_COMPRESSION_HDR, - refresh_rect_support: false, - suppress_output_support: false, -}); +lazy_static! { + pub static ref CAPSET_GENERAL: General = General { + major_platform_type: MajorPlatformType::WINDOWS, + minor_platform_type: MinorPlatformType::WINDOWS_NT, + protocol_version: PROTOCOL_VER, + extra_flags: GeneralExtraFlags::FASTPATH_OUTPUT_SUPPORTED + | GeneralExtraFlags::LONG_CREDENTIALS_SUPPORTED + | GeneralExtraFlags::AUTORECONNECT_SUPPORTED + | GeneralExtraFlags::ENC_SALTED_CHECKSUM + | GeneralExtraFlags::NO_BITMAP_COMPRESSION_HDR, + refresh_rect_support: false, + suppress_output_support: false, + }; +} #[test] fn from_buffer_correctly_parses_general_capset() { diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache/mod.rs rename to crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache.rs diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache/tests.rs index fff93d06..be7443e0 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/glyph_cache/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; @@ -15,59 +14,61 @@ const GLYPH_CACHE_BUFFER: [u8; 48] = [ const CACHE_DEFINITION_BUFFER: [u8; 4] = [0xfe, 0x00, 0x04, 0x00]; -static GLYPH_CACHE: LazyLock = LazyLock::new(|| GlyphCache { - glyph_cache: [ - CacheDefinition { - entries: 254, - max_cell_size: 4, - }, - CacheDefinition { - entries: 254, - max_cell_size: 4, - }, - CacheDefinition { - entries: 254, - max_cell_size: 8, - }, - CacheDefinition { - entries: 254, - max_cell_size: 8, - }, - CacheDefinition { - entries: 254, - max_cell_size: 16, - }, - CacheDefinition { - entries: 254, - max_cell_size: 32, - }, - CacheDefinition { - entries: 254, - max_cell_size: 64, - }, - CacheDefinition { - entries: 254, - max_cell_size: 128, - }, - CacheDefinition { - entries: 254, +lazy_static! { + pub static ref GLYPH_CACHE: GlyphCache = GlyphCache { + glyph_cache: [ + CacheDefinition { + entries: 254, + max_cell_size: 4 + }, + CacheDefinition { + entries: 254, + max_cell_size: 4 + }, + CacheDefinition { + entries: 254, + max_cell_size: 8 + }, + CacheDefinition { + entries: 254, + max_cell_size: 8 + }, + CacheDefinition { + entries: 254, + max_cell_size: 16 + }, + CacheDefinition { + entries: 254, + max_cell_size: 32 + }, + CacheDefinition { + entries: 254, + max_cell_size: 64 + }, + CacheDefinition { + entries: 254, + max_cell_size: 128 + }, + CacheDefinition { + entries: 254, + max_cell_size: 256 + }, + CacheDefinition { + entries: 64, + max_cell_size: 2048 + } + ], + frag_cache: CacheDefinition { + entries: 256, max_cell_size: 256, }, - CacheDefinition { - entries: 64, - max_cell_size: 2048, - }, - ], - frag_cache: CacheDefinition { - entries: 256, - max_cell_size: 256, - }, - glyph_support_level: GlyphSupportLevel::Encode, -}); -static CACHE_DEFINITION: LazyLock = LazyLock::new(|| CacheDefinition { - entries: 254, - max_cell_size: 4, -}); + glyph_support_level: GlyphSupportLevel::Encode, + }; + pub static ref CACHE_DEFINITION: CacheDefinition = CacheDefinition { + entries: 254, + max_cell_size: 4, + }; +} #[test] fn from_buffer_correctly_parses_glyph_cache_capset() { diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/input/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/input/tests.rs index 5337365d..a9d15011 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/input/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/input/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; @@ -17,14 +16,16 @@ const INPUT_BUFFER: [u8; 84] = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // imeFileName ]; -static INPUT: LazyLock = LazyLock::new(|| Input { - input_flags: InputFlags::SCANCODES | InputFlags::UNICODE | InputFlags::MOUSEX, - keyboard_layout: 0x409, - keyboard_type: Some(KeyboardType::IbmEnhanced), - keyboard_subtype: 0, - keyboard_function_key: 12, - keyboard_ime_filename: String::new(), -}); +lazy_static! { + pub static ref INPUT: Input = Input { + input_flags: InputFlags::SCANCODES | InputFlags::UNICODE | InputFlags::MOUSEX, + keyboard_layout: 0x409, + keyboard_type: Some(KeyboardType::IbmEnhanced), + keyboard_subtype: 0, + keyboard_function_key: 12, + keyboard_ime_filename: String::new(), + }; +} #[test] fn from_buffer_correctly_parses_input_capset() { diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/offscreen_bitmap_cache/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/offscreen_bitmap_cache.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/capability_sets/offscreen_bitmap_cache/mod.rs rename to crates/ironrdp-pdu/src/rdp/capability_sets/offscreen_bitmap_cache.rs diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/offscreen_bitmap_cache/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/offscreen_bitmap_cache/tests.rs index e8dac691..5501ac74 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/offscreen_bitmap_cache/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/offscreen_bitmap_cache/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; @@ -9,11 +8,14 @@ const OFFSCREEN_BITMAP_CACHE_BUFFER: [u8; 8] = [ 0x00, 0x1e, // offscreenCacheSize 0x64, 0x00, // offscreenCacheEntries ]; -static OFFSCREEN_BITMAP_CACHE: LazyLock = LazyLock::new(|| OffscreenBitmapCache { - is_supported: true, - cache_size: 7680, - cache_entries: 100, -}); + +lazy_static! { + pub static ref OFFSCREEN_BITMAP_CACHE: OffscreenBitmapCache = OffscreenBitmapCache { + is_supported: true, + cache_size: 7680, + cache_entries: 100, + }; +} #[test] fn from_buffer_correctly_parses_offscreen_bitmap_cache_capset() { diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/order/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/order.rs similarity index 89% rename from crates/ironrdp-pdu/src/rdp/capability_sets/order/mod.rs rename to crates/ironrdp-pdu/src/rdp/capability_sets/order.rs index 70d823cb..30de1c57 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/order/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/order.rs @@ -9,7 +9,6 @@ const ORD_LEVEL_1_ORDERS: u16 = 1; const SUPPORT_ARRAY_LEN: usize = 32; const DESKTOP_SAVE_Y_GRAN_VAL: u16 = 20; -#[repr(u8)] #[derive(Copy, Clone)] pub enum OrderSupportIndex { DstBlt = 0x00, @@ -35,16 +34,6 @@ pub enum OrderSupportIndex { Index = 0x1B, } -impl OrderSupportIndex { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] - fn as_u8(self) -> u8 { - self as u8 - } -} - bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct OrderFlags: u16 { @@ -66,11 +55,11 @@ bitflags! { #[derive(Debug, PartialEq, Eq, Clone)] pub struct Order { - order_flags: OrderFlags, + pub order_flags: OrderFlags, order_support: [u8; SUPPORT_ARRAY_LEN], - order_support_ex_flags: OrderSupportExFlags, - desktop_save_size: u32, - text_ansi_code_page: u16, + pub order_support_ex_flags: OrderSupportExFlags, + pub desktop_save_size: u32, + pub text_ansi_code_page: u16, } impl Order { @@ -94,11 +83,11 @@ impl Order { } pub fn set_support_flag(&mut self, flag: OrderSupportIndex, value: bool) { - self.order_support[usize::from(flag.as_u8())] = u8::from(value) + self.order_support[flag as usize] = u8::from(value) } pub fn get_support_flag(&mut self, flag: OrderSupportIndex) -> bool { - self.order_support[usize::from(flag.as_u8())] == 1 + self.order_support[flag as usize] == 1 } } diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/order/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/order/tests.rs index 85d0e2ee..3f6c873e 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/order/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/order/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; @@ -25,40 +24,42 @@ const ORDER_BUFFER: [u8; 84] = [ 0x00, 0x00, // pad2octetsE ]; -static ORDER: LazyLock = LazyLock::new(|| Order { - order_flags: OrderFlags::COLOR_INDEX_SUPPORT | OrderFlags::NEGOTIATE_ORDER_SUPPORT, - order_support: { - let mut array = [0u8; 32]; +lazy_static! { + pub static ref ORDER: Order = Order { + order_flags: OrderFlags::COLOR_INDEX_SUPPORT | OrderFlags::NEGOTIATE_ORDER_SUPPORT, + order_support: { + let mut array = [0u8; 32]; - array[usize::from(OrderSupportIndex::DstBlt.as_u8())] = 1; - array[usize::from(OrderSupportIndex::PatBlt.as_u8())] = 1; - array[usize::from(OrderSupportIndex::ScrBlt.as_u8())] = 1; - array[usize::from(OrderSupportIndex::MemBlt.as_u8())] = 1; - array[usize::from(OrderSupportIndex::Mem3Blt.as_u8())] = 1; - array[usize::from(OrderSupportIndex::DrawnInEGrid.as_u8())] = 1; - array[usize::from(OrderSupportIndex::LineTo.as_u8())] = 1; - array[usize::from(OrderSupportIndex::MultiDrawnInEGrid.as_u8())] = 1; - array[usize::from(OrderSupportIndex::SaveBitmap.as_u8())] = 1; - array[usize::from(OrderSupportIndex::MultiDstBlt.as_u8())] = 1; - array[usize::from(OrderSupportIndex::MultiPatBlt.as_u8())] = 1; - array[usize::from(OrderSupportIndex::MultiScrBlt.as_u8())] = 1; - array[usize::from(OrderSupportIndex::MultiOpaqueRect.as_u8())] = 1; - array[usize::from(OrderSupportIndex::Fast.as_u8())] = 1; - array[usize::from(OrderSupportIndex::PolygonSC.as_u8())] = 1; - array[usize::from(OrderSupportIndex::PolygonCB.as_u8())] = 1; - array[usize::from(OrderSupportIndex::Polyline.as_u8())] = 1; - array[usize::from(OrderSupportIndex::FastGlyph.as_u8())] = 1; - array[usize::from(OrderSupportIndex::EllipseSC.as_u8())] = 1; - array[usize::from(OrderSupportIndex::EllipseCB.as_u8())] = 1; - array[usize::from(OrderSupportIndex::Index.as_u8())] = 1; + array[OrderSupportIndex::DstBlt as usize] = 1; + array[OrderSupportIndex::PatBlt as usize] = 1; + array[OrderSupportIndex::ScrBlt as usize] = 1; + array[OrderSupportIndex::MemBlt as usize] = 1; + array[OrderSupportIndex::Mem3Blt as usize] = 1; + array[OrderSupportIndex::DrawnInEGrid as usize] = 1; + array[OrderSupportIndex::LineTo as usize] = 1; + array[OrderSupportIndex::MultiDrawnInEGrid as usize] = 1; + array[OrderSupportIndex::SaveBitmap as usize] = 1; + array[OrderSupportIndex::MultiDstBlt as usize] = 1; + array[OrderSupportIndex::MultiPatBlt as usize] = 1; + array[OrderSupportIndex::MultiScrBlt as usize] = 1; + array[OrderSupportIndex::MultiOpaqueRect as usize] = 1; + array[OrderSupportIndex::Fast as usize] = 1; + array[OrderSupportIndex::PolygonSC as usize] = 1; + array[OrderSupportIndex::PolygonCB as usize] = 1; + array[OrderSupportIndex::Polyline as usize] = 1; + array[OrderSupportIndex::FastGlyph as usize] = 1; + array[OrderSupportIndex::EllipseSC as usize] = 1; + array[OrderSupportIndex::EllipseCB as usize] = 1; + array[OrderSupportIndex::Index as usize] = 1; - array - }, + array + }, - order_support_ex_flags: OrderSupportExFlags::CACHE_BITMAP_REV3_SUPPORT, - desktop_save_size: 230_400, - text_ansi_code_page: 0, -}); + order_support_ex_flags: OrderSupportExFlags::CACHE_BITMAP_REV3_SUPPORT, + desktop_save_size: 230_400, + text_ansi_code_page: 0, + }; +} #[test] fn from_buffer_correctly_parses_order_capset() { diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/pointer/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/pointer/tests.rs index f7b0a73a..d5933ab9 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/pointer/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/pointer/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; @@ -10,10 +9,12 @@ const POINTER_BUFFER: [u8; 6] = [ 0x15, 0x00, // pointerCacheSize ]; -static POINTER: LazyLock = LazyLock::new(|| Pointer { - color_pointer_cache_size: 20, - pointer_cache_size: 21, -}); +lazy_static! { + pub static ref POINTER: Pointer = Pointer { + color_pointer_cache_size: 20, + pointer_cache_size: 21, + }; +} #[test] fn from_buffer_correctly_parses_pointer_capset() { diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/sound/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/sound.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/capability_sets/sound/mod.rs rename to crates/ironrdp-pdu/src/rdp/capability_sets/sound.rs diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/sound/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/sound/tests.rs index d43f52b0..0d3627ec 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/sound/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/sound/tests.rs @@ -1,14 +1,15 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; const SOUND_BUFFER: [u8; 4] = [0x01, 0x00, 0x00, 0x00]; -static SOUND: LazyLock = LazyLock::new(|| Sound { - flags: SoundFlags::BEEPS, -}); +lazy_static! { + pub static ref SOUND: Sound = Sound { + flags: SoundFlags::BEEPS, + }; +} #[test] fn from_buffer_correctly_parses_sound_capset() { diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/surface_commands/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/surface_commands/tests.rs index ac96f46e..1dfbb2c0 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/surface_commands/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/surface_commands/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; @@ -9,9 +8,11 @@ const SURFACE_COMMANDS_BUFFER: [u8; 8] = [ 0x00, 0x00, 0x00, 0x00, // reserved ]; -static SURFACE_COMMANDS: LazyLock = LazyLock::new(|| SurfaceCommands { - flags: CmdFlags::SET_SURFACE_BITS | CmdFlags::FRAME_MARKER | CmdFlags::STREAM_SURFACE_BITS, -}); +lazy_static! { + pub static ref SURFACE_COMMANDS: SurfaceCommands = SurfaceCommands { + flags: CmdFlags::SET_SURFACE_BITS | CmdFlags::FRAME_MARKER | CmdFlags::STREAM_SURFACE_BITS, + }; +} #[test] fn from_buffer_correctly_parses_surface_commands_capset() { diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/virtual_channel/mod.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/virtual_channel.rs similarity index 98% rename from crates/ironrdp-pdu/src/rdp/capability_sets/virtual_channel/mod.rs rename to crates/ironrdp-pdu/src/rdp/capability_sets/virtual_channel.rs index 085e78f9..84e6ac42 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/virtual_channel/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/virtual_channel.rs @@ -29,7 +29,7 @@ bitflags! { /// # MSDN /// /// * [Virtual Channel Capability Set](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/a8593178-80c0-4b80-876c-cb77e62cecfc) -#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct VirtualChannel { pub flags: VirtualChannelFlags, pub chunk_size: Option, diff --git a/crates/ironrdp-pdu/src/rdp/capability_sets/virtual_channel/tests.rs b/crates/ironrdp-pdu/src/rdp/capability_sets/virtual_channel/tests.rs index ff14c89a..6f42c549 100644 --- a/crates/ironrdp-pdu/src/rdp/capability_sets/virtual_channel/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/capability_sets/virtual_channel/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; @@ -13,14 +12,16 @@ const VIRTUAL_CHANNEL_BUFFER: [u8; 8] = [ 0x40, 0x06, 0x00, 0x00, // chunk size ]; -static VIRTUAL_CHANNEL_INCOMPLETE: LazyLock = LazyLock::new(|| VirtualChannel { - flags: VirtualChannelFlags::COMPRESSION_SERVER_TO_CLIENT, - chunk_size: None, -}); -static VIRTUAL_CHANNEL: LazyLock = LazyLock::new(|| VirtualChannel { - flags: VirtualChannelFlags::NO_COMPRESSION, - chunk_size: Some(1600), -}); +lazy_static! { + pub static ref VIRTUAL_CHANNEL_INCOMPLETE: VirtualChannel = VirtualChannel { + flags: VirtualChannelFlags::COMPRESSION_SERVER_TO_CLIENT, + chunk_size: None, + }; + pub static ref VIRTUAL_CHANNEL: VirtualChannel = VirtualChannel { + flags: VirtualChannelFlags::NO_COMPRESSION, + chunk_size: Some(1600), + }; +} #[test] fn from_buffer_correctly_parses_virtual_channel_incomplete_capset() { @@ -37,7 +38,7 @@ fn from_buffer_correctly_parses_virtual_channel_capset() { #[test] fn to_buffer_correctly_serializes_virtual_channel_incomplete_capset() { - let c = *VIRTUAL_CHANNEL_INCOMPLETE; + let c = VIRTUAL_CHANNEL_INCOMPLETE.clone(); let buffer = encode_vec(&c).unwrap(); @@ -46,7 +47,7 @@ fn to_buffer_correctly_serializes_virtual_channel_incomplete_capset() { #[test] fn to_buffer_correctly_serializes_virtual_channel_capset() { - let c = *VIRTUAL_CHANNEL; + let c = VIRTUAL_CHANNEL.clone(); let buffer = encode_vec(&c).unwrap(); diff --git a/crates/ironrdp-pdu/src/rdp/client_info.rs b/crates/ironrdp-pdu/src/rdp/client_info.rs index 4180fbec..3f8ff727 100644 --- a/crates/ironrdp-pdu/src/rdp/client_info.rs +++ b/crates/ironrdp-pdu/src/rdp/client_info.rs @@ -145,8 +145,9 @@ impl<'de> Decode<'de> for ClientInfo { let flags = ClientInfoFlags::from_bits(flags_with_compression_type & !COMPRESSION_TYPE_MASK) .ok_or_else(|| invalid_field_err!("flags", "invalid ClientInfoFlags"))?; - let compression_type = CompressionType::from_u32((flags_with_compression_type & COMPRESSION_TYPE_MASK) >> 9) - .ok_or_else(|| invalid_field_err!("flags", "invalid CompressionType"))?; + let compression_type = + CompressionType::from_u8(((flags_with_compression_type & COMPRESSION_TYPE_MASK) >> 9) as u8) + .ok_or_else(|| invalid_field_err!("flags", "invalid CompressionType"))?; let character_set = if flags.contains(ClientInfoFlags::UNICODE) { CharacterSet::Unicode @@ -156,11 +157,11 @@ impl<'de> Decode<'de> for ClientInfo { // Sizes exclude the length of the mandatory null terminator let nt = usize::from(character_set.as_u16()); - let domain_size = usize::from(src.read_u16()) + nt; - let user_name_size = usize::from(src.read_u16()) + nt; - let password_size = usize::from(src.read_u16()) + nt; - let alternate_shell_size = usize::from(src.read_u16()) + nt; - let work_dir_size = usize::from(src.read_u16()) + nt; + let domain_size = src.read_u16() as usize + nt; + let user_name_size = src.read_u16() as usize + nt; + let password_size = src.read_u16() as usize + nt; + let alternate_shell_size = src.read_u16() as usize + nt; + let work_dir_size = src.read_u16() as usize + nt; ensure_size!(in: src, size: domain_size + user_name_size + password_size + alternate_shell_size + work_dir_size); let domain = utils::decode_string(src.read_slice(domain_size), character_set, true)?; @@ -225,12 +226,12 @@ impl ExtendedClientInfo { let address_family = AddressFamily::from_u16(src.read_u16()); // This size includes the length of the mandatory null terminator. - let address_size = usize::from(src.read_u16()); + let address_size = src.read_u16() as usize; ensure_size!(in: src, size: address_size + CLIENT_DIR_LENGTH_SIZE); let address = utils::decode_string(src.read_slice(address_size), character_set, false)?; // This size includes the length of the mandatory null terminator. - let dir_size = usize::from(src.read_u16()); + let dir_size = src.read_u16() as usize; ensure_size!(in: src, size: dir_size); let dir = utils::decode_string(src.read_slice(dir_size), character_set, false)?; @@ -323,7 +324,7 @@ impl Encode for ExtendedClientOptionalInfo { dst.write_u32(performance_flags.bits()); } if let Some(reconnect_cookie) = self.reconnect_cookie { - dst.write_u16(u16::try_from(RECONNECT_COOKIE_LEN).expect("RECONNECT_COOKIE_LEN fit into u16")); + dst.write_u16(RECONNECT_COOKIE_LEN as u16); dst.write_array(reconnect_cookie); } @@ -380,9 +381,7 @@ impl<'de> Decode<'de> for ExtendedClientOptionalInfo { return Ok(optional_data); } let reconnect_cookie_size = src.read_u16(); - if reconnect_cookie_size != u16::try_from(RECONNECT_COOKIE_LEN).expect("RECONNECT_COOKIE_LEN fit into u16") - && reconnect_cookie_size != 0 - { + if reconnect_cookie_size != RECONNECT_COOKIE_LEN as u16 && reconnect_cookie_size != 0 { return Err(invalid_field_err!("cbAutoReconnectCookie", "invalid cookie size")); } if reconnect_cookie_size != 0 { diff --git a/crates/ironrdp-pdu/src/rdp/finalization_messages.rs b/crates/ironrdp-pdu/src/rdp/finalization_messages.rs index bea2710d..480066ba 100644 --- a/crates/ironrdp-pdu/src/rdp/finalization_messages.rs +++ b/crates/ironrdp-pdu/src/rdp/finalization_messages.rs @@ -220,10 +220,7 @@ impl<'de> Decode<'de> for MonitorLayoutPdu { return Err(invalid_field_err!("nMonitors", "invalid monitor count")); } - let mut monitors = Vec::with_capacity( - usize::try_from(monitor_count) - .expect("monitor_count is guaranteed to fit into usize due to the prior check"), - ); + let mut monitors = Vec::with_capacity(monitor_count as usize); for _ in 0..monitor_count { monitors.push(gcc::Monitor::decode(src)?); } diff --git a/crates/ironrdp-pdu/src/rdp/headers.rs b/crates/ironrdp-pdu/src/rdp/headers.rs index e97c8add..f469f52c 100644 --- a/crates/ironrdp-pdu/src/rdp/headers.rs +++ b/crates/ironrdp-pdu/src/rdp/headers.rs @@ -115,7 +115,7 @@ impl<'de> Decode<'de> for ShareControlHeader { fn decode(src: &mut ReadCursor<'de>) -> DecodeResult { ensure_fixed_part_size!(in: src); - let total_length = usize::from(src.read_u16()); + let total_length = src.read_u16() as usize; let pdu_type_with_version = src.read_u16(); let pdu_source = src.read_u16(); let share_id = src.read_u32(); diff --git a/crates/ironrdp-pdu/src/rdp/server_error_info.rs b/crates/ironrdp-pdu/src/rdp/server_error_info.rs index 28a51521..01b74bee 100644 --- a/crates/ironrdp-pdu/src/rdp/server_error_info.rs +++ b/crates/ironrdp-pdu/src/rdp/server_error_info.rs @@ -412,10 +412,6 @@ impl RdpSpecificCode { } } - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn as_u32(self) -> u32 { self as u32 } diff --git a/crates/ironrdp-pdu/src/rdp/server_license/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license.rs similarity index 97% rename from crates/ironrdp-pdu/src/rdp/server_license/mod.rs rename to crates/ironrdp-pdu/src/rdp/server_license.rs index 170ce33c..ee1b2bf0 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license.rs @@ -207,8 +207,6 @@ pub enum ServerLicenseError { Utf8Error(#[from] std::string::FromUtf8Error), #[error("DER error: {0}")] DerError(#[from] pkcs1::der::Error), - #[error("invalid `{0}`: out of range integral type conversion")] - InvalidField(&'static str), #[error("invalid preamble field: {0}")] InvalidPreamble(String), #[error("invalid preamble message type field")] @@ -340,10 +338,8 @@ impl<'de> Decode<'de> for BlobHeader { } } -fn compute_mac_data(mac_salt_key: &[u8], data: &[u8]) -> Result, ServerLicenseError> { - let data_len_buffer = u32::try_from(data.len()) - .map_err(|_| ServerLicenseError::InvalidField("MAC data length"))? - .to_le_bytes(); +fn compute_mac_data(mac_salt_key: &[u8], data: &[u8]) -> Vec { + let data_len_buffer = (data.len() as u32).to_le_bytes(); let pad_one: [u8; 40] = [0x36; 40]; @@ -364,7 +360,7 @@ fn compute_mac_data(mac_salt_key: &[u8], data: &[u8]) -> Result, ServerL .as_slice(), ); - Ok(md5.finalize().to_vec()) + md5.finalize().to_vec() } #[derive(Debug, PartialEq)] diff --git a/crates/ironrdp-pdu/src/rdp/server_license/client_license_info.rs b/crates/ironrdp-pdu/src/rdp/server_license/client_license_info.rs index 4c72032d..bec11af5 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/client_license_info.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/client_license_info.rs @@ -80,7 +80,7 @@ impl ClientLicenseInfo { let mut rc4 = Rc4::new(&license_key); let encrypted_hwid = rc4.process(&hardware_id); - let mac_data = compute_mac_data(mac_salt_key, &hardware_id)?; + let mac_data = compute_mac_data(mac_salt_key, &hardware_id); let size = RANDOM_NUMBER_SIZE + PREAMBLE_SIZE @@ -97,8 +97,7 @@ impl ClientLicenseInfo { preamble_message_type: PreambleType::LicenseInfo, preamble_flags: PreambleFlags::empty(), preamble_version: PreambleVersion::V3, - preamble_message_size: u16::try_from(size) - .map_err(|_| ServerLicenseError::InvalidField("preamble message size"))?, + preamble_message_size: (size) as u16, }; Ok(( diff --git a/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request.rs similarity index 94% rename from crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request/mod.rs rename to crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request.rs index adaacc86..1ae1d666 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request.rs @@ -98,17 +98,14 @@ impl ClientNewLicenseRequest { preamble_message_type: PreambleType::NewLicenseRequest, preamble_flags: PreambleFlags::empty(), preamble_version: PreambleVersion::V3, - preamble_message_size: u16::try_from( - RANDOM_NUMBER_SIZE - + PREAMBLE_SIZE - + LICENSE_REQUEST_STATIC_FIELDS_SIZE - + encrypted_premaster_secret.len() - + client_machine_name.len() - + UTF8_NULL_TERMINATOR_SIZE - + client_username.len() - + UTF8_NULL_TERMINATOR_SIZE, - ) - .map_err(|_| ServerLicenseError::InvalidField("preamble message size"))?, + preamble_message_size: (RANDOM_NUMBER_SIZE + + PREAMBLE_SIZE + + LICENSE_REQUEST_STATIC_FIELDS_SIZE + + encrypted_premaster_secret.len() + + client_machine_name.len() + + UTF8_NULL_TERMINATOR_SIZE + + client_username.len() + + UTF8_NULL_TERMINATOR_SIZE) as u16, }; Ok(( diff --git a/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request/tests.rs b/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request/tests.rs index 8d54c706..302285e5 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/client_new_license_request/tests.rs @@ -1,7 +1,6 @@ -use std::sync::LazyLock; - use byteorder::{LittleEndian, WriteBytesExt as _}; use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; use crate::rdp::server_license::server_license_request::cert::{CertificateType, X509CertificateChain}; @@ -60,8 +59,8 @@ const LICENSE_KEY_BUFFER: [u8; 16] = [ const CLIENT_USERNAME: &str = "sample-user"; const CLIENT_MACHINE_NAME: &str = "sample-machine-name"; -static CLIENT_NEW_LICENSE_REQUEST: LazyLock = LazyLock::new(|| { - ClientNewLicenseRequest { +lazy_static! { + pub static ref CLIENT_NEW_LICENSE_REQUEST: LicensePdu = ClientNewLicenseRequest { license_header: LicenseHeader { security_header: BasicSecurityHeader { flags: BasicSecurityHeaderFlags::LICENSE_PKT, @@ -69,238 +68,212 @@ static CLIENT_NEW_LICENSE_REQUEST: LazyLock = LazyLock::new(|| { preamble_message_type: PreambleType::NewLicenseRequest, preamble_flags: PreambleFlags::empty(), preamble_version: PreambleVersion::V3, - preamble_message_size: u16::try_from( - PREAMBLE_SIZE - + RANDOM_NUMBER_SIZE - + LICENSE_REQUEST_STATIC_FIELDS_SIZE - + ENCRYPTED_PREMASTER_SECRET.len() - + CLIENT_MACHINE_NAME.len() - + UTF8_NULL_TERMINATOR_SIZE - + CLIENT_USERNAME.len() - + UTF8_NULL_TERMINATOR_SIZE, - ) - .expect("can't panic"), + preamble_message_size: (PREAMBLE_SIZE + + RANDOM_NUMBER_SIZE + + LICENSE_REQUEST_STATIC_FIELDS_SIZE + + ENCRYPTED_PREMASTER_SECRET.len() + + CLIENT_MACHINE_NAME.len() + + UTF8_NULL_TERMINATOR_SIZE + + CLIENT_USERNAME.len() + + UTF8_NULL_TERMINATOR_SIZE) as u16, }, client_random: Vec::from(CLIENT_RANDOM_BUFFER.as_ref()), encrypted_premaster_secret: Vec::from(ENCRYPTED_PREMASTER_SECRET.as_ref()), client_username: CLIENT_USERNAME.to_owned(), client_machine_name: CLIENT_MACHINE_NAME.to_owned(), - } - .into() -}); + }.into(); -static REQUEST_BUFFER: LazyLock> = LazyLock::new(|| { - let username_len = CLIENT_USERNAME.len() + UTF8_NULL_TERMINATOR_SIZE; - let mut username_len_buf = Vec::new(); - username_len_buf - .write_u16::(u16::try_from(username_len).expect("can't panic")) - .unwrap(); + pub static ref REQUEST_BUFFER: Vec = { + let username_len = CLIENT_USERNAME.len() + UTF8_NULL_TERMINATOR_SIZE; + let mut username_len_buf = Vec::new(); + username_len_buf.write_u16::(username_len as u16).unwrap(); - let machine_name_len = CLIENT_MACHINE_NAME.len() + UTF8_NULL_TERMINATOR_SIZE; - let mut machine_name_len_buf = Vec::new(); - machine_name_len_buf - .write_u16::(u16::try_from(machine_name_len).unwrap()) - .unwrap(); + let machine_name_len = CLIENT_MACHINE_NAME.len() + UTF8_NULL_TERMINATOR_SIZE; + let mut machine_name_len_buf = Vec::new(); + machine_name_len_buf.write_u16::(machine_name_len as u16).unwrap(); - let buf = [ - &[ - 0x01u8, 0x00, 0x00, 0x00, // preferred_key_exchange_algorithm - 0x00, 0x00, 0x01, 0x04, - ], // platform_id - CLIENT_RANDOM_BUFFER.as_ref(), - &[ - 0x02, 0x00, // blob type - 0x48, 0x00, - ], // blob len - ENCRYPTED_PREMASTER_SECRET.as_ref(), - &[0x0f, 0x00], // blob type - username_len_buf.as_slice(), - CLIENT_USERNAME.as_bytes(), - &[ - 0x00, // null - 0x10, 0x00, - ], // blob type - machine_name_len_buf.as_slice(), // blob len - CLIENT_MACHINE_NAME.as_bytes(), - &[0x00], - ] // null - .concat(); + let buf = [ + &[0x01u8, 0x00, 0x00, 0x00, // preferred_key_exchange_algorithm + 0x00, 0x00, 0x01, 0x04], // platform_id + CLIENT_RANDOM_BUFFER.as_ref(), + &[0x02, 0x00, // blob type + 0x48, 0x00], // blob len + ENCRYPTED_PREMASTER_SECRET.as_ref(), + &[0x0f, 0x00], // blob type + username_len_buf.as_slice(), + CLIENT_USERNAME.as_bytes(), + &[0x00, // null + 0x10, 0x00], // blob type + machine_name_len_buf.as_slice(), // blob len + CLIENT_MACHINE_NAME.as_bytes(), + &[0x00]] // null + .concat(); - let preamble_size_field = u16::try_from(buf.len() + PREAMBLE_SIZE).expect("can't panic"); + let preamble_size_field = (buf.len() + PREAMBLE_SIZE) as u16; - [ - LICENSE_HEADER_BUFFER_NO_SIZE.as_ref(), - &preamble_size_field.to_le_bytes(), - buf.as_slice(), - ] - .concat() -}); - -pub(crate) static SERVER_LICENSE_REQUEST: LazyLock = LazyLock::new(|| { - let mut req = ServerLicenseRequest { - license_header: LicenseHeader { - security_header: BasicSecurityHeader { - flags: BasicSecurityHeaderFlags::LICENSE_PKT, - }, - preamble_message_type: PreambleType::LicenseRequest, - preamble_flags: PreambleFlags::empty(), - preamble_version: PreambleVersion::V3, - preamble_message_size: 0, - }, - server_random: Vec::from(SERVER_RANDOM_BUFFER.as_ref()), - product_info: ProductInfo { - version: 0x60000, - company_name: "Microsoft Corporation".to_owned(), - product_id: "A02".to_owned(), - }, - server_certificate: Some(ServerCertificate { - issued_permanently: true, - certificate: CertificateType::X509(X509CertificateChain { - certificate_array: vec![ - vec![ - 0x30, 0x82, 0x03, 0xda, 0x30, 0x82, 0x02, 0xc2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x7f, - 0x00, 0x00, 0x01, 0x76, 0x00, 0x8f, 0x08, 0x64, 0x08, 0x68, 0xa7, 0x63, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x76, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, - 0x00, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x50, 0x72, - 0x6f, 0x64, 0x32, 0x4c, 0x53, 0x52, 0x41, 0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d, - 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x30, 0x32, 0x36, 0x32, 0x32, 0x35, 0x33, 0x34, 0x30, - 0x5a, 0x17, 0x0d, 0x32, 0x37, 0x30, 0x36, 0x30, 0x36, 0x32, 0x30, 0x34, 0x32, 0x33, 0x38, 0x5a, - 0x30, 0x11, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x06, 0x42, 0x65, 0x63, - 0x6b, 0x65, 0x72, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, - 0x82, 0x01, 0x01, 0x00, 0xa8, 0x6b, 0xda, 0xae, 0x08, 0x1d, 0xc5, 0x05, 0x70, 0x7d, 0xa0, 0x41, - 0x46, 0xb4, 0x14, 0xcf, 0xfb, 0x8e, 0x09, 0x0b, 0x0a, 0x52, 0x8a, 0x7f, 0x7a, 0x35, 0xb6, 0xe3, - 0x0d, 0x1c, 0xbe, 0x49, 0x63, 0x41, 0x92, 0x86, 0x00, 0xa2, 0xd3, 0xff, 0x5b, 0x08, 0x7d, 0x2b, - 0x65, 0xe4, 0xc3, 0x09, 0x68, 0x72, 0x21, 0xc4, 0xd8, 0x0a, 0x21, 0x9e, 0x1f, 0xdf, 0xb2, 0xaa, - 0x2b, 0x42, 0x68, 0xe7, 0xeb, 0x52, 0xf8, 0x9e, 0xfc, 0x7f, 0x0f, 0x55, 0x26, 0x7d, 0x44, 0xfb, - 0x35, 0xe5, 0xc2, 0x2c, 0xb6, 0x8d, 0x06, 0xc5, 0xdc, 0xbf, 0x66, 0xf6, 0xb2, 0xf2, 0x9b, 0xe2, - 0x49, 0xaf, 0xfd, 0x4c, 0x69, 0x46, 0x72, 0xe0, 0x2f, 0x31, 0x77, 0x86, 0x7b, 0x5b, 0x6d, 0x49, - 0xe6, 0xc7, 0x84, 0xd1, 0xdd, 0x56, 0x89, 0x8d, 0xbd, 0x07, 0x18, 0x01, 0x43, 0x70, 0x9b, 0x00, - 0x71, 0x16, 0x89, 0x66, 0x2e, 0xb6, 0x5f, 0x62, 0xeb, 0x96, 0xed, 0xf2, 0xdb, 0xdb, 0xcf, 0xdd, - 0xa8, 0xab, 0xde, 0x93, 0xb3, 0xdb, 0x54, 0xf0, 0x34, 0x4a, 0x28, 0xc3, 0x11, 0xf6, 0xb9, 0xd6, - 0x45, 0x3f, 0x07, 0xc0, 0x8e, 0x10, 0x7a, 0x2b, 0x56, 0x15, 0xbb, 0x00, 0x9d, 0x82, 0x27, 0xf2, - 0x11, 0xa3, 0xda, 0x03, 0xaa, 0x51, 0xc0, 0xfd, 0x90, 0xc8, 0x73, 0x81, 0xce, 0x97, 0x30, 0xa2, - 0x54, 0x63, 0x6f, 0xfc, 0x7f, 0x5b, 0x71, 0xec, 0x11, 0xb0, 0xa0, 0xc8, 0x74, 0x3a, 0xcc, 0x1b, - 0x5e, 0xcd, 0x91, 0xa8, 0x18, 0x92, 0xeb, 0x33, 0xc4, 0x6d, 0xb8, 0x16, 0x67, 0xe1, 0xc5, 0xa6, - 0x26, 0x35, 0x48, 0xc4, 0xe7, 0x94, 0xeb, 0xbb, 0xb8, 0xde, 0xd3, 0xe1, 0xc0, 0xcb, 0x00, 0x20, - 0xf6, 0xbc, 0xa9, 0xc5, 0x70, 0xc4, 0xda, 0x1b, 0x61, 0x0b, 0x9f, 0x0b, 0x19, 0x93, 0xaf, 0x8f, - 0x40, 0xbb, 0x26, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x1d, 0x30, 0x82, 0x01, - 0x19, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa3, 0xda, 0xe5, 0xef, - 0xc3, 0x1c, 0x7a, 0xcf, 0x34, 0x2b, 0xa2, 0x42, 0x2b, 0x77, 0xcb, 0x62, 0xfb, 0x4c, 0x28, 0x51, - 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x9c, 0xe1, 0xad, - 0x8f, 0xd4, 0x86, 0xd2, 0x1c, 0x7e, 0x48, 0x32, 0xf2, 0x28, 0xfe, 0x87, 0x90, 0xe3, 0xb1, 0xc5, - 0x8e, 0x30, 0x4a, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x43, 0x30, 0x41, 0x30, 0x3f, 0xa0, 0x3d, - 0xa0, 0x3b, 0x86, 0x39, 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2f, 0x2f, 0x2f, 0x52, 0x44, 0x32, - 0x38, 0x31, 0x38, 0x37, 0x38, 0x30, 0x45, 0x33, 0x45, 0x45, 0x43, 0x2f, 0x43, 0x65, 0x72, 0x74, - 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x50, 0x72, 0x6f, 0x64, 0x32, 0x4c, 0x53, 0x52, 0x41, - 0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x64, 0x06, - 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x58, 0x30, 0x56, 0x30, 0x54, 0x06, - 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x48, 0x66, 0x69, 0x6c, 0x65, 0x3a, - 0x2f, 0x2f, 0x2f, 0x2f, 0x52, 0x44, 0x32, 0x38, 0x31, 0x38, 0x37, 0x38, 0x30, 0x45, 0x33, 0x45, - 0x45, 0x43, 0x2f, 0x43, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x52, 0x44, - 0x32, 0x38, 0x31, 0x38, 0x37, 0x38, 0x30, 0x45, 0x33, 0x45, 0x45, 0x43, 0x5f, 0x50, 0x72, 0x6f, - 0x64, 0x32, 0x4c, 0x53, 0x52, 0x41, 0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d, 0x2e, - 0x63, 0x72, 0x74, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, - 0x00, 0x30, 0x17, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x04, 0x0b, 0x16, - 0x09, 0x54, 0x4c, 0x53, 0x7e, 0x42, 0x41, 0x53, 0x49, 0x43, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, - 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x55, 0xd5, - 0x94, 0x3b, 0x06, 0xef, 0xf2, 0xb0, 0xf9, 0xd7, 0x36, 0x2a, 0x36, 0xe0, 0xf1, 0xd9, 0x18, 0xc1, - 0x89, 0x7e, 0xa2, 0xcf, 0x01, 0x6f, 0x22, 0x7b, 0x34, 0x81, 0xf0, 0x7a, 0x45, 0x11, 0x6e, 0x75, - 0x4b, 0x0b, 0xa8, 0xcd, 0x92, 0x57, 0x19, 0x80, 0xb7, 0x6e, 0x1a, 0x4d, 0x12, 0x65, 0x91, 0x56, - 0x38, 0x17, 0x22, 0xa2, 0x75, 0xae, 0xf9, 0x12, 0x75, 0x38, 0xf3, 0x19, 0x74, 0xea, 0x87, 0x46, - 0x1f, 0x98, 0x2c, 0x2f, 0xf9, 0xfc, 0xb4, 0xdc, 0x25, 0xa0, 0xd3, 0x34, 0x1b, 0xbc, 0x21, 0xbb, - 0x3d, 0x82, 0xad, 0x15, 0xc6, 0x3d, 0x02, 0x75, 0x33, 0x70, 0x25, 0x0a, 0x1a, 0xf7, 0x4c, 0xcb, - 0x84, 0xa3, 0xc1, 0x78, 0xe6, 0xf5, 0xa1, 0x44, 0x54, 0xc8, 0x34, 0xfd, 0xef, 0xbf, 0x86, 0x81, - 0x9d, 0x9a, 0x7e, 0xb6, 0xad, 0x71, 0x7e, 0xe4, 0xd9, 0x71, 0x6c, 0xb9, 0xe7, 0xf2, 0xd6, 0xd7, - 0xbb, 0x66, 0x5a, 0x30, 0xf5, 0x29, 0xae, 0x02, 0x39, 0x3d, 0xea, 0x7a, 0x79, 0x1b, 0x53, 0xc5, - 0xbe, 0x8d, 0xfb, 0xe2, 0xe4, 0x8e, 0xc2, 0x04, 0xb3, 0x0a, 0x94, 0x75, 0xa3, 0xbf, 0xd4, 0x87, - 0xd2, 0x74, 0x15, 0x05, 0x5e, 0xd5, 0x8f, 0x94, 0x23, 0x41, 0x13, 0x3f, 0xbd, 0xed, 0x21, 0x55, - 0x96, 0xe9, 0xc4, 0x93, 0x34, 0x7f, 0xaa, 0xea, 0xe7, 0xb1, 0x9a, 0xca, 0x25, 0x91, 0x18, 0xdf, - 0x28, 0x05, 0x8e, 0x53, 0xb3, 0x8c, 0x8d, 0xcc, 0xf3, 0xf4, 0x78, 0x76, 0x76, 0x7b, 0x82, 0xd6, - 0x75, 0x7a, 0x7d, 0xb3, 0x23, 0x2c, 0xc7, 0xbe, 0xa6, 0xb0, 0x50, 0x4d, 0x6c, 0xe2, 0x90, 0x85, - 0x97, 0x77, 0x0d, 0x2f, 0xf5, 0x7b, 0xb0, 0xc6, 0xad, 0xfa, 0x9a, 0x2c, 0xdf, 0xeb, 0x0d, 0x60, - 0xd3, 0x0e, 0xa8, 0x5c, 0x43, 0xab, 0x09, 0x85, 0xa3, 0xa9, 0x31, 0x66, 0xbd, 0xe4, - ], - vec![ - 0x30, 0x82, 0x04, 0x59, 0x30, 0x82, 0x03, 0x45, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x05, 0x01, - 0x00, 0x00, 0x00, 0x02, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, - 0x11, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x06, 0x42, 0x65, 0x63, 0x6b, - 0x65, 0x72, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x30, 0x32, 0x36, 0x32, 0x33, 0x32, 0x36, - 0x34, 0x35, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, 0x31, 0x39, 0x30, 0x33, 0x31, 0x34, 0x30, - 0x37, 0x5a, 0x30, 0x81, 0xa6, 0x31, 0x81, 0xa3, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x1e, - 0x20, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x69, 0x00, - 0x70, 0x00, 0x5f, 0x00, 0x74, 0x00, 0x63, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x32, 0x00, - 0x37, 0x30, 0x33, 0x06, 0x03, 0x55, 0x04, 0x07, 0x1e, 0x2c, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x61, - 0x00, 0x63, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x74, 0x00, 0x63, - 0x00, 0x70, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x32, 0x00, 0x37, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x2e, - 0x00, 0x30, 0x00, 0x2e, 0x00, 0x31, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x05, 0x1e, 0x3c, 0x00, - 0x31, 0x00, 0x42, 0x00, 0x63, 0x00, 0x4b, 0x00, 0x65, 0x00, 0x56, 0x00, 0x33, 0x00, 0x4d, 0x00, - 0x67, 0x00, 0x74, 0x00, 0x6a, 0x00, 0x55, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x32, 0x00, 0x50, 0x00, - 0x49, 0x00, 0x68, 0x00, 0x35, 0x00, 0x52, 0x00, 0x57, 0x00, 0x56, 0x00, 0x36, 0x00, 0x42, 0x00, - 0x58, 0x00, 0x48, 0x00, 0x77, 0x00, 0x3d, 0x00, 0x0d, 0x00, 0x0a, 0x30, 0x58, 0x30, 0x09, 0x06, - 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x0f, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, - 0xab, 0xac, 0x87, 0x11, 0x83, 0xbf, 0xe9, 0x48, 0x25, 0x00, 0x2c, 0x33, 0x31, 0x5e, 0x3d, 0x78, - 0xc8, 0x5f, 0x82, 0xcb, 0x36, 0x41, 0xf5, 0xb4, 0x65, 0x15, 0xee, 0x04, 0x31, 0xae, 0xe2, 0x48, - 0x58, 0x99, 0x7f, 0x4f, 0x90, 0x1d, 0xf7, 0x7c, 0xd7, 0xf8, 0x47, 0x93, 0xa0, 0xca, 0x9c, 0xdf, - 0x91, 0xb0, 0x41, 0xe8, 0x05, 0x4b, 0xdc, 0x24, 0x5b, 0x72, 0xf7, 0x68, 0x91, 0x84, 0xfb, 0x19, - 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xf4, 0x30, 0x82, 0x01, 0xf0, 0x30, 0x14, 0x06, - 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x04, 0x01, 0x01, 0xff, 0x04, 0x04, 0x01, - 0x00, 0x05, 0x00, 0x30, 0x3c, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x02, - 0x01, 0x01, 0xff, 0x04, 0x2c, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, - 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, - 0x00, 0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x00, - 0x00, 0x30, 0x81, 0xdd, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x05, 0x01, - 0x01, 0xff, 0x04, 0x81, 0xcc, 0x00, 0x30, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x22, 0x04, 0x00, 0x00, 0x1c, 0x00, 0x4a, 0x00, 0x66, 0x00, 0x4a, 0x00, 0xb0, 0x00, 0x03, - 0x00, 0x33, 0x00, 0x64, 0x00, 0x32, 0x00, 0x36, 0x00, 0x37, 0x00, 0x39, 0x00, 0x35, 0x00, 0x34, - 0x00, 0x2d, 0x00, 0x65, 0x00, 0x65, 0x00, 0x62, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x31, - 0x00, 0x64, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x62, 0x00, 0x39, 0x00, 0x34, 0x00, 0x65, 0x00, 0x2d, - 0x00, 0x30, 0x00, 0x30, 0x00, 0x63, 0x00, 0x30, 0x00, 0x34, 0x00, 0x66, 0x00, 0x61, 0x00, 0x33, - 0x00, 0x30, 0x00, 0x38, 0x00, 0x30, 0x00, 0x64, 0x00, 0x00, 0x00, 0x33, 0x00, 0x64, 0x00, 0x32, - 0x00, 0x36, 0x00, 0x37, 0x00, 0x39, 0x00, 0x35, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x65, 0x00, 0x65, - 0x00, 0x62, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x31, 0x00, 0x64, 0x00, 0x31, 0x00, 0x2d, - 0x00, 0x62, 0x00, 0x39, 0x00, 0x34, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x63, - 0x00, 0x30, 0x00, 0x34, 0x00, 0x66, 0x00, 0x61, 0x00, 0x33, 0x00, 0x30, 0x00, 0x38, 0x00, 0x30, - 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x30, 0x81, 0x80, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x06, 0x01, - 0x01, 0xff, 0x04, 0x70, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x57, 0x00, - 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x34, 0x00, 0x4c, 0x00, 0x34, 0x00, 0x4c, 0x00, 0x36, 0x00, - 0x41, 0x00, 0x4d, 0x00, 0x42, 0x00, 0x43, 0x00, 0x53, 0x00, 0x51, 0x00, 0x00, 0x00, 0x30, 0x00, - 0x30, 0x00, 0x34, 0x00, 0x32, 0x00, 0x39, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, - 0x30, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x33, 0x00, 0x34, 0x00, 0x39, 0x00, 0x37, 0x00, 0x32, 0x00, - 0x2d, 0x00, 0x41, 0x00, 0x54, 0x00, 0x33, 0x00, 0x35, 0x00, 0x33, 0x00, 0x00, 0x00, 0x57, 0x00, - 0x4f, 0x00, 0x52, 0x00, 0x4b, 0x00, 0x47, 0x00, 0x52, 0x00, 0x4f, 0x00, 0x55, 0x00, 0x50, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x30, 0x37, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x01, 0x01, 0xff, 0x04, 0x2d, - 0x30, 0x2b, 0xa1, 0x22, 0xa4, 0x20, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x34, 0x00, - 0x4c, 0x00, 0x34, 0x00, 0x4c, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x42, 0x00, 0x43, 0x00, - 0x53, 0x00, 0x51, 0x00, 0x00, 0x00, 0x82, 0x05, 0x01, 0x00, 0x00, 0x00, 0x02, 0x30, 0x09, 0x06, - 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3e, 0xd3, 0xd5, - 0x61, 0x8a, 0x87, 0x7b, 0x98, 0x2c, 0x6d, 0x20, 0x38, 0x12, 0x08, 0xd8, 0xf7, 0x83, 0x08, 0xf8, - 0xe6, 0xb2, 0xe1, 0x21, 0xe1, 0x30, 0x61, 0x12, 0x19, 0xe8, 0xc1, 0x41, 0xaf, 0x59, 0x7c, 0x1e, - 0x3e, 0xc8, 0x40, 0x9e, 0x24, 0xe8, 0x8d, 0x0c, 0x41, 0xfd, 0xf8, 0x3e, 0xa1, 0xb3, 0xac, 0x56, - 0xac, 0x52, 0x91, 0x5a, 0xf8, 0xd0, 0x40, 0x8e, 0x13, 0x47, 0xa9, 0x8a, 0x0a, 0x62, 0x6d, 0x11, - 0x89, 0x20, 0x56, 0xe7, 0xd6, 0x5f, 0x12, 0x44, 0x94, 0xbf, 0x63, 0x99, 0xa3, 0x42, 0x40, 0xd5, - 0xc6, 0x8c, 0x1f, 0x4b, 0xf8, 0xaf, 0x83, 0x8e, 0xf6, 0x74, 0xb2, 0x0b, 0x55, 0x13, 0x4a, 0x76, - 0xed, 0x37, 0xd8, 0x3d, 0x13, 0xe7, 0xae, 0x43, 0x4c, 0x9a, 0x61, 0x6c, 0x7b, 0x1b, 0xd1, 0xaa, - 0x00, 0x97, 0xdf, 0x5b, 0x85, 0x9f, 0xc8, 0xee, 0x6c, 0xe5, 0xa2, 0x63, 0x76, 0xe4, 0x06, 0xd3, - 0x2a, 0xe0, 0x55, 0xe1, 0x92, 0x78, 0xed, 0x03, 0x7b, 0x7d, 0x1a, 0x6e, 0xc2, 0x56, 0xdc, 0xad, - 0x6e, 0xd7, 0xa9, 0xfe, 0xa7, 0xfd, 0x09, 0x0a, 0xa6, 0xd5, 0x8a, 0x99, 0xa4, 0x75, 0x89, 0xad, - 0x84, 0xc7, 0x09, 0xf7, 0x4c, 0x6e, 0xd0, 0xe2, 0x80, 0x17, 0x62, 0xfa, 0x86, 0xfe, 0x43, 0x51, - 0xf2, 0xb4, 0xf6, 0xef, 0x3b, 0xb3, 0x3d, 0x1f, 0xef, 0xa3, 0xcb, 0xa2, 0x57, 0x25, 0x7c, 0x02, - 0xf2, 0x27, 0x1c, 0x87, 0x70, 0x8e, 0x84, 0x20, 0xfe, 0x1d, 0x4a, 0xc4, 0x87, 0x24, 0x3b, 0xba, - 0xff, 0x34, 0x1a, 0xe2, 0xff, 0xa2, 0x43, 0x39, 0xd8, 0x19, 0x97, 0xf8, 0xf0, 0xf9, 0x73, 0xa6, - 0xb6, 0x55, 0x64, 0xa6, 0xca, 0xa3, 0x48, 0x22, 0xb7, 0x1a, 0x9b, 0x98, 0x1a, 0x8e, 0x2f, 0xaa, - 0xec, 0xc1, 0xfe, 0x25, 0x36, 0x2b, 0x70, 0x97, 0x8c, 0x5b, 0x62, 0x21, 0xc3, - ], - ], - }), - }), - scope_list: vec![Scope(String::from("microsoft.com"))], + [ + LICENSE_HEADER_BUFFER_NO_SIZE.as_ref(), + &preamble_size_field.to_le_bytes(), + buf.as_slice() + ] + .concat() }; - req.license_header.preamble_message_size = u16::try_from(req.size()).expect("can't panic"); - req.into() -}); + + pub(crate) static ref SERVER_LICENSE_REQUEST: LicensePdu = { + let mut req = ServerLicenseRequest { + license_header: LicenseHeader { + security_header: BasicSecurityHeader { + flags: BasicSecurityHeaderFlags::LICENSE_PKT, + }, + preamble_message_type: PreambleType::LicenseRequest, + preamble_flags: PreambleFlags::empty(), + preamble_version: PreambleVersion::V3, + preamble_message_size: 0, + }, + server_random: Vec::from(SERVER_RANDOM_BUFFER.as_ref()), + product_info: ProductInfo { + version: 0x60000, + company_name: "Microsoft Corporation".to_owned(), + product_id: "A02".to_owned(), + }, + server_certificate: Some(ServerCertificate { + issued_permanently: true, + certificate: CertificateType::X509(X509CertificateChain { + certificate_array: vec![ + vec![0x30, 0x82, 0x03, 0xda, 0x30, 0x82, 0x02, 0xc2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x7f, + 0x00, 0x00, 0x01, 0x76, 0x00, 0x8f, 0x08, 0x64, 0x08, 0x68, 0xa7, 0x63, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x76, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, + 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x50, 0x72, 0x6f, 0x64, 0x32, + 0x4c, 0x53, 0x52, 0x41, 0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d, 0x30, 0x1e, 0x17, 0x0d, + 0x31, 0x39, 0x31, 0x30, 0x32, 0x36, 0x32, 0x32, 0x35, 0x33, 0x34, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x37, + 0x30, 0x36, 0x30, 0x36, 0x32, 0x30, 0x34, 0x32, 0x33, 0x38, 0x5a, 0x30, 0x11, 0x31, 0x0f, 0x30, 0x0d, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x06, 0x42, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, + 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa8, 0x6b, 0xda, 0xae, 0x08, + 0x1d, 0xc5, 0x05, 0x70, 0x7d, 0xa0, 0x41, 0x46, 0xb4, 0x14, 0xcf, 0xfb, 0x8e, 0x09, 0x0b, 0x0a, 0x52, + 0x8a, 0x7f, 0x7a, 0x35, 0xb6, 0xe3, 0x0d, 0x1c, 0xbe, 0x49, 0x63, 0x41, 0x92, 0x86, 0x00, 0xa2, 0xd3, + 0xff, 0x5b, 0x08, 0x7d, 0x2b, 0x65, 0xe4, 0xc3, 0x09, 0x68, 0x72, 0x21, 0xc4, 0xd8, 0x0a, 0x21, 0x9e, + 0x1f, 0xdf, 0xb2, 0xaa, 0x2b, 0x42, 0x68, 0xe7, 0xeb, 0x52, 0xf8, 0x9e, 0xfc, 0x7f, 0x0f, 0x55, 0x26, + 0x7d, 0x44, 0xfb, 0x35, 0xe5, 0xc2, 0x2c, 0xb6, 0x8d, 0x06, 0xc5, 0xdc, 0xbf, 0x66, 0xf6, 0xb2, 0xf2, + 0x9b, 0xe2, 0x49, 0xaf, 0xfd, 0x4c, 0x69, 0x46, 0x72, 0xe0, 0x2f, 0x31, 0x77, 0x86, 0x7b, 0x5b, 0x6d, + 0x49, 0xe6, 0xc7, 0x84, 0xd1, 0xdd, 0x56, 0x89, 0x8d, 0xbd, 0x07, 0x18, 0x01, 0x43, 0x70, 0x9b, 0x00, + 0x71, 0x16, 0x89, 0x66, 0x2e, 0xb6, 0x5f, 0x62, 0xeb, 0x96, 0xed, 0xf2, 0xdb, 0xdb, 0xcf, 0xdd, 0xa8, + 0xab, 0xde, 0x93, 0xb3, 0xdb, 0x54, 0xf0, 0x34, 0x4a, 0x28, 0xc3, 0x11, 0xf6, 0xb9, 0xd6, 0x45, 0x3f, + 0x07, 0xc0, 0x8e, 0x10, 0x7a, 0x2b, 0x56, 0x15, 0xbb, 0x00, 0x9d, 0x82, 0x27, 0xf2, 0x11, 0xa3, 0xda, + 0x03, 0xaa, 0x51, 0xc0, 0xfd, 0x90, 0xc8, 0x73, 0x81, 0xce, 0x97, 0x30, 0xa2, 0x54, 0x63, 0x6f, 0xfc, + 0x7f, 0x5b, 0x71, 0xec, 0x11, 0xb0, 0xa0, 0xc8, 0x74, 0x3a, 0xcc, 0x1b, 0x5e, 0xcd, 0x91, 0xa8, 0x18, + 0x92, 0xeb, 0x33, 0xc4, 0x6d, 0xb8, 0x16, 0x67, 0xe1, 0xc5, 0xa6, 0x26, 0x35, 0x48, 0xc4, 0xe7, 0x94, + 0xeb, 0xbb, 0xb8, 0xde, 0xd3, 0xe1, 0xc0, 0xcb, 0x00, 0x20, 0xf6, 0xbc, 0xa9, 0xc5, 0x70, 0xc4, 0xda, + 0x1b, 0x61, 0x0b, 0x9f, 0x0b, 0x19, 0x93, 0xaf, 0x8f, 0x40, 0xbb, 0x26, 0x79, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x82, 0x01, 0x1d, 0x30, 0x82, 0x01, 0x19, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0xa3, 0xda, 0xe5, 0xef, 0xc3, 0x1c, 0x7a, 0xcf, 0x34, 0x2b, 0xa2, 0x42, 0x2b, 0x77, + 0xcb, 0x62, 0xfb, 0x4c, 0x28, 0x51, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, + 0x80, 0x14, 0x9c, 0xe1, 0xad, 0x8f, 0xd4, 0x86, 0xd2, 0x1c, 0x7e, 0x48, 0x32, 0xf2, 0x28, 0xfe, 0x87, + 0x90, 0xe3, 0xb1, 0xc5, 0x8e, 0x30, 0x4a, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x43, 0x30, 0x41, 0x30, + 0x3f, 0xa0, 0x3d, 0xa0, 0x3b, 0x86, 0x39, 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2f, 0x2f, 0x2f, 0x52, + 0x44, 0x32, 0x38, 0x31, 0x38, 0x37, 0x38, 0x30, 0x45, 0x33, 0x45, 0x45, 0x43, 0x2f, 0x43, 0x65, 0x72, + 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x50, 0x72, 0x6f, 0x64, 0x32, 0x4c, 0x53, 0x52, 0x41, + 0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x64, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x58, 0x30, 0x56, 0x30, 0x54, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x48, 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2f, 0x2f, + 0x2f, 0x52, 0x44, 0x32, 0x38, 0x31, 0x38, 0x37, 0x38, 0x30, 0x45, 0x33, 0x45, 0x45, 0x43, 0x2f, 0x43, + 0x65, 0x72, 0x74, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x52, 0x44, 0x32, 0x38, 0x31, 0x38, 0x37, + 0x38, 0x30, 0x45, 0x33, 0x45, 0x45, 0x43, 0x5f, 0x50, 0x72, 0x6f, 0x64, 0x32, 0x4c, 0x53, 0x52, 0x41, + 0x73, 0x68, 0x61, 0x32, 0x52, 0x44, 0x53, 0x4c, 0x4d, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0c, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x17, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0x82, 0x37, 0x12, 0x04, 0x0b, 0x16, 0x09, 0x54, 0x4c, 0x53, 0x7e, 0x42, 0x41, 0x53, 0x49, + 0x43, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x01, 0x00, 0x55, 0xd5, 0x94, 0x3b, 0x06, 0xef, 0xf2, 0xb0, 0xf9, 0xd7, 0x36, 0x2a, 0x36, + 0xe0, 0xf1, 0xd9, 0x18, 0xc1, 0x89, 0x7e, 0xa2, 0xcf, 0x01, 0x6f, 0x22, 0x7b, 0x34, 0x81, 0xf0, 0x7a, + 0x45, 0x11, 0x6e, 0x75, 0x4b, 0x0b, 0xa8, 0xcd, 0x92, 0x57, 0x19, 0x80, 0xb7, 0x6e, 0x1a, 0x4d, 0x12, + 0x65, 0x91, 0x56, 0x38, 0x17, 0x22, 0xa2, 0x75, 0xae, 0xf9, 0x12, 0x75, 0x38, 0xf3, 0x19, 0x74, 0xea, + 0x87, 0x46, 0x1f, 0x98, 0x2c, 0x2f, 0xf9, 0xfc, 0xb4, 0xdc, 0x25, 0xa0, 0xd3, 0x34, 0x1b, 0xbc, 0x21, + 0xbb, 0x3d, 0x82, 0xad, 0x15, 0xc6, 0x3d, 0x02, 0x75, 0x33, 0x70, 0x25, 0x0a, 0x1a, 0xf7, 0x4c, 0xcb, + 0x84, 0xa3, 0xc1, 0x78, 0xe6, 0xf5, 0xa1, 0x44, 0x54, 0xc8, 0x34, 0xfd, 0xef, 0xbf, 0x86, 0x81, 0x9d, + 0x9a, 0x7e, 0xb6, 0xad, 0x71, 0x7e, 0xe4, 0xd9, 0x71, 0x6c, 0xb9, 0xe7, 0xf2, 0xd6, 0xd7, 0xbb, 0x66, + 0x5a, 0x30, 0xf5, 0x29, 0xae, 0x02, 0x39, 0x3d, 0xea, 0x7a, 0x79, 0x1b, 0x53, 0xc5, 0xbe, 0x8d, 0xfb, + 0xe2, 0xe4, 0x8e, 0xc2, 0x04, 0xb3, 0x0a, 0x94, 0x75, 0xa3, 0xbf, 0xd4, 0x87, 0xd2, 0x74, 0x15, 0x05, + 0x5e, 0xd5, 0x8f, 0x94, 0x23, 0x41, 0x13, 0x3f, 0xbd, 0xed, 0x21, 0x55, 0x96, 0xe9, 0xc4, 0x93, 0x34, + 0x7f, 0xaa, 0xea, 0xe7, 0xb1, 0x9a, 0xca, 0x25, 0x91, 0x18, 0xdf, 0x28, 0x05, 0x8e, 0x53, 0xb3, 0x8c, + 0x8d, 0xcc, 0xf3, 0xf4, 0x78, 0x76, 0x76, 0x7b, 0x82, 0xd6, 0x75, 0x7a, 0x7d, 0xb3, 0x23, 0x2c, 0xc7, + 0xbe, 0xa6, 0xb0, 0x50, 0x4d, 0x6c, 0xe2, 0x90, 0x85, 0x97, 0x77, 0x0d, 0x2f, 0xf5, 0x7b, 0xb0, 0xc6, + 0xad, 0xfa, 0x9a, 0x2c, 0xdf, 0xeb, 0x0d, 0x60, 0xd3, 0x0e, 0xa8, 0x5c, 0x43, 0xab, 0x09, 0x85, 0xa3, + 0xa9, 0x31, 0x66, 0xbd, 0xe4], + vec![0x30, 0x82, 0x04, 0x59, 0x30, 0x82, 0x03, 0x45, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x05, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x30, 0x11, + 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x06, 0x42, 0x65, 0x63, 0x6b, 0x65, 0x72, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x30, 0x32, 0x36, 0x32, 0x33, 0x32, 0x36, 0x34, 0x35, 0x5a, + 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, 0x31, 0x39, 0x30, 0x33, 0x31, 0x34, 0x30, 0x37, 0x5a, 0x30, 0x81, + 0xa6, 0x31, 0x81, 0xa3, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x1e, 0x20, 0x00, 0x6e, 0x00, 0x63, + 0x00, 0x61, 0x00, 0x63, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x69, 0x00, 0x70, 0x00, 0x5f, 0x00, 0x74, 0x00, + 0x63, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x32, 0x00, 0x37, 0x30, 0x33, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x1e, 0x2c, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6e, 0x00, 0x5f, 0x00, 0x69, + 0x00, 0x70, 0x00, 0x5f, 0x00, 0x74, 0x00, 0x63, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x32, 0x00, + 0x37, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x31, 0x30, 0x43, 0x06, 0x03, + 0x55, 0x04, 0x05, 0x1e, 0x3c, 0x00, 0x31, 0x00, 0x42, 0x00, 0x63, 0x00, 0x4b, 0x00, 0x65, 0x00, 0x56, + 0x00, 0x33, 0x00, 0x4d, 0x00, 0x67, 0x00, 0x74, 0x00, 0x6a, 0x00, 0x55, 0x00, 0x74, 0x00, 0x6f, 0x00, + 0x32, 0x00, 0x50, 0x00, 0x49, 0x00, 0x68, 0x00, 0x35, 0x00, 0x52, 0x00, 0x57, 0x00, 0x56, 0x00, 0x36, + 0x00, 0x42, 0x00, 0x58, 0x00, 0x48, 0x00, 0x77, 0x00, 0x3d, 0x00, 0x0d, 0x00, 0x0a, 0x30, 0x58, 0x30, + 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x0f, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, + 0x00, 0xab, 0xac, 0x87, 0x11, 0x83, 0xbf, 0xe9, 0x48, 0x25, 0x00, 0x2c, 0x33, 0x31, 0x5e, 0x3d, 0x78, + 0xc8, 0x5f, 0x82, 0xcb, 0x36, 0x41, 0xf5, 0xb4, 0x65, 0x15, 0xee, 0x04, 0x31, 0xae, 0xe2, 0x48, 0x58, + 0x99, 0x7f, 0x4f, 0x90, 0x1d, 0xf7, 0x7c, 0xd7, 0xf8, 0x47, 0x93, 0xa0, 0xca, 0x9c, 0xdf, 0x91, 0xb0, + 0x41, 0xe8, 0x05, 0x4b, 0xdc, 0x24, 0x5b, 0x72, 0xf7, 0x68, 0x91, 0x84, 0xfb, 0x19, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0xf4, 0x30, 0x82, 0x01, 0xf0, 0x30, 0x14, 0x06, 0x09, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0x82, 0x37, 0x12, 0x04, 0x01, 0x01, 0xff, 0x04, 0x04, 0x01, 0x00, 0x05, 0x00, 0x30, 0x3c, + 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x02, 0x01, 0x01, 0xff, 0x04, 0x2c, 0x4d, + 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, + 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, + 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x30, 0x81, 0xdd, 0x06, 0x09, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0x82, 0x37, 0x12, 0x05, 0x01, 0x01, 0xff, 0x04, 0x81, 0xcc, 0x00, 0x30, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x22, 0x04, 0x00, 0x00, 0x1c, 0x00, 0x4a, 0x00, 0x66, 0x00, + 0x4a, 0x00, 0xb0, 0x00, 0x03, 0x00, 0x33, 0x00, 0x64, 0x00, 0x32, 0x00, 0x36, 0x00, 0x37, 0x00, 0x39, + 0x00, 0x35, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x65, 0x00, 0x65, 0x00, 0x62, 0x00, 0x37, 0x00, 0x2d, 0x00, + 0x31, 0x00, 0x31, 0x00, 0x64, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x62, 0x00, 0x39, 0x00, 0x34, 0x00, 0x65, + 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x63, 0x00, 0x30, 0x00, 0x34, 0x00, 0x66, 0x00, 0x61, 0x00, + 0x33, 0x00, 0x30, 0x00, 0x38, 0x00, 0x30, 0x00, 0x64, 0x00, 0x00, 0x00, 0x33, 0x00, 0x64, 0x00, 0x32, + 0x00, 0x36, 0x00, 0x37, 0x00, 0x39, 0x00, 0x35, 0x00, 0x34, 0x00, 0x2d, 0x00, 0x65, 0x00, 0x65, 0x00, + 0x62, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x31, 0x00, 0x64, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x62, + 0x00, 0x39, 0x00, 0x34, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x30, 0x00, 0x63, 0x00, 0x30, 0x00, + 0x34, 0x00, 0x66, 0x00, 0x61, 0x00, 0x33, 0x00, 0x30, 0x00, 0x38, 0x00, 0x30, 0x00, 0x64, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x06, 0x09, + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x12, 0x06, 0x01, 0x01, 0xff, 0x04, 0x70, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x34, 0x00, + 0x4c, 0x00, 0x34, 0x00, 0x4c, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x42, 0x00, 0x43, 0x00, 0x53, + 0x00, 0x51, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x34, 0x00, 0x32, 0x00, 0x39, 0x00, 0x2d, 0x00, + 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x2d, 0x00, 0x33, 0x00, 0x34, 0x00, 0x39, + 0x00, 0x37, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x41, 0x00, 0x54, 0x00, 0x33, 0x00, 0x35, 0x00, 0x33, 0x00, + 0x00, 0x00, 0x57, 0x00, 0x4f, 0x00, 0x52, 0x00, 0x4b, 0x00, 0x47, 0x00, 0x52, 0x00, 0x4f, 0x00, 0x55, + 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x37, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x01, 0x01, 0xff, + 0x04, 0x2d, 0x30, 0x2b, 0xa1, 0x22, 0xa4, 0x20, 0x57, 0x00, 0x49, 0x00, 0x4e, 0x00, 0x2d, 0x00, 0x34, + 0x00, 0x4c, 0x00, 0x34, 0x00, 0x4c, 0x00, 0x36, 0x00, 0x41, 0x00, 0x4d, 0x00, 0x42, 0x00, 0x43, 0x00, + 0x53, 0x00, 0x51, 0x00, 0x00, 0x00, 0x82, 0x05, 0x01, 0x00, 0x00, 0x00, 0x02, 0x30, 0x09, 0x06, 0x05, + 0x2b, 0x0e, 0x03, 0x02, 0x1d, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3e, 0xd3, 0xd5, 0x61, 0x8a, + 0x87, 0x7b, 0x98, 0x2c, 0x6d, 0x20, 0x38, 0x12, 0x08, 0xd8, 0xf7, 0x83, 0x08, 0xf8, 0xe6, 0xb2, 0xe1, + 0x21, 0xe1, 0x30, 0x61, 0x12, 0x19, 0xe8, 0xc1, 0x41, 0xaf, 0x59, 0x7c, 0x1e, 0x3e, 0xc8, 0x40, 0x9e, + 0x24, 0xe8, 0x8d, 0x0c, 0x41, 0xfd, 0xf8, 0x3e, 0xa1, 0xb3, 0xac, 0x56, 0xac, 0x52, 0x91, 0x5a, 0xf8, + 0xd0, 0x40, 0x8e, 0x13, 0x47, 0xa9, 0x8a, 0x0a, 0x62, 0x6d, 0x11, 0x89, 0x20, 0x56, 0xe7, 0xd6, 0x5f, + 0x12, 0x44, 0x94, 0xbf, 0x63, 0x99, 0xa3, 0x42, 0x40, 0xd5, 0xc6, 0x8c, 0x1f, 0x4b, 0xf8, 0xaf, 0x83, + 0x8e, 0xf6, 0x74, 0xb2, 0x0b, 0x55, 0x13, 0x4a, 0x76, 0xed, 0x37, 0xd8, 0x3d, 0x13, 0xe7, 0xae, 0x43, + 0x4c, 0x9a, 0x61, 0x6c, 0x7b, 0x1b, 0xd1, 0xaa, 0x00, 0x97, 0xdf, 0x5b, 0x85, 0x9f, 0xc8, 0xee, 0x6c, + 0xe5, 0xa2, 0x63, 0x76, 0xe4, 0x06, 0xd3, 0x2a, 0xe0, 0x55, 0xe1, 0x92, 0x78, 0xed, 0x03, 0x7b, 0x7d, + 0x1a, 0x6e, 0xc2, 0x56, 0xdc, 0xad, 0x6e, 0xd7, 0xa9, 0xfe, 0xa7, 0xfd, 0x09, 0x0a, 0xa6, 0xd5, 0x8a, + 0x99, 0xa4, 0x75, 0x89, 0xad, 0x84, 0xc7, 0x09, 0xf7, 0x4c, 0x6e, 0xd0, 0xe2, 0x80, 0x17, 0x62, 0xfa, + 0x86, 0xfe, 0x43, 0x51, 0xf2, 0xb4, 0xf6, 0xef, 0x3b, 0xb3, 0x3d, 0x1f, 0xef, 0xa3, 0xcb, 0xa2, 0x57, + 0x25, 0x7c, 0x02, 0xf2, 0x27, 0x1c, 0x87, 0x70, 0x8e, 0x84, 0x20, 0xfe, 0x1d, 0x4a, 0xc4, 0x87, 0x24, + 0x3b, 0xba, 0xff, 0x34, 0x1a, 0xe2, 0xff, 0xa2, 0x43, 0x39, 0xd8, 0x19, 0x97, 0xf8, 0xf0, 0xf9, 0x73, + 0xa6, 0xb6, 0x55, 0x64, 0xa6, 0xca, 0xa3, 0x48, 0x22, 0xb7, 0x1a, 0x9b, 0x98, 0x1a, 0x8e, 0x2f, 0xaa, + 0xec, 0xc1, 0xfe, 0x25, 0x36, 0x2b, 0x70, 0x97, 0x8c, 0x5b, 0x62, 0x21, 0xc3], + ], + }), + }), + scope_list: vec![Scope(String::from("microsoft.com"))], + }; + req.license_header.preamble_message_size = req.size() as u16; + req.into() + }; +} #[test] fn from_buffer_correctly_parses_client_new_license_request() { diff --git a/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response.rs similarity index 95% rename from crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response/mod.rs rename to crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response.rs index d00e068a..0bf408bf 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response.rs @@ -46,7 +46,7 @@ impl ClientPlatformChallengeResponse { let decrypted_challenge = rc4.process(platform_challenge.encrypted_platform_challenge.as_slice()); let decrypted_challenge_mac = - super::compute_mac_data(encryption_data.mac_salt_key.as_slice(), decrypted_challenge.as_slice())?; + super::compute_mac_data(encryption_data.mac_salt_key.as_slice(), decrypted_challenge.as_slice()); if decrypted_challenge_mac != platform_challenge.mac_data { return Err(ServerLicenseError::InvalidMacData); @@ -56,10 +56,7 @@ impl ClientPlatformChallengeResponse { challenge_response_data.write_u16::(RESPONSE_DATA_VERSION)?; challenge_response_data.write_u16::(ClientType::Other.as_u16())?; challenge_response_data.write_u16::(LicenseDetailLevel::Detail.as_u16())?; - challenge_response_data.write_u16::( - u16::try_from(decrypted_challenge.len()) - .map_err(|_| ServerLicenseError::InvalidField("decrypted challenge len"))?, - )?; + challenge_response_data.write_u16::(decrypted_challenge.len() as u16)?; challenge_response_data.write_all(&decrypted_challenge)?; let mut hardware_id = Vec::with_capacity(CLIENT_HARDWARE_IDENTIFICATION_SIZE); @@ -78,7 +75,7 @@ impl ClientPlatformChallengeResponse { let mac_data = super::compute_mac_data( encryption_data.mac_salt_key.as_slice(), challenge_response_data.as_slice(), - )?; + ); let license_header = LicenseHeader { security_header: BasicSecurityHeader { @@ -87,12 +84,10 @@ impl ClientPlatformChallengeResponse { preamble_message_type: PreambleType::PlatformChallengeResponse, preamble_flags: PreambleFlags::empty(), preamble_version: PreambleVersion::V3, - preamble_message_size: u16::try_from( - PREAMBLE_SIZE + preamble_message_size: (PREAMBLE_SIZE + (BLOB_TYPE_SIZE + BLOB_LENGTH_SIZE) * 2 // 2 blobs in this structure - + MAC_SIZE + encrypted_challenge_response_data.len() + encrypted_hwid.len(), - ) - .map_err(|_| ServerLicenseError::InvalidField("preamble message size"))?, + + MAC_SIZE + encrypted_challenge_response_data.len() + encrypted_hwid.len()) + as u16, }; Ok(Self { diff --git a/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response/test.rs b/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response/test.rs index d086f954..ce298e81 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response/test.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/client_platform_challenge_response/test.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; use crate::rdp::server_license::{LicensePdu, BASIC_SECURITY_HEADER_SIZE}; @@ -45,37 +44,35 @@ const DATA_BUFFER: [u8; 16] = [ 0xf1, 0x59, 0x87, 0x3e, 0xc9, 0xd8, 0x98, 0xaf, 0x24, 0x02, 0xf8, 0xf3, 0x29, 0x3a, 0xf0, 0x26, ]; -pub(crate) static RESPONSE: LazyLock = LazyLock::new(|| PlatformChallengeResponseData { - client_type: ClientType::Win32, - license_detail_level: LicenseDetailLevel::Detail, - challenge: Vec::from(CHALLENGE_BUFFER.as_ref()), -}); -pub(crate) static CLIENT_HARDWARE_IDENTIFICATION: LazyLock = - LazyLock::new(|| ClientHardwareIdentification { +lazy_static! { + pub(crate) static ref RESPONSE: PlatformChallengeResponseData = PlatformChallengeResponseData { + client_type: ClientType::Win32, + license_detail_level: LicenseDetailLevel::Detail, + challenge: Vec::from(CHALLENGE_BUFFER.as_ref()), + }; + pub(crate) static ref CLIENT_HARDWARE_IDENTIFICATION: ClientHardwareIdentification = ClientHardwareIdentification { platform_id: HARDWARE_ID, data: Vec::from(DATA_BUFFER.as_ref()), - }); -pub(crate) static CLIENT_PLATFORM_CHALLENGE_RESPONSE: LazyLock = LazyLock::new(|| { - LicensePdu::ClientPlatformChallengeResponse(ClientPlatformChallengeResponse { - license_header: LicenseHeader { - security_header: BasicSecurityHeader { - flags: BasicSecurityHeaderFlags::LICENSE_PKT, + }; + pub(crate) static ref CLIENT_PLATFORM_CHALLENGE_RESPONSE: LicensePdu = + LicensePdu::ClientPlatformChallengeResponse(ClientPlatformChallengeResponse { + license_header: LicenseHeader { + security_header: BasicSecurityHeader { + flags: BasicSecurityHeaderFlags::LICENSE_PKT, + }, + preamble_message_type: PreambleType::PlatformChallengeResponse, + preamble_flags: PreambleFlags::empty(), + preamble_version: PreambleVersion::V3, + preamble_message_size: (CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER.len() - BASIC_SECURITY_HEADER_SIZE) + as u16, }, - preamble_message_type: PreambleType::PlatformChallengeResponse, - preamble_flags: PreambleFlags::empty(), - preamble_version: PreambleVersion::V3, - preamble_message_size: u16::try_from( - CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER.len() - BASIC_SECURITY_HEADER_SIZE, - ) - .expect("can't panic"), - }, - encrypted_challenge_response_data: Vec::from(&CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[12..30]), - encrypted_hwid: Vec::from(&CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[34..54]), - mac_data: Vec::from( - &CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER.len() - 16..], - ), - }) -}); + encrypted_challenge_response_data: Vec::from(&CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[12..30]), + encrypted_hwid: Vec::from(&CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[34..54]), + mac_data: Vec::from( + &CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER[CLIENT_PLATFORM_CHALLENGE_RESPONSE_BUFFER.len() - 16..] + ), + }); +} #[test] fn from_buffer_correctly_parses_platform_challenge_response_data() { @@ -168,8 +165,7 @@ fn challenge_response_creates_from_server_challenge_and_encryption_data_correctl preamble_message_type: PreambleType::PlatformChallenge, preamble_flags: PreambleFlags::empty(), preamble_version: PreambleVersion::V3, - preamble_message_size: u16::try_from(encrypted_platform_challenge.len() + mac_data.len() + PREAMBLE_SIZE) - .expect("can't panic"), + preamble_message_size: (encrypted_platform_challenge.len() + mac_data.len() + PREAMBLE_SIZE) as u16, }, encrypted_platform_challenge, mac_data, @@ -204,8 +200,7 @@ fn challenge_response_creates_from_server_challenge_and_encryption_data_correctl let mac_data = crate::rdp::server_license::compute_mac_data( encryption_data.mac_salt_key.as_slice(), [response_data.as_ref(), hardware_id.as_slice()].concat().as_slice(), - ) - .expect("can't panic"); + ); let correct_challenge_response = ClientPlatformChallengeResponse { license_header: LicenseHeader { @@ -215,12 +210,10 @@ fn challenge_response_creates_from_server_challenge_and_encryption_data_correctl preamble_message_type: PreambleType::PlatformChallengeResponse, preamble_flags: PreambleFlags::empty(), preamble_version: PreambleVersion::V3, - preamble_message_size: u16::try_from( - PREAMBLE_SIZE + preamble_message_size: (PREAMBLE_SIZE + (BLOB_TYPE_SIZE + BLOB_LENGTH_SIZE) * 2 // 2 blobs in this structure - + MAC_SIZE + encrypted_challenge_response_data.len() + encrypted_hwid.len(), - ) - .expect("can't panic"), + + MAC_SIZE + encrypted_challenge_response_data.len() + encrypted_hwid.len()) + as u16, }, encrypted_challenge_response_data, encrypted_hwid, diff --git a/crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message/mod.rs rename to crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message.rs diff --git a/crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message/test.rs b/crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message/test.rs index 7ccfc467..588e6d18 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message/test.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/licensing_error_message/test.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; use crate::rdp::server_license::LicensePdu; @@ -11,24 +10,26 @@ const LICENSE_MESSAGE_BUFFER: [u8; 12] = [ 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, // message ]; -static LICENSING_ERROR_MESSAGE: LazyLock = LazyLock::new(|| { - let mut pdu = LicensingErrorMessage { - license_header: LicenseHeader { - security_header: BasicSecurityHeader { - flags: BasicSecurityHeaderFlags::LICENSE_PKT, +lazy_static! { + pub static ref LICENSING_ERROR_MESSAGE: LicensePdu = { + let mut pdu = LicensingErrorMessage { + license_header: LicenseHeader { + security_header: BasicSecurityHeader { + flags: BasicSecurityHeaderFlags::LICENSE_PKT, + }, + preamble_message_type: PreambleType::ErrorAlert, + preamble_flags: PreambleFlags::empty(), + preamble_version: PreambleVersion::V3, + preamble_message_size: 0, }, - preamble_message_type: PreambleType::ErrorAlert, - preamble_flags: PreambleFlags::empty(), - preamble_version: PreambleVersion::V3, - preamble_message_size: 0, - }, - error_code: LicenseErrorCode::StatusValidClient, - state_transition: LicensingStateTransition::NoTransition, - error_info: Vec::new(), + error_code: LicenseErrorCode::StatusValidClient, + state_transition: LicensingStateTransition::NoTransition, + error_info: Vec::new(), + }; + pdu.license_header.preamble_message_size = pdu.size() as u16; + pdu.into() }; - pdu.license_header.preamble_message_size = u16::try_from(pdu.size()).expect("can't panic"); - pdu.into() -}); +} #[test] fn from_buffer_correctly_parses_licensing_error_message() { diff --git a/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/server_license_request.rs similarity index 97% rename from crates/ironrdp-pdu/src/rdp/server_license/server_license_request/mod.rs rename to crates/ironrdp-pdu/src/rdp/server_license/server_license_request.rs index e4c5ee38..3ed5cfe4 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/server_license_request.rs @@ -108,10 +108,7 @@ impl ServerLicenseRequest { return Err(invalid_field_err!("scopeCount", "invalid scope count")); } - let mut scope_list = Vec::with_capacity( - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked integer underflow)")] - usize::try_from(scope_count).expect("scope_count is guaranteed to fit into usize due to the prior check"), - ); + let mut scope_list = Vec::with_capacity(scope_count as usize); for _ in 0..scope_count { scope_list.push(Scope::decode(src)?); diff --git a/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/tests.rs b/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/tests.rs index 37bbd951..a29e4226 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/server_license_request/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::cert::{RsaPublicKey, PROP_CERT_BLOBS_HEADERS_SIZE, PROP_CERT_NO_BLOBS_SIZE, RSA_KEY_SIZE_WITHOUT_MODULUS}; use super::*; @@ -211,60 +210,62 @@ const SCOPE_BUFFER: [u8; 18] = [ 0x00, // scope array ]; -static PROPRIETARY_CERTIFICATE: LazyLock = LazyLock::new(|| ProprietaryCertificate { - public_key: RsaPublicKey { +lazy_static! { + pub static ref PROPRIETARY_CERTIFICATE: ProprietaryCertificate = ProprietaryCertificate { + public_key: RsaPublicKey { + public_exponent: 0x0001_0001, + modulus: Vec::from(MODULUS.as_ref()), + }, + signature: Vec::from(SIGNATURE.as_ref()), + }; + pub static ref PRODUCT_INFO: ProductInfo = ProductInfo { + version: 0x60000, + company_name: "Microsoft Corporation".to_owned(), + product_id: "A02".to_owned(), + }; + pub static ref PUBLIC_KEY: RsaPublicKey = RsaPublicKey { public_exponent: 0x0001_0001, modulus: Vec::from(MODULUS.as_ref()), - }, - signature: Vec::from(SIGNATURE.as_ref()), -}); -static PRODUCT_INFO: LazyLock = LazyLock::new(|| ProductInfo { - version: 0x60000, - company_name: "Microsoft Corporation".to_owned(), - product_id: "A02".to_owned(), -}); -static PUBLIC_KEY: LazyLock = LazyLock::new(|| RsaPublicKey { - public_exponent: 0x0001_0001, - modulus: Vec::from(MODULUS.as_ref()), -}); -static SERVER_LICENSE_REQUEST: LazyLock = LazyLock::new(|| { - let mut req = ServerLicenseRequest { - license_header: LicenseHeader { - security_header: BasicSecurityHeader { - flags: BasicSecurityHeaderFlags::LICENSE_PKT, - }, - preamble_message_type: PreambleType::LicenseRequest, - preamble_flags: PreambleFlags::empty(), - preamble_version: PreambleVersion::V3, - preamble_message_size: 0, - }, - server_random: Vec::from(SERVER_RANDOM_BUFFER.as_ref()), - product_info: ProductInfo { - version: 0x60000, - company_name: "Microsoft Corporation".to_owned(), - product_id: "A02".to_owned(), - }, - server_certificate: Some(ServerCertificate { - issued_permanently: true, - certificate: CertificateType::X509(X509CertificateChain { - certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref())], - }), - }), - scope_list: vec![Scope(String::from("microsoft.com"))], }; - req.license_header.preamble_message_size = u16::try_from(req.size()).expect("can't panic"); - req.into() -}); -static X509_CERTIFICATE: LazyLock = LazyLock::new(|| ServerCertificate { - issued_permanently: true, - certificate: CertificateType::X509(X509CertificateChain { - certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref())], - }), -}); -static SCOPE: LazyLock = LazyLock::new(|| Scope(String::from("microsoft.com"))); -static CERT_CHAIN: LazyLock = LazyLock::new(|| X509CertificateChain { - certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref())], -}); + pub static ref SERVER_LICENSE_REQUEST: LicensePdu = { + let mut req = ServerLicenseRequest { + license_header: LicenseHeader { + security_header: BasicSecurityHeader { + flags: BasicSecurityHeaderFlags::LICENSE_PKT, + }, + preamble_message_type: PreambleType::LicenseRequest, + preamble_flags: PreambleFlags::empty(), + preamble_version: PreambleVersion::V3, + preamble_message_size: 0, + }, + server_random: Vec::from(SERVER_RANDOM_BUFFER.as_ref()), + product_info: ProductInfo { + version: 0x60000, + company_name: "Microsoft Corporation".to_owned(), + product_id: "A02".to_owned(), + }, + server_certificate: Some(ServerCertificate { + issued_permanently: true, + certificate: CertificateType::X509(X509CertificateChain { + certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref())], + }), + }), + scope_list: vec![Scope(String::from("microsoft.com"))], + }; + req.license_header.preamble_message_size = req.size() as u16; + req.into() + }; + pub static ref X509_CERTIFICATE: ServerCertificate = ServerCertificate { + issued_permanently: true, + certificate: CertificateType::X509(X509CertificateChain { + certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref()),], + }), + }; + pub static ref SCOPE: Scope = Scope(String::from("microsoft.com")); + static ref CERT_CHAIN: X509CertificateChain = X509CertificateChain { + certificate_array: vec![Vec::from(CERT_1_BUFFER.as_ref()), Vec::from(CERT_2_BUFFER.as_ref()),], + }; +} #[test] fn from_buffer_correctly_parses_server_license_request() { @@ -322,7 +323,7 @@ fn from_buffer_correctly_parses_server_license_request_no_certificate() { server_certificate: None, scope_list: vec![Scope(String::from("microsoft.com"))], }; - request.license_header.preamble_message_size = u16::try_from(request.size()).expect("can't panic"); + request.license_header.preamble_message_size = request.size() as u16; let request: LicensePdu = request.into(); assert_eq!(request, decode(&request_buffer).unwrap()); @@ -369,7 +370,7 @@ fn to_buffer_correctly_serializes_server_license_request() { }), scope_list: vec![Scope(String::from("microsoft.com"))], }; - request.license_header.preamble_message_size = u16::try_from(request.size()).unwrap(); + request.license_header.preamble_message_size = request.size() as u16; let request: LicensePdu = request.into(); let serialized_request = encode_vec(&request).unwrap(); diff --git a/crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge/mod.rs rename to crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge.rs diff --git a/crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge/test.rs b/crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge/test.rs index 3939b1d4..ac61d260 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge/test.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/server_platform_challenge/test.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; use crate::rdp::server_license::{ @@ -27,8 +26,8 @@ const MAC_DATA_BUFFER: [u8; MAC_SIZE] = [ 0x38, 0x23, 0x62, 0x5d, 0x10, 0x8b, 0x93, 0xc3, 0xf1, 0xe4, 0x67, 0x1f, 0x4a, 0xb6, 0x00, 0x0a, // mac data ]; -static PLATFORM_CHALLENGE: LazyLock = LazyLock::new(|| { - ServerPlatformChallenge { +lazy_static! { + pub static ref PLATFORM_CHALLENGE: LicensePdu = ServerPlatformChallenge { license_header: LicenseHeader { security_header: BasicSecurityHeader { flags: BasicSecurityHeaderFlags::LICENSE_PKT, @@ -36,14 +35,13 @@ static PLATFORM_CHALLENGE: LazyLock = LazyLock::new(|| { preamble_message_type: PreambleType::PlatformChallenge, preamble_flags: PreambleFlags::empty(), preamble_version: PreambleVersion::V3, - preamble_message_size: u16::try_from(PLATFORM_CHALLENGE_BUFFER.len() - BASIC_SECURITY_HEADER_SIZE) - .expect("can't panic"), + preamble_message_size: (PLATFORM_CHALLENGE_BUFFER.len() - BASIC_SECURITY_HEADER_SIZE) as u16, }, encrypted_platform_challenge: Vec::from(CHALLENGE_BUFFER.as_ref()), mac_data: Vec::from(MAC_DATA_BUFFER.as_ref()), } - .into() -}); + .into(); +} #[test] fn from_buffer_correctly_parses_server_platform_challenge() { diff --git a/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license/mod.rs b/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license.rs similarity index 99% rename from crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license/mod.rs rename to crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license.rs index 72671172..492f188e 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license/mod.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license.rs @@ -69,7 +69,7 @@ impl ServerUpgradeLicense { pub fn verify_server_license(&self, encryption_data: &LicenseEncryptionData) -> Result<(), ServerLicenseError> { let decrypted_license_info = self.decrypted_license_info(encryption_data); let mac_data = - super::compute_mac_data(encryption_data.mac_salt_key.as_slice(), decrypted_license_info.as_ref())?; + super::compute_mac_data(encryption_data.mac_salt_key.as_slice(), decrypted_license_info.as_ref()); if mac_data != self.mac_data { return Err(ServerLicenseError::InvalidMacData); diff --git a/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license/tests.rs b/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license/tests.rs index a89d31c0..6aa58641 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/server_upgrade_license/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; use crate::rdp::server_license::{ @@ -245,15 +244,15 @@ const NEW_LICENSE_INFORMATION_BUFFER: [u8; 2031] = [ 0xb8, 0x1b, 0xb9, 0xcd, 0xfb, 0x31, 0x00, // license info ]; -static NEW_LICENSE_INFORMATION: LazyLock = LazyLock::new(|| LicenseInformation { - version: 0x0006_0000, - scope: "microsoft.com".to_owned(), - company_name: "Microsoft Corporation".to_owned(), - product_id: "A02".to_owned(), - license_info: Vec::from(&NEW_LICENSE_INFORMATION_BUFFER[NEW_LICENSE_INFORMATION_BUFFER.len() - 0x0799..]), -}); -static SERVER_UPGRADE_LICENSE: LazyLock = LazyLock::new(|| { - ServerUpgradeLicense { +lazy_static! { + pub static ref NEW_LICENSE_INFORMATION: LicenseInformation = LicenseInformation { + version: 0x0006_0000, + scope: "microsoft.com".to_owned(), + company_name: "Microsoft Corporation".to_owned(), + product_id: "A02".to_owned(), + license_info: Vec::from(&NEW_LICENSE_INFORMATION_BUFFER[NEW_LICENSE_INFORMATION_BUFFER.len() - 0x0799..]), + }; + pub static ref SERVER_UPGRADE_LICENSE: LicensePdu = ServerUpgradeLicense { license_header: LicenseHeader { security_header: BasicSecurityHeader { flags: BasicSecurityHeaderFlags::LICENSE_PKT, @@ -261,16 +260,15 @@ static SERVER_UPGRADE_LICENSE: LazyLock = LazyLock::new(|| { preamble_message_type: PreambleType::NewLicense, preamble_flags: PreambleFlags::empty(), preamble_version: PreambleVersion::V3, - preamble_message_size: u16::try_from(SERVER_UPGRADE_LICENSE_BUFFER.len() - BASIC_SECURITY_HEADER_SIZE) - .expect("buffer size is too large"), + preamble_message_size: (SERVER_UPGRADE_LICENSE_BUFFER.len() - BASIC_SECURITY_HEADER_SIZE) as u16, }, encrypted_license_info: Vec::from( - &SERVER_UPGRADE_LICENSE_BUFFER[12..SERVER_UPGRADE_LICENSE_BUFFER.len() - MAC_SIZE], + &SERVER_UPGRADE_LICENSE_BUFFER[12..SERVER_UPGRADE_LICENSE_BUFFER.len() - MAC_SIZE] ), mac_data: Vec::from(MAC_DATA.as_ref()), } - .into() -}); + .into(); +} #[test] fn from_buffer_correctly_parses_new_license_information() { @@ -620,10 +618,11 @@ fn upgrade_license_verifies_correctly() { preamble_message_type: PreambleType::NewLicense, preamble_flags: PreambleFlags::empty(), preamble_version: PreambleVersion::V3, - preamble_message_size: u16::try_from( - PREAMBLE_SIZE + BLOB_LENGTH_SIZE + BLOB_TYPE_SIZE + encrypted_license_info.len() + MAC_SIZE, - ) - .expect("can't panic"), + preamble_message_size: (PREAMBLE_SIZE + + BLOB_LENGTH_SIZE + + BLOB_TYPE_SIZE + + encrypted_license_info.len() + + MAC_SIZE) as u16, }, encrypted_license_info, mac_data, diff --git a/crates/ironrdp-pdu/src/rdp/server_license/tests.rs b/crates/ironrdp-pdu/src/rdp/server_license/tests.rs index 84bbb408..27e12c61 100644 --- a/crates/ironrdp-pdu/src/rdp/server_license/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/server_license/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; @@ -36,15 +35,17 @@ const STATUS_VALID_CLIENT_BUFFER: [u8; 20] = [ 0xff, 0x03, 0x10, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, ]; -static LICENSE_HEADER: LazyLock = LazyLock::new(|| LicenseHeader { - security_header: BasicSecurityHeader { - flags: BasicSecurityHeaderFlags::LICENSE_PKT, - }, - preamble_message_type: PreambleType::ErrorAlert, - preamble_flags: PreambleFlags::empty(), - preamble_version: PreambleVersion::V3, - preamble_message_size: 0x10, -}); +lazy_static! { + pub static ref LICENSE_HEADER: LicenseHeader = LicenseHeader { + security_header: BasicSecurityHeader { + flags: BasicSecurityHeaderFlags::LICENSE_PKT, + }, + preamble_message_type: PreambleType::ErrorAlert, + preamble_flags: PreambleFlags::empty(), + preamble_version: PreambleVersion::V3, + preamble_message_size: 0x10, + }; +} #[test] fn read_blob_header_handles_wrong_type_correctly() { @@ -105,7 +106,7 @@ fn mac_data_computes_correctly() { let decrypted_server_challenge: [u8; 10] = [0x54, 0x0, 0x45, 0x0, 0x53, 0x0, 0x54, 0x0, 0x0, 0x0]; assert_eq!( - compute_mac_data(mac_salt_key.as_ref(), decrypted_server_challenge.as_ref()).unwrap(), + compute_mac_data(mac_salt_key.as_ref(), decrypted_server_challenge.as_ref()), server_mac_data.as_ref() ); } diff --git a/crates/ironrdp-pdu/src/rdp/session_info/mod.rs b/crates/ironrdp-pdu/src/rdp/session_info.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/session_info/mod.rs rename to crates/ironrdp-pdu/src/rdp/session_info.rs diff --git a/crates/ironrdp-pdu/src/rdp/session_info/logon_extended.rs b/crates/ironrdp-pdu/src/rdp/session_info/logon_extended.rs index 88a42e5c..47c195dc 100644 --- a/crates/ironrdp-pdu/src/rdp/session_info/logon_extended.rs +++ b/crates/ironrdp-pdu/src/rdp/session_info/logon_extended.rs @@ -112,8 +112,8 @@ impl Encode for ServerAutoReconnect { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_fixed_part_size!(in: dst); - dst.write_u32(u32::try_from(AUTO_RECONNECT_PACKET_SIZE).expect("AUTO_RECONNECT_PACKET_SIZE fits into u32")); - dst.write_u32(u32::try_from(AUTO_RECONNECT_PACKET_SIZE).expect("AUTO_RECONNECT_PACKET_SIZE fits into u32")); + dst.write_u32(AUTO_RECONNECT_PACKET_SIZE as u32); + dst.write_u32(AUTO_RECONNECT_PACKET_SIZE as u32); dst.write_u32(AUTO_RECONNECT_VERSION_1); dst.write_u32(self.logon_id); dst.write_slice(self.random_bits.as_ref()); @@ -136,8 +136,7 @@ impl<'de> Decode<'de> for ServerAutoReconnect { let _data_length = src.read_u32(); let packet_length = src.read_u32(); - if packet_length != u32::try_from(AUTO_RECONNECT_PACKET_SIZE).expect("AUTO_RECONNECT_PACKET_SIZE fits into u32") - { + if packet_length != AUTO_RECONNECT_PACKET_SIZE as u32 { return Err(invalid_field_err!("packetLen", "invalid auto-reconnect packet size")); } @@ -172,7 +171,7 @@ impl Encode for LogonErrorsInfo { fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_fixed_part_size!(in: dst); - dst.write_u32(u32::try_from(LOGON_ERRORS_INFO_SIZE).expect("LOGON_ERRORS_INFO_SIZE fits into u32")); + dst.write_u32(LOGON_ERRORS_INFO_SIZE as u32); dst.write_u32(self.error_type.as_u32()); dst.write_u32(self.error_data.to_u32()); diff --git a/crates/ironrdp-pdu/src/rdp/session_info/logon_info.rs b/crates/ironrdp-pdu/src/rdp/session_info/logon_info.rs index e30c54b2..8555a5fe 100644 --- a/crates/ironrdp-pdu/src/rdp/session_info/logon_info.rs +++ b/crates/ironrdp-pdu/src/rdp/session_info/logon_info.rs @@ -111,7 +111,7 @@ impl Encode for LogonInfoVersion2 { ensure_size!(in: dst, size: self.size()); dst.write_u16(SAVE_SESSION_PDU_VERSION_ONE); - dst.write_u32(u32::try_from(LOGON_INFO_V2_SIZE).expect("LOGON_INFO_V2_SIZE fits into u32")); + dst.write_u32(LOGON_INFO_V2_SIZE as u32); dst.write_u32(self.logon_info.session_id); dst.write_u32(cast_length!( "domainNameSize", diff --git a/crates/ironrdp-pdu/src/rdp/session_info/tests.rs b/crates/ironrdp-pdu/src/rdp/session_info/tests.rs index 2af92759..b230f6d2 100644 --- a/crates/ironrdp-pdu/src/rdp/session_info/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/session_info/tests.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec, DecodeErrorKind}; +use lazy_static::lazy_static; use super::*; @@ -235,37 +234,39 @@ const DOMAIN_NAME: &str = "NTDEV"; const USER_NAME: &str = "eltons"; const SESSION_ID: u32 = 0x02; -static LOGON_INFO_V1: LazyLock = LazyLock::new(|| LogonInfoVersion1 { - logon_info: LogonInfo { - domain_name: DOMAIN_NAME.to_owned(), - user_name: USER_NAME.to_owned(), - session_id: SESSION_ID, - }, -}); -static LOGON_INFO_V2: LazyLock = LazyLock::new(|| LogonInfoVersion2 { - logon_info: LogonInfo { - domain_name: DOMAIN_NAME.to_owned(), - user_name: USER_NAME.to_owned(), - session_id: SESSION_ID, - }, -}); -static LOGON_EXTENDED: LazyLock = LazyLock::new(|| LogonInfoExtended { - present_fields_flags: LogonExFlags::AUTO_RECONNECT_COOKIE | LogonExFlags::LOGON_ERRORS, - auto_reconnect: Some(ServerAutoReconnect { - logon_id: SESSION_ID, - random_bits: [ - 0xa8, 0x02, 0xe7, 0x25, 0xe2, 0x4c, 0x82, 0xb7, 0x52, 0xa5, 0x53, 0x50, 0x34, 0x98, 0xa1, 0xa8, - ], - }), - errors_info: Some(LogonErrorsInfo { - error_type: LogonErrorNotificationType::NoPermission, - error_data: LogonErrorNotificationData::ErrorCode(LogonErrorNotificationDataErrorCode::FailedOther), - }), -}); -static SESSION_PLAIN_NOTIFY: LazyLock = LazyLock::new(|| SaveSessionInfoPdu { - info_type: InfoType::PlainNotify, - info_data: InfoData::PlainNotify, -}); +lazy_static! { + static ref LOGON_INFO_V1: LogonInfoVersion1 = LogonInfoVersion1 { + logon_info: LogonInfo { + domain_name: DOMAIN_NAME.to_owned(), + user_name: USER_NAME.to_owned(), + session_id: SESSION_ID, + }, + }; + static ref LOGON_INFO_V2: LogonInfoVersion2 = LogonInfoVersion2 { + logon_info: LogonInfo { + domain_name: DOMAIN_NAME.to_owned(), + user_name: USER_NAME.to_owned(), + session_id: SESSION_ID, + }, + }; + static ref LOGON_EXTENDED: LogonInfoExtended = LogonInfoExtended { + present_fields_flags: LogonExFlags::AUTO_RECONNECT_COOKIE | LogonExFlags::LOGON_ERRORS, + auto_reconnect: Some(ServerAutoReconnect { + logon_id: SESSION_ID, + random_bits: [ + 0xa8, 0x02, 0xe7, 0x25, 0xe2, 0x4c, 0x82, 0xb7, 0x52, 0xa5, 0x53, 0x50, 0x34, 0x98, 0xa1, 0xa8 + ], + }), + errors_info: Some(LogonErrorsInfo { + error_type: LogonErrorNotificationType::NoPermission, + error_data: LogonErrorNotificationData::ErrorCode(LogonErrorNotificationDataErrorCode::FailedOther), + }), + }; + static ref SESSION_PLAIN_NOTIFY: SaveSessionInfoPdu = SaveSessionInfoPdu { + info_type: InfoType::PlainNotify, + info_data: InfoData::PlainNotify, + }; +} #[test] fn from_buffer_correct_parses_logon_info_v1() { diff --git a/crates/ironrdp-pdu/src/rdp/vc/mod.rs b/crates/ironrdp-pdu/src/rdp/vc.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/vc/mod.rs rename to crates/ironrdp-pdu/src/rdp/vc.rs diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/mod.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/vc/dvc/mod.rs rename to crates/ironrdp-pdu/src/rdp/vc/dvc.rs diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/mod.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/mod.rs rename to crates/ironrdp-pdu/src/rdp/vc/dvc/gfx.rs diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/mod.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages.rs similarity index 100% rename from crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/mod.rs rename to crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages.rs diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/avc_messages.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/avc_messages.rs index 73b17078..501c44c3 100644 --- a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/avc_messages.rs +++ b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/avc_messages.rs @@ -112,9 +112,9 @@ impl<'de> Decode<'de> for Avc420BitmapStream<'de> { fn decode(src: &mut ReadCursor<'de>) -> DecodeResult { ensure_fixed_part_size!(in: src); - let num_regions = cast_length!("number of regions", src.read_u32())?; - let mut rectangles = Vec::with_capacity(num_regions); - let mut quant_qual_vals = Vec::with_capacity(num_regions); + let num_regions = src.read_u32(); + let mut rectangles = Vec::with_capacity(num_regions as usize); + let mut quant_qual_vals = Vec::with_capacity(num_regions as usize); for _ in 0..num_regions { rectangles.push(InclusiveRectangle::decode(src)?); } @@ -158,7 +158,7 @@ impl Encode for Avc444BitmapStream<'_> { let mut stream_info = 0u32; stream_info.set_bits(0..30, cast_length!("stream1size", self.stream1.size())?); - stream_info.set_bits(30..32, u32::from(self.encoding.bits())); + stream_info.set_bits(30..32, self.encoding.bits() as u32); dst.write_u32(stream_info); self.stream1.encode(dst)?; if let Some(stream) = self.stream2.as_ref() { @@ -188,8 +188,7 @@ impl<'de> Decode<'de> for Avc444BitmapStream<'de> { let stream_info = src.read_u32(); let stream_len = stream_info.get_bits(0..30); - let encoding = - Encoding::from_bits_truncate(u8::try_from(stream_info.get_bits(30..32)).expect("value fits into u8")); + let encoding = Encoding::from_bits_truncate(stream_info.get_bits(30..32) as u8); if stream_len == 0 { if encoding == Encoding::LUMA_AND_CHROMA { @@ -203,7 +202,7 @@ impl<'de> Decode<'de> for Avc444BitmapStream<'de> { stream2: None, }) } else { - let (mut stream1, mut stream2) = src.split_at(cast_length!("first stream length", stream_len)?); + let (mut stream1, mut stream2) = src.split_at(stream_len as usize); let stream1 = Avc420BitmapStream::decode(&mut stream1)?; let stream2 = if encoding == Encoding::LUMA_AND_CHROMA { Some(Avc420BitmapStream::decode(&mut stream2)?) diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/server.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/server.rs index 4684d0a9..f2046d15 100644 --- a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/server.rs +++ b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/server.rs @@ -231,7 +231,7 @@ impl Encode for SolidFillPdu { dst.write_u16(self.surface_id); self.fill_pixel.encode(dst)?; - dst.write_u16(cast_length!("number of rectangles", self.rectangles.len())?); + dst.write_u16(self.rectangles.len() as u16); for rectangle in self.rectangles.iter() { rectangle.encode(dst)?; @@ -976,10 +976,6 @@ pub enum PixelFormat { } impl PixelFormat { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn as_u8(self) -> u8 { self as u8 } @@ -1030,10 +1026,10 @@ impl<'a> Decode<'a> for Timestamp { let timestamp = src.read_u32(); - let milliseconds = u16::try_from(timestamp.get_bits(..10)).expect("value fits into u16"); - let seconds = u8::try_from(timestamp.get_bits(10..16)).expect("value fits into u8"); - let minutes = u8::try_from(timestamp.get_bits(16..22)).expect("value fits into u8"); - let hours = u16::try_from(timestamp.get_bits(22..)).expect("value fits into u16"); + let milliseconds = timestamp.get_bits(..10) as u16; + let seconds = timestamp.get_bits(10..16) as u8; + let minutes = timestamp.get_bits(16..22) as u8; + let hours = timestamp.get_bits(22..) as u16; Ok(Self { milliseconds, diff --git a/crates/ironrdp-pdu/src/rdp/vc/tests.rs b/crates/ironrdp-pdu/src/rdp/vc/tests.rs index ef31a096..b781bc4e 100644 --- a/crates/ironrdp-pdu/src/rdp/vc/tests.rs +++ b/crates/ironrdp-pdu/src/rdp/vc/tests.rs @@ -1,16 +1,17 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode, encode_vec}; +use lazy_static::lazy_static; use super::*; const CHANNEL_CHUNK_LENGTH_DEFAULT: u32 = 1600; const CHANNEL_PDU_HEADER_BUFFER: [u8; CHANNEL_PDU_HEADER_SIZE] = [0x40, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]; -static CHANNEL_PDU_HEADER: LazyLock = LazyLock::new(|| ChannelPduHeader { - length: CHANNEL_CHUNK_LENGTH_DEFAULT, - flags: ChannelControlFlags::FLAG_FIRST, -}); +lazy_static! { + static ref CHANNEL_PDU_HEADER: ChannelPduHeader = ChannelPduHeader { + length: CHANNEL_CHUNK_LENGTH_DEFAULT, + flags: ChannelControlFlags::FLAG_FIRST, + }; +} #[test] fn from_buffer_correct_parses_channel_header() { diff --git a/crates/ironrdp-pdu/src/utils.rs b/crates/ironrdp-pdu/src/utils.rs index edfa115d..4326ace3 100644 --- a/crates/ironrdp-pdu/src/utils.rs +++ b/crates/ironrdp-pdu/src/utils.rs @@ -8,11 +8,8 @@ use num_derive::FromPrimitive; use crate::{DecodeResult, EncodeResult}; pub fn split_u64(value: u64) -> (u32, u32) { - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked integer downcast)")] let low = u32::try_from(value & 0xFFFF_FFFF).expect("masking with 0xFFFF_FFFF ensures that the value fits into u32"); - - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked integer downcast)")] let high = u32::try_from(value >> 32).expect("(u64 >> 32) fits into u32"); (low, high) @@ -34,8 +31,6 @@ pub fn to_utf16_bytes(value: &str) -> Vec { pub fn from_utf16_bytes(mut value: &[u8]) -> String { let mut value_u16 = vec![0x00; value.len() / 2]; - - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (prior constrain)")] value .read_u16_into::(value_u16.as_mut()) .expect("read_u16_into cannot fail at this point"); @@ -111,7 +106,6 @@ pub fn read_string_from_cursor( let str_buffer = &mut slice; let mut u16_buffer = vec![0u16; str_buffer.len() / 2]; - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (prior constrain)")] str_buffer .read_u16_into::(u16_buffer.as_mut()) .expect("BUG: str_buffer is always even for UTF16"); @@ -301,12 +295,7 @@ where ) } -/// Utility function that panics on overflow -/// -/// # Panics -/// -/// Panics if sum of values overflows. -// FIXME: Is it really something we want to expose from ironrdp-pdu? +// Utility function that panics on overflow pub fn strict_sum(values: &[T]) -> T where T: CheckedAdd + Copy + Debug, diff --git a/crates/ironrdp-rdcleanpath/CHANGELOG.md b/crates/ironrdp-rdcleanpath/CHANGELOG.md index 071e3893..fa6410ca 100644 --- a/crates/ironrdp-rdcleanpath/CHANGELOG.md +++ b/crates/ironrdp-rdcleanpath/CHANGELOG.md @@ -6,16 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.2.1](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdcleanpath-v0.2.0...ironrdp-rdcleanpath-v0.2.1)] - 2025-10-02 - -### Features - -- Human-readable descriptions for RDCleanPath errors (#999) ([18c81ed5d8](https://github.com/Devolutions/IronRDP/commit/18c81ed5d8d3bf13b3d10fe15209233c0c10bb62)) - - More munging to give human-readable webclient-side errors for - RDCleanPath general/negotiation errors, including strings for WSA and - TLS and HTTP error conditions. - ## [[0.2.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdcleanpath-v0.1.3...ironrdp-rdcleanpath-v0.2.0)] - 2025-08-29 ### Features diff --git a/crates/ironrdp-rdcleanpath/Cargo.toml b/crates/ironrdp-rdcleanpath/Cargo.toml index 3c3c73dd..9e47b1fa 100644 --- a/crates/ironrdp-rdcleanpath/Cargo.toml +++ b/crates/ironrdp-rdcleanpath/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-rdcleanpath" -version = "0.2.1" +version = "0.2.0" readme = "README.md" description = "RDCleanPath PDU structure used by IronRDP web client and Devolutions Gateway" edition.workspace = true diff --git a/crates/ironrdp-rdcleanpath/src/lib.rs b/crates/ironrdp-rdcleanpath/src/lib.rs index b884ba85..7deb4c67 100644 --- a/crates/ironrdp-rdcleanpath/src/lib.rs +++ b/crates/ironrdp-rdcleanpath/src/lib.rs @@ -30,128 +30,18 @@ pub struct RDCleanPathErr { impl fmt::Display for RDCleanPathErr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let error_description = match self.error_code { - GENERAL_ERROR_CODE => "general error", - NEGOTIATION_ERROR_CODE => "negotiation error", - _ => "unknown error", - }; - write!(f, "{error_description} (code {})", self.error_code)?; + write!(f, "RDCleanPath error (code {})", self.error_code)?; if let Some(http_status_code) = self.http_status_code { - let description = match http_status_code { - 200 => "OK", - 400 => "bad request", - 401 => "unauthorized", - 403 => "forbidden", - 404 => "not found", - 405 => "method not allowed", - 408 => "request timeout", - 409 => "conflict", - 410 => "gone", - 413 => "payload too large", - 414 => "URI too long", - 422 => "unprocessable entity", - 429 => "too many requests", - 500 => "internal server error", - 501 => "not implemented", - 502 => "bad gateway", - 503 => "service unavailable", - 504 => "gateway timeout", - 505 => "HTTP version not supported", - _ => "unknown HTTP status", - }; - write!(f, "; HTTP {http_status_code} {description}")?; + write!(f, " [HTTP status = {http_status_code}]")?; } if let Some(wsa_last_error) = self.wsa_last_error { - let description = match wsa_last_error { - 10004 => "interrupted system call", - 10009 => "bad file descriptor", - 10013 => "permission denied", - 10014 => "bad address", - 10022 => "invalid argument", - 10024 => "too many open files", - 10035 => "resource temporarily unavailable", - 10036 => "operation now in progress", - 10037 => "operation already in progress", - 10038 => "socket operation on nonsocket", - 10039 => "destination address required", - 10040 => "message too long", - 10041 => "protocol wrong type for socket", - 10042 => "bad protocol option", - 10043 => "protocol not supported", - 10044 => "socket type not supported", - 10045 => "operation not supported", - 10046 => "protocol family not supported", - 10047 => "address family not supported by protocol family", - 10048 => "address already in use", - 10049 => "cannot assign requested address", - 10050 => "network is down", - 10051 => "network is unreachable", - 10052 => "network dropped connection on reset", - 10053 => "software caused connection abort", - 10054 => "connection reset by peer", - 10055 => "no buffer space available", - 10056 => "socket is already connected", - 10057 => "socket is not connected", - 10058 => "cannot send after socket shutdown", - 10060 => "connection timed out", - 10061 => "connection refused", - 10064 => "host is down", - 10065 => "no route to host", - 10067 => "too many processes", - 10091 => "network subsystem is unavailable", - 10092 => "Winsock version not supported", - 10093 => "successful WSAStartup not yet performed", - 10101 => "graceful shutdown in progress", - 10109 => "class type not found", - 11001 => "host not found", - 11002 => "nonauthoritative host not found", - 11003 => "this is a nonrecoverable error", - 11004 => "valid name, no data record of requested type", - _ => "unknown WSA error", - }; - write!(f, "; WSA {wsa_last_error} {description}")?; + write!(f, " [WSA last error = {wsa_last_error}]")?; } if let Some(tls_alert_code) = self.tls_alert_code { - let description = match tls_alert_code { - 0 => "close notify", - 10 => "unexpected message", - 20 => "bad record MAC", - 21 => "decryption failed", - 22 => "record overflow", - 30 => "decompression failure", - 40 => "handshake failure", - 41 => "no certificate", - 42 => "bad certificate", - 43 => "unsupported certificate", - 44 => "certificate revoked", - 45 => "certificate expired", - 46 => "certificate unknown", - 47 => "illegal parameter", - 48 => "unknown CA", - 49 => "access denied", - 50 => "decode error", - 51 => "decrypt error", - 60 => "export restriction", - 70 => "protocol version", - 71 => "insufficient security", - 80 => "internal error", - 90 => "user canceled", - 100 => "no renegotiation", - 109 => "missing extension", - 110 => "unsupported extension", - 111 => "certificate unobtainable", - 112 => "unrecognized name", - 113 => "bad certificate status response", - 114 => "bad certificate hash value", - 115 => "unknown PSK identity", - 116 => "certificate required", - 120 => "no application protocol", - _ => "unknown TLS alert", - }; - write!(f, "; TLS alert {tls_alert_code} {description}")?; + write!(f, " [TLS alert = {tls_alert_code}]")?; } Ok(()) diff --git a/crates/ironrdp-rdpdr-native/CHANGELOG.md b/crates/ironrdp-rdpdr-native/CHANGELOG.md index 301fa404..4370951c 100644 --- a/crates/ironrdp-rdpdr-native/CHANGELOG.md +++ b/crates/ironrdp-rdpdr-native/CHANGELOG.md @@ -6,9 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.5.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdpdr-native-v0.4.0...ironrdp-rdpdr-native-v0.5.0)] - 2025-12-18 - - ## [[0.4.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdpdr-native-v0.3.0...ironrdp-rdpdr-native-v0.4.0)] - 2025-08-29 ### Build diff --git a/crates/ironrdp-rdpdr-native/Cargo.toml b/crates/ironrdp-rdpdr-native/Cargo.toml index 14fea584..1d61a701 100644 --- a/crates/ironrdp-rdpdr-native/Cargo.toml +++ b/crates/ironrdp-rdpdr-native/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-rdpdr-native" -version = "0.5.0" +version = "0.4.0" readme = "README.md" description = "Native RDPDR static channel backend implementations for IronRDP" edition.workspace = true @@ -19,6 +19,6 @@ test = false ironrdp-core = { path = "../ironrdp-core", version = "0.1" } ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6" } # public ironrdp-svc = { path = "../ironrdp-svc", version = "0.5" } # public -ironrdp-rdpdr = { path = "../ironrdp-rdpdr", version = "0.5" } # public +ironrdp-rdpdr = { path = "../ironrdp-rdpdr", version = "0.4" } # public nix = { version = "0.30", features = ["fs", "dir"] } tracing = { version = "0.1", features = ["log"] } diff --git a/crates/ironrdp-rdpdr/CHANGELOG.md b/crates/ironrdp-rdpdr/CHANGELOG.md index e61a8251..99da423d 100644 --- a/crates/ironrdp-rdpdr/CHANGELOG.md +++ b/crates/ironrdp-rdpdr/CHANGELOG.md @@ -6,18 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.5.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdpdr-v0.4.1...ironrdp-rdpdr-v0.5.0)] - 2025-12-18 - -### Bug Fixes - -- Fix incorrect padding when parsing NDR strings ([#1015](https://github.com/Devolutions/IronRDP/issues/1015)) ([a0a3e750c9](https://github.com/Devolutions/IronRDP/commit/a0a3e750c9e4ee9c73b957fbcb26dbc59e57d07d)) - - When parsing Network Data Representation (NDR) messages, we're supposed - to account for padding at the end of strings to remain aligned on a - 4-byte boundary. The existing code doesn't seem to cover all cases, and - the resulting misalignment causes misleading errors when processing the - rest of the message. - ## [[0.4.1](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdpdr-v0.4.0...ironrdp-rdpdr-v0.4.1)] - 2025-09-04 ### Features @@ -30,24 +18,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add USER_LOGGEDON flag support ([5e78f91713](https://github.com/Devolutions/IronRDP/commit/5e78f917132a174bdd5d8711beb1744de1bd265a)) + ## [[0.2.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdpdr-v0.1.3...ironrdp-rdpdr-v0.2.0)] - 2025-03-12 ### Build - Bump ironrdp-pdu + ## [[0.1.3](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdpdr-v0.1.2...ironrdp-rdpdr-v0.1.3)] - 2025-03-12 ### Build - Update dependencies (#695) ([c21fa44fd6](https://github.com/Devolutions/IronRDP/commit/c21fa44fd6f3c6a6b74788ff68e83133c1314caa)) + ## [[0.1.2](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdpdr-v0.1.1...ironrdp-rdpdr-v0.1.2)] - 2025-01-28 ### Documentation - Use CDN URLs instead of the blob storage URLs for Devolutions logo (#631) ([dd249909a8](https://github.com/Devolutions/IronRDP/commit/dd249909a894004d4f728d30b3a4aa77a0f8193b)) + + ## [[0.1.1](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdpdr-v0.1.0...ironrdp-rdpdr-v0.1.1)] - 2024-12-14 ### Other diff --git a/crates/ironrdp-rdpdr/Cargo.toml b/crates/ironrdp-rdpdr/Cargo.toml index b585bff1..32a762e7 100644 --- a/crates/ironrdp-rdpdr/Cargo.toml +++ b/crates/ironrdp-rdpdr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-rdpdr" -version = "0.5.0" +version = "0.4.1" readme = "README.md" description = "RDPDR channel implementation." edition.workspace = true diff --git a/crates/ironrdp-rdpdr/src/lib.rs b/crates/ironrdp-rdpdr/src/lib.rs index e5e1191f..48062bf6 100644 --- a/crates/ironrdp-rdpdr/src/lib.rs +++ b/crates/ironrdp-rdpdr/src/lib.rs @@ -1,6 +1,10 @@ #![cfg_attr(doc, doc = include_str!("../README.md"))] #![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")] #![allow(clippy::arithmetic_side_effects)] // FIXME: remove +#![allow(clippy::cast_lossless)] // FIXME: remove +#![allow(clippy::cast_possible_truncation)] // FIXME: remove +#![allow(clippy::cast_possible_wrap)] // FIXME: remove +#![allow(clippy::cast_sign_loss)] // FIXME: remove use ironrdp_core::{decode_cursor, impl_as_any, ReadCursor}; use ironrdp_pdu::gcc::ChannelName; diff --git a/crates/ironrdp-rdpdr/src/pdu/efs.rs b/crates/ironrdp-rdpdr/src/pdu/efs.rs index 5c669f29..37633d4e 100644 --- a/crates/ironrdp-rdpdr/src/pdu/efs.rs +++ b/crates/ironrdp-rdpdr/src/pdu/efs.rs @@ -154,15 +154,9 @@ impl ClientNameRequest { pub fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_size!(in: dst, size: self.size()); - - let encoded_computer_name_length = cast_length!( - "encoded computer name length", - encoded_str_len(self.computer_name(), self.unicode_flag().into(), true) - )?; - dst.write_u32(self.unicode_flag().into()); dst.write_u32(0); // // CodePage (4 bytes): it MUST be set to 0 - dst.write_u32(encoded_computer_name_length); + dst.write_u32(encoded_str_len(self.computer_name(), self.unicode_flag().into(), true) as u32); write_string_to_cursor(dst, self.computer_name(), self.unicode_flag().into(), true) } @@ -192,10 +186,6 @@ impl From for CharacterSet { } impl From for u32 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(val: ClientNameRequestUnicodeFlag) -> Self { val as u32 } @@ -441,7 +431,7 @@ impl CapabilityHeader { fn new_general() -> Self { Self { cap_type: CapabilityType::General, - length: u16::try_from(Self::SIZE + GeneralCapabilitySet::SIZE).expect("value fits into u16"), + length: (Self::SIZE + GeneralCapabilitySet::SIZE) as u16, version: GENERAL_CAPABILITY_VERSION_02, } } @@ -449,7 +439,7 @@ impl CapabilityHeader { fn new_smartcard() -> Self { Self { cap_type: CapabilityType::Smartcard, - length: u16::try_from(Self::SIZE).expect("value fits into u16"), + length: Self::SIZE as u16, version: SMARTCARD_CAPABILITY_VERSION_01, } } @@ -457,7 +447,7 @@ impl CapabilityHeader { fn new_drive() -> Self { Self { cap_type: CapabilityType::Drive, - length: u16::try_from(Self::SIZE).expect("value fits into u16"), + length: Self::SIZE as u16, version: DRIVE_CAPABILITY_VERSION_02, } } @@ -500,10 +490,6 @@ enum CapabilityType { } impl From for u16 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(cap_type: CapabilityType) -> Self { cap_type as u16 } @@ -1004,10 +990,6 @@ pub enum DeviceType { } impl From for u32 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(device_type: DeviceType) -> Self { device_type as u32 } @@ -1229,10 +1211,6 @@ impl TryFrom for MajorFunction { } impl From for u32 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(major_function: MajorFunction) -> Self { major_function as u32 } @@ -1275,6 +1253,12 @@ impl From for u32 { } } +impl From for u8 { + fn from(minor_function: MinorFunction) -> Self { + minor_function.0 as u8 + } +} + /// [2.2.1.4.5] Device Control Request (DR_CONTROL_REQ) /// /// [2.2.1.4.5]: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpefs/30662c80-ec6e-4ed1-9004-2e6e367bb59f diff --git a/crates/ironrdp-rdpdr/src/pdu/esc/mod.rs b/crates/ironrdp-rdpdr/src/pdu/esc.rs similarity index 98% rename from crates/ironrdp-rdpdr/src/pdu/esc/mod.rs rename to crates/ironrdp-rdpdr/src/pdu/esc.rs index 1b495a7b..b7deefde 100644 --- a/crates/ironrdp-rdpdr/src/pdu/esc/mod.rs +++ b/crates/ironrdp-rdpdr/src/pdu/esc.rs @@ -574,10 +574,6 @@ impl ReturnCode { } impl From for u32 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(val: ReturnCode) -> Self { val as u32 } @@ -1248,7 +1244,7 @@ impl rpce::HeaderlessDecode for TransmitCall { #[derive(Debug, PartialEq, Clone)] pub struct SCardIORequest { pub protocol: CardProtocol, - pub extra_bytes_length: usize, + pub extra_bytes_length: u32, pub extra_bytes: Vec, } @@ -1259,7 +1255,7 @@ impl ndr::Decode for SCardIORequest { { ensure_size!(in: src, size: size_of::() * 2); let protocol = CardProtocol::from_bits_retain(src.read_u32()); - let extra_bytes_length = cast_length!("SCardIORequest", "extra_bytes_length", src.read_u32())?; + let extra_bytes_length = src.read_u32(); let _extra_bytes_ptr = ndr::decode_ptr(src, index)?; let extra_bytes = Vec::new(); Ok(Self { @@ -1271,8 +1267,9 @@ impl ndr::Decode for SCardIORequest { fn decode_value(&mut self, src: &mut ReadCursor<'_>, charset: Option) -> DecodeResult<()> { expect_no_charset(charset)?; - ensure_size!(in: src, size: self.extra_bytes_length); - self.extra_bytes = src.read_slice(self.extra_bytes_length).to_vec(); + let extra_bytes_length: usize = cast_length!("TransmitCall", "extra_bytes_length", self.extra_bytes_length)?; + ensure_size!(in: src, size: extra_bytes_length); + self.extra_bytes = src.read_slice(extra_bytes_length).to_vec(); Ok(()) } } @@ -1280,11 +1277,8 @@ impl ndr::Decode for SCardIORequest { impl ndr::Encode for SCardIORequest { fn encode_ptr(&self, index: &mut u32, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { ensure_size!(in: dst, size: self.size_ptr()); - - let extra_bytes_length = cast_length!("SCardIORequest", "extra_bytes_length", self.extra_bytes_length)?; - dst.write_u32(self.protocol.bits()); - ndr::encode_ptr(Some(extra_bytes_length), index, dst) + ndr::encode_ptr(Some(self.extra_bytes_length), index, dst) } fn encode_value(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> { @@ -1298,7 +1292,7 @@ impl ndr::Encode for SCardIORequest { } fn size_value(&self) -> usize { - self.extra_bytes_length + self.extra_bytes_length as usize } } @@ -1491,10 +1485,6 @@ pub enum CardState { } impl From for u32 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(val: CardState) -> Self { val as u32 } diff --git a/crates/ironrdp-rdpdr/src/pdu/esc/ndr.rs b/crates/ironrdp-rdpdr/src/pdu/esc/ndr.rs index 8bc4e3e2..65afde51 100644 --- a/crates/ironrdp-rdpdr/src/pdu/esc/ndr.rs +++ b/crates/ironrdp-rdpdr/src/pdu/esc/ndr.rs @@ -80,21 +80,17 @@ pub fn ptr_size(with_length: bool) -> usize { /// offset fields prefixing the string, as well as any extra padding for a 4-byte aligned /// NULL-terminated string. pub fn read_string_from_cursor(cursor: &mut ReadCursor<'_>, charset: CharacterSet) -> DecodeResult { - const ALIGNMENT: usize = 4; ensure_size!(ctx: "ndr::read_string_from_cursor", in: cursor, size: size_of::() * 3); - let _length = cursor.read_u32(); + let length = cursor.read_u32(); let _offset = cursor.read_u32(); let _length2 = cursor.read_u32(); let string = utils::read_string_from_cursor(cursor, charset, true)?; // Skip padding for 4-byte aligned NULL-terminated string. - let mut pad = cursor.pos(); - let size = (pad + ALIGNMENT - 1) & !(ALIGNMENT - 1); - pad = size - pad; - if pad > 0 { - ensure_size!(ctx: "ndr::read_string_from_cursor", in: cursor, size: pad); - cursor.advance(pad); + if length % 2 != 0 { + ensure_size!(ctx: "ndr::read_string_from_cursor", in: cursor, size: size_of::()); + let _padding = cursor.read_u16(); } Ok(string) diff --git a/crates/ironrdp-rdpdr/src/pdu/esc/rpce.rs b/crates/ironrdp-rdpdr/src/pdu/esc/rpce.rs index 75f6a90f..31c97bae 100644 --- a/crates/ironrdp-rdpdr/src/pdu/esc/rpce.rs +++ b/crates/ironrdp-rdpdr/src/pdu/esc/rpce.rs @@ -244,10 +244,6 @@ impl TryFrom for Endianness { } impl From for u8 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(endianness: Endianness) -> Self { endianness as u8 } diff --git a/crates/ironrdp-rdpdr/src/pdu/mod.rs b/crates/ironrdp-rdpdr/src/pdu/mod.rs index 33848882..fa96cba0 100644 --- a/crates/ironrdp-rdpdr/src/pdu/mod.rs +++ b/crates/ironrdp-rdpdr/src/pdu/mod.rs @@ -374,10 +374,6 @@ impl TryFrom for Component { } impl From for u16 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(component: Component) -> Self { component as u16 } @@ -458,10 +454,6 @@ impl Display for PacketId { } impl From for u16 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(packet_id: PacketId) -> Self { packet_id as u16 } diff --git a/crates/ironrdp-rdpsnd-native/CHANGELOG.md b/crates/ironrdp-rdpsnd-native/CHANGELOG.md index ff009f99..9b3c6938 100644 --- a/crates/ironrdp-rdpsnd-native/CHANGELOG.md +++ b/crates/ironrdp-rdpsnd-native/CHANGELOG.md @@ -6,12 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.4.2](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdpsnd-native-v0.4.1...ironrdp-rdpsnd-native-v0.4.2)] - 2025-12-18 - -### Build - -- Bump bytemuck from 1.23.2 to 1.24.0 ([#1008](https://github.com/Devolutions/IronRDP/issues/1008)) ([a24a1fa9e8](https://github.com/Devolutions/IronRDP/commit/a24a1fa9e8f1898b2fcdd41d87660ab9e38f89ed)) - ## [[0.4.1](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdpsnd-native-v0.4.0...ironrdp-rdpsnd-native-v0.4.1)] - 2025-09-24 ### Build @@ -55,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use CDN URLs instead of the blob storage URLs for Devolutions logo (#631) ([dd249909a8](https://github.com/Devolutions/IronRDP/commit/dd249909a894004d4f728d30b3a4aa77a0f8193b)) + ## [[0.1.1](https://github.com/Devolutions/IronRDP/compare/ironrdp-rdpsnd-native-v0.1.0...ironrdp-rdpsnd-native-v0.1.1)] - 2024-12-15 ### Other diff --git a/crates/ironrdp-rdpsnd-native/Cargo.toml b/crates/ironrdp-rdpsnd-native/Cargo.toml index c6711eb0..26683271 100644 --- a/crates/ironrdp-rdpsnd-native/Cargo.toml +++ b/crates/ironrdp-rdpsnd-native/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-rdpsnd-native" -version = "0.4.2" +version = "0.4.1" description = "Native RDPSND static channel backend implementations for IronRDP" edition.workspace = true license.workspace = true @@ -20,7 +20,7 @@ opus = ["dep:opus2", "dep:bytemuck"] [dependencies] anyhow = "1" -bytemuck = { version = "1.24", optional = true } +bytemuck = { version = "1.23", optional = true } cpal = "0.16" ironrdp-rdpsnd = { path = "../ironrdp-rdpsnd", version = "0.6" } # public opus2 = { version = "0.3", optional = true, features = ["bundled"] } diff --git a/crates/ironrdp-rdpsnd-native/examples/cpal.rs b/crates/ironrdp-rdpsnd-native/examples/cpal.rs index 2372e9d0..9486abbe 100644 --- a/crates/ironrdp-rdpsnd-native/examples/cpal.rs +++ b/crates/ironrdp-rdpsnd-native/examples/cpal.rs @@ -54,7 +54,7 @@ fn main() -> anyhow::Result<()> { } }); - stream.stream().play()?; + stream.stream.play()?; thread::sleep(Duration::from_secs(3)); let _ = producer.join(); diff --git a/crates/ironrdp-rdpsnd-native/src/cpal.rs b/crates/ironrdp-rdpsnd-native/src/cpal.rs index f91d4719..bd5bf96e 100644 --- a/crates/ironrdp-rdpsnd-native/src/cpal.rs +++ b/crates/ironrdp-rdpsnd-native/src/cpal.rs @@ -134,7 +134,7 @@ impl RdpsndClientHandler for RdpsndBackend { #[doc(hidden)] pub struct DecodeStream { _dec_thread: Option>, - stream: Stream, + pub stream: Stream, } impl DecodeStream { @@ -160,10 +160,6 @@ impl DecodeStream { } }; - #[expect( - clippy::as_conversions, - reason = "opus::Channels has no conversions to usize implemented" - )] let mut pcm = vec![0u8; nb_samples * chan as usize * size_of::()]; if let Err(error) = dec.decode(&pkt, bytemuck::cast_slice_mut(pcm.as_mut_slice()), false) { error!(?error, "Failed to decode an Opus packet"); @@ -226,10 +222,6 @@ impl DecodeStream { stream, }) } - - pub fn stream(&self) -> &Stream { - &self.stream - } } struct RxBuffer { diff --git a/crates/ironrdp-rdpsnd/src/client.rs b/crates/ironrdp-rdpsnd/src/client.rs index 0cc8c6ed..b90e7dc9 100644 --- a/crates/ironrdp-rdpsnd/src/client.rs +++ b/crates/ironrdp-rdpsnd/src/client.rs @@ -80,7 +80,7 @@ impl Rdpsnd { server_format .formats - .get(usize::from(format_no)) + .get(format_no as usize) .ok_or_else(|| pdu_other_err!("invalid format")) } @@ -196,7 +196,7 @@ impl SvcProcessor for Rdpsnd { match pdu { // TODO: handle WaveInfo for < v8 pdu::ServerAudioOutputPdu::Wave2(pdu) => { - let format_no = usize::from(pdu.format_no); + let format_no = pdu.format_no as usize; let ts = pdu.audio_timestamp; self.handler.wave(format_no, ts, pdu.data); return Ok(self.wave_confirm(pdu.timestamp, pdu.block_no)?.into()); diff --git a/crates/ironrdp-rdpsnd/src/pdu/mod.rs b/crates/ironrdp-rdpsnd/src/pdu/mod.rs index 258b239a..eb3b45e1 100644 --- a/crates/ironrdp-rdpsnd/src/pdu/mod.rs +++ b/crates/ironrdp-rdpsnd/src/pdu/mod.rs @@ -51,10 +51,6 @@ impl TryFrom for Version { } impl From for u16 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(version: Version) -> Self { version as u16 } @@ -446,8 +442,9 @@ impl<'de> Decode<'de> for ClientAudioFormatPdu { ensure_fixed_part_size!(in: src); let flags = AudioFormatFlags::from_bits_truncate(src.read_u32()); - let volume_left = src.read_u16(); - let volume_right = src.read_u16(); + let volume = src.read_u32(); + let volume_left = (volume & 0xFFFF) as u16; + let volume_right = (volume >> 16) as u16; let pitch = src.read_u32(); let dgram_port = src.read_u16_be(); let n_formats = usize::from(src.read_u16()); @@ -492,10 +489,6 @@ impl TryFrom for QualityMode { } impl From for u16 { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] fn from(mode: QualityMode) -> Self { mode as u16 } @@ -633,7 +626,7 @@ impl<'de> Decode<'de> for TrainingPdu { ensure_fixed_part_size!(in: src); let timestamp = src.read_u16(); - let len = usize::from(src.read_u16()); + let len = src.read_u16() as usize; let data = if len != 0 { if len < Self::FIXED_PART_SIZE + ServerAudioOutputPdu::FIXED_PART_SIZE { return Err(invalid_field_err!("TrainingPdu::wPackSize", "too small")); @@ -846,7 +839,7 @@ impl Encode for WavePdu<'_> { impl WavePdu<'_> { fn decode(src: &mut ReadCursor<'_>, body_size: u16) -> DecodeResult { let info = WaveInfoPdu::decode(src)?; - let body_size = usize::from(body_size); + let body_size = body_size as usize; let data_len = body_size .checked_sub(info.size()) .ok_or_else(|| invalid_field_err!("Length", "WaveInfo body_size is too small"))?; @@ -1097,8 +1090,9 @@ impl<'de> Decode<'de> for VolumePdu { fn decode(src: &mut ReadCursor<'de>) -> DecodeResult { ensure_fixed_part_size!(in: src); - let volume_left = src.read_u16(); - let volume_right = src.read_u16(); + let volume = src.read_u32(); + let volume_left = (volume & 0xFFFF) as u16; + let volume_right = (volume >> 16) as u16; Ok(Self { volume_left, diff --git a/crates/ironrdp-server/CHANGELOG.md b/crates/ironrdp-server/CHANGELOG.md index 916740d6..e68c17d2 100644 --- a/crates/ironrdp-server/CHANGELOG.md +++ b/crates/ironrdp-server/CHANGELOG.md @@ -6,15 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.10.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-server-v0.9.0...ironrdp-server-v0.10.0)] - 2025-12-18 - -### Bug Fixes - -- Send TLS close_notify during graceful RDP disconnect ([#1032](https://github.com/Devolutions/IronRDP/issues/1032)) ([a70e01d9c5](https://github.com/Devolutions/IronRDP/commit/a70e01d9c5675a7dffd65eda7428537c8ad6a857)) - - Add support for sending a proper TLS close_notify message when the RDP - client initiates a graceful disconnect PDU. - ## [[0.9.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-server-v0.8.0...ironrdp-server-v0.9.0)] - 2025-09-24 ### Bug Fixes diff --git a/crates/ironrdp-server/Cargo.toml b/crates/ironrdp-server/Cargo.toml index b1e4650c..e4d531d3 100644 --- a/crates/ironrdp-server/Cargo.toml +++ b/crates/ironrdp-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-server" -version = "0.10.0" +version = "0.9.0" readme = "README.md" description = "Extendable skeleton for implementing custom RDP servers" edition.workspace = true @@ -31,17 +31,17 @@ anyhow = "1.0" tokio = { version = "1", features = ["net", "macros", "sync", "rt"] } # public tokio-rustls = "0.26" # public async-trait = "0.1" -ironrdp-async = { path = "../ironrdp-async", version = "0.8" } +ironrdp-async = { path = "../ironrdp-async", version = "0.7" } ironrdp-ainput = { path = "../ironrdp-ainput", version = "0.4" } ironrdp-core = { path = "../ironrdp-core", version = "0.1" } ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6" } # public ironrdp-svc = { path = "../ironrdp-svc", version = "0.5" } # public -ironrdp-cliprdr = { path = "../ironrdp-cliprdr", version = "0.5" } # public +ironrdp-cliprdr = { path = "../ironrdp-cliprdr", version = "0.4" } # public ironrdp-displaycontrol = { path = "../ironrdp-displaycontrol", version = "0.4" } # public ironrdp-dvc = { path = "../ironrdp-dvc", version = "0.4" } # public -ironrdp-tokio = { path = "../ironrdp-tokio", version = "0.8" } -ironrdp-acceptor = { path = "../ironrdp-acceptor", version = "0.8" } # public -ironrdp-graphics = { path = "../ironrdp-graphics", version = "0.7" } # public +ironrdp-tokio = { path = "../ironrdp-tokio", version = "0.7" } +ironrdp-acceptor = { path = "../ironrdp-acceptor", version = "0.7" } # public +ironrdp-graphics = { path = "../ironrdp-graphics", version = "0.6" } # public ironrdp-rdpsnd = { path = "../ironrdp-rdpsnd", version = "0.6" } # public tracing = { version = "0.1", features = ["log"] } x509-cert = { version = "0.2.5", optional = true } diff --git a/crates/ironrdp-server/src/encoder/bitmap.rs b/crates/ironrdp-server/src/encoder/bitmap.rs index 8810e433..e7a78c7b 100644 --- a/crates/ironrdp-server/src/encoder/bitmap.rs +++ b/crates/ironrdp-server/src/encoder/bitmap.rs @@ -19,7 +19,7 @@ pub(crate) struct BitmapEncoder { impl BitmapEncoder { pub(crate) fn new() -> Self { Self { - buffer: vec![0; usize::from(u16::MAX)], + buffer: vec![0; u16::MAX as usize], } } diff --git a/crates/ironrdp-server/src/encoder/fast_path.rs b/crates/ironrdp-server/src/encoder/fast_path.rs index 1b4da818..90ed98e4 100644 --- a/crates/ironrdp-server/src/encoder/fast_path.rs +++ b/crates/ironrdp-server/src/encoder/fast_path.rs @@ -13,10 +13,6 @@ const FASTPATH_HEADER_SIZE: usize = 6; reason = "Unfortunately, expect attribute doesn't work when above or after visibility::make attribute" )] #[allow(unreachable_pub)] -#[expect( - clippy::partial_pub_fields, - reason = "public field is not a part of the public API and is used by benchmarks" -)] #[cfg_attr(feature = "__bench", visibility::make(pub))] pub(crate) struct UpdateFragmenter { code: UpdateCode, diff --git a/crates/ironrdp-server/src/encoder/mod.rs b/crates/ironrdp-server/src/encoder/mod.rs index 6355c232..1e6950da 100644 --- a/crates/ironrdp-server/src/encoder/mod.rs +++ b/crates/ironrdp-server/src/encoder/mod.rs @@ -31,16 +31,6 @@ enum CodecId { None = 0x0, } -impl CodecId { - #[expect( - clippy::as_conversions, - reason = "guarantees discriminant layout, and as is the only way to cast enum -> primitive" - )] - fn as_u8(self) -> u8 { - self as u8 - } -} - #[cfg_attr(feature = "__bench", visibility::make(pub))] #[derive(Debug)] pub(crate) struct UpdateEncoderCodecs { @@ -399,7 +389,7 @@ impl BitmapUpdateHandler for NoneHandler { for row in bitmap.data.chunks(bitmap.stride.get()).rev() { data.extend_from_slice(&row[..stride]); } - set_surface(bitmap, CodecId::None.as_u8(), &data) + set_surface(bitmap, CodecId::None as u8, &data) } } diff --git a/crates/ironrdp-server/src/encoder/rfx.rs b/crates/ironrdp-server/src/encoder/rfx.rs index 198cec1d..fd30d589 100644 --- a/crates/ironrdp-server/src/encoder/rfx.rs +++ b/crates/ironrdp-server/src/encoder/rfx.rs @@ -220,7 +220,6 @@ impl<'a> UpdateEncoder<'a> { } #[cfg(feature = "__bench")] -#[expect(clippy::missing_panics_doc, reason = "panics in benches are allowed")] pub(crate) mod bench { use super::*; diff --git a/crates/ironrdp-server/src/handler.rs b/crates/ironrdp-server/src/handler.rs index 0bcf6519..a1497167 100644 --- a/crates/ironrdp-server/src/handler.rs +++ b/crates/ironrdp-server/src/handler.rs @@ -97,14 +97,9 @@ impl From<(u16, fast_path::KeyboardFlags)> for KeyboardEvent { } impl From<(u16, scan_code::KeyboardFlags)> for KeyboardEvent { - #[expect( - clippy::as_conversions, - clippy::cast_possible_truncation, - reason = "we are truncating the value on purpose" - )] + #[expect(clippy::cast_possible_truncation)] // we are actually truncating the value fn from((key, flags): (u16, scan_code::KeyboardFlags)) -> Self { let extended = flags.contains(scan_code::KeyboardFlags::EXTENDED); - if flags.contains(scan_code::KeyboardFlags::RELEASE) { KeyboardEvent::Released { code: key as u8, @@ -136,11 +131,7 @@ impl From for KeyboardEvent { } impl From for KeyboardEvent { - #[expect( - clippy::as_conversions, - clippy::cast_possible_truncation, - reason = "we are truncating the value on purpose" - )] + #[expect(clippy::cast_possible_truncation)] // we are actually truncating the value fn from(value: SyncToggleFlags) -> Self { KeyboardEvent::Synchronize(SynchronizeFlags::from_bits_truncate(value.bits() as u8)) } diff --git a/crates/ironrdp-server/src/helper.rs b/crates/ironrdp-server/src/helper.rs index 53d6870f..38b76fa3 100644 --- a/crates/ironrdp-server/src/helper.rs +++ b/crates/ironrdp-server/src/helper.rs @@ -7,7 +7,8 @@ use anyhow::Context as _; use rustls_pemfile::{certs, pkcs8_private_keys}; use tokio_rustls::rustls::pki_types::pem::PemObject as _; use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer}; -use tokio_rustls::{rustls, TlsAcceptor}; +use tokio_rustls::rustls::{self}; +use tokio_rustls::TlsAcceptor; pub struct TlsIdentityCtx { pub certs: Vec>, diff --git a/crates/ironrdp-server/src/server.rs b/crates/ironrdp-server/src/server.rs index 9fe234d8..101ea406 100644 --- a/crates/ironrdp-server/src/server.rs +++ b/crates/ironrdp-server/src/server.rs @@ -21,7 +21,7 @@ use ironrdp_pdu::{decode_err, mcs, nego, rdp, Action, PduResult}; use ironrdp_svc::{server_encode_svc_messages, StaticChannelId, StaticChannelSet, SvcProcessor}; use ironrdp_tokio::{split_tokio_framed, unsplit_tokio_framed, FramedRead, FramedWrite, TokioFramed}; use rdpsnd::server::{RdpsndServer, RdpsndServerMessage}; -use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt as _}; +use tokio::io::{AsyncRead, AsyncWrite}; use tokio::net::{TcpListener, TcpStream}; use tokio::sync::{mpsc, oneshot, Mutex}; use tokio::task; @@ -349,20 +349,15 @@ impl RdpServer { ironrdp_acceptor::accept_credssp( &mut framed, &mut acceptor, - &mut ironrdp_tokio::reqwest::ReqwestNetworkClient::new(), client_name.into(), pub_key.clone(), None, + None, ) .await?; } - let framed = self.accept_finalize(framed, acceptor).await?; - debug!("Shutting down TLS connection"); - let (mut tls_stream, _) = framed.into_inner(); - if let Err(e) = tls_stream.shutdown().await { - debug!(?e, "TLS shutdown error"); - } + self.accept_finalize(framed, acceptor).await?; } BeginResult::Continue(framed) => { @@ -828,7 +823,7 @@ impl RdpServer { } async fn handle_fastpath(&mut self, input: FastPathInput) { - for event in input.input_events().iter().copied() { + for event in input.0 { let mut handler = self.handler.lock().await; match event { FastPathInputEvent::KeyboardEvent(flags, key) => { @@ -959,7 +954,7 @@ impl RdpServer { } } - async fn accept_finalize(&mut self, mut framed: TokioFramed, mut acceptor: Acceptor) -> Result> + async fn accept_finalize(&mut self, mut framed: TokioFramed, mut acceptor: Acceptor) -> Result<()> where S: AsyncRead + AsyncWrite + Sync + Send + Unpin, { @@ -987,12 +982,11 @@ impl RdpServer { framed = unsplit_tokio_framed(reader, writer); continue; } - RunState::Disconnect => { - let final_framed = unsplit_tokio_framed(reader, writer); - return Ok(final_framed); - } + RunState::Disconnect => break, } } + + Ok(()) } pub fn set_credentials(&mut self, creds: Option) { diff --git a/crates/ironrdp-session/CHANGELOG.md b/crates/ironrdp-session/CHANGELOG.md index 90011784..3b043327 100644 --- a/crates/ironrdp-session/CHANGELOG.md +++ b/crates/ironrdp-session/CHANGELOG.md @@ -6,9 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.8.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-session-v0.7.0...ironrdp-session-v0.8.0)] - 2025-12-18 - - ## [[0.6.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-session-v0.5.0...ironrdp-session-v0.6.0)] - 2025-08-29 ### Features diff --git a/crates/ironrdp-session/Cargo.toml b/crates/ironrdp-session/Cargo.toml index dd00422d..1d9436aa 100644 --- a/crates/ironrdp-session/Cargo.toml +++ b/crates/ironrdp-session/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-session" -version = "0.8.0" +version = "0.7.0" readme = "README.md" description = "State machines to drive an RDP session" edition.workspace = true @@ -22,11 +22,11 @@ qoiz = ["dep:zstd-safe", "qoi"] [dependencies] ironrdp-core = { path = "../ironrdp-core", version = "0.1" } # public -ironrdp-connector = { path = "../ironrdp-connector", version = "0.8" } # public # TODO: at some point, this dependency could be removed (good for compilation speed) +ironrdp-connector = { path = "../ironrdp-connector", version = "0.7" } # public # TODO: at some point, this dependency could be removed (good for compilation speed) ironrdp-svc = { path = "../ironrdp-svc", version = "0.5" } # public ironrdp-dvc = { path = "../ironrdp-dvc", version = "0.4" } # public ironrdp-error = { path = "../ironrdp-error", version = "0.1" } # public -ironrdp-graphics = { path = "../ironrdp-graphics", version = "0.7" } # public +ironrdp-graphics = { path = "../ironrdp-graphics", version = "0.6" } # public ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6", features = ["std"] } # public ironrdp-displaycontrol = { path = "../ironrdp-displaycontrol", version = "0.4" } tracing = { version = "0.1", features = ["log"] } diff --git a/crates/ironrdp-session/src/active_stage.rs b/crates/ironrdp-session/src/active_stage.rs index 75ef5499..5ae3f80e 100644 --- a/crates/ironrdp-session/src/active_stage.rs +++ b/crates/ironrdp-session/src/active_stage.rs @@ -68,7 +68,7 @@ impl ActiveStage { // Encoding fastpath response frame // PERF: unnecessary copy - let fastpath_input = FastPathInput::new(events.to_vec()).map_err(SessionError::decode)?; + let fastpath_input = FastPathInput(events.to_vec()); let frame = ironrdp_core::encode_vec(&fastpath_input).map_err(SessionError::encode)?; output.push(ActiveStageOutput::ResponseFrame(frame)); diff --git a/crates/ironrdp-session/src/fast_path.rs b/crates/ironrdp-session/src/fast_path.rs index 9826fbf9..8dbdc068 100644 --- a/crates/ironrdp-session/src/fast_path.rs +++ b/crates/ironrdp-session/src/fast_path.rs @@ -221,7 +221,7 @@ impl Processor { let decoded_pointer = Arc::new( DecodedPointer::decode_color_pointer_attribute(&pointer, bitmap_target) - .map_err(|e| SessionError::custom("failed to decode color pointer attribute", e))?, + .expect("Failed to decode color pointer attribute"), ); let _ = self @@ -261,7 +261,7 @@ impl Processor { let decoded_pointer = Arc::new( DecodedPointer::decode_pointer_attribute(&pointer, bitmap_target) - .map_err(|e| SessionError::custom("failed to decode pointer attribute", e))?, + .expect("Failed to decode pointer attribute"), ); let _ = self @@ -279,7 +279,7 @@ impl Processor { let decoded_pointer: Arc = Arc::new( DecodedPointer::decode_large_pointer_attribute(&pointer, bitmap_target) - .map_err(|e| SessionError::custom("failed to decode large pointer attribute", e))?, + .expect("Failed to decode large pointer attribute"), ); let _ = self @@ -298,7 +298,7 @@ impl Processor { // FIXME: This seems to be a way of special-handling the error case in FastPathUpdate::decode_cursor_with_code // to ignore the unsupported update PDUs, but this is a fragile logic and the rationale behind it is not // obvious. - if let DecodeErrorKind::InvalidField { field, reason } = e.kind() { + if let DecodeErrorKind::InvalidField { field, reason } = e.kind { warn!(field, reason, "Received invalid Fast-Path update"); processor_updates.push(UpdateKind::None); } else { diff --git a/crates/ironrdp-session/src/image.rs b/crates/ironrdp-session/src/image.rs index 88dedb54..7e27c3f1 100644 --- a/crates/ironrdp-session/src/image.rs +++ b/crates/ironrdp-session/src/image.rs @@ -72,6 +72,7 @@ struct PointerRenderingState { } #[expect(clippy::too_many_arguments)] +#[expect(clippy::cast_lossless)] // FIXME fn copy_cursor_data( from: &[u8], from_pos: (usize, usize), @@ -123,17 +124,11 @@ fn copy_cursor_data( continue; } - #[expect(clippy::as_conversions, reason = "(u16 >> 8) fits into u8 + hot loop")] - { - // Integer alpha blending, source represented as premultiplied alpha color, calculation in floating point - to[to_start + pixel * PIXEL_SIZE] = - src_r + ((u16::from(dest_r) * u16::from(255 - src_a)) >> 8) as u8; - to[to_start + pixel * PIXEL_SIZE + 1] = - src_g + ((u16::from(dest_g) * u16::from(255 - src_a)) >> 8) as u8; - to[to_start + pixel * PIXEL_SIZE + 2] = - src_b + ((u16::from(dest_b) * u16::from(255 - src_a)) >> 8) as u8; - // Framebuffer is always opaque, so we can skip alpha channel change - } + // Integer alpha blending, source represented as premultiplied alpha color, calculation in floating point + to[to_start + pixel * PIXEL_SIZE] = src_r + (((dest_r as u16) * (255 - src_a) as u16) >> 8) as u8; + to[to_start + pixel * PIXEL_SIZE + 1] = src_g + (((dest_g as u16) * (255 - src_a) as u16) >> 8) as u8; + to[to_start + pixel * PIXEL_SIZE + 2] = src_b + (((dest_b as u16) * (255 - src_a) as u16) >> 8) as u8; + // Framebuffer is always opaque, so we can skip alpha channel change } } else { to[to_start..to_start + width * PIXEL_SIZE] @@ -232,13 +227,6 @@ impl DecodedImage { return Ok(None); } - let pointer_src_rect_width = usize::from(self.pointer_src_rect.width()); - let pointer_src_rect_height = usize::from(self.pointer_src_rect.height()); - let pointer_draw_x = usize::from(self.pointer_draw_x); - let pointer_draw_y = usize::from(self.pointer_draw_y); - let width = usize::from(self.width); - let height = usize::from(self.height); - match &layer { PointerLayer::Background => { if self.pointer_backbuffer.is_empty() { @@ -249,12 +237,15 @@ impl DecodedImage { copy_cursor_data( &self.pointer_backbuffer, (0, 0), - pointer_src_rect_width * 4, + self.pointer_src_rect.width() as usize * 4, &mut self.data, - width * 4, - (pointer_draw_x, pointer_draw_y), - (pointer_src_rect_width, pointer_src_rect_height), - (width, height), + self.width as usize * 4, + (self.pointer_draw_x as usize, self.pointer_draw_y as usize), + ( + self.pointer_src_rect.width() as usize, + self.pointer_src_rect.height() as usize, + ), + (self.width as usize, self.height as usize), false, ); } @@ -263,34 +254,37 @@ impl DecodedImage { let buffer_size = self .pointer_backbuffer .len() - .max(pointer_src_rect_width * pointer_src_rect_height * 4); + .max(self.pointer_src_rect.width() as usize * self.pointer_src_rect.height() as usize * 4); self.pointer_backbuffer.resize(buffer_size, 0); copy_cursor_data( &self.data, - (pointer_draw_x, pointer_draw_y), - width * 4, + (self.pointer_draw_x as usize, self.pointer_draw_y as usize), + self.width as usize * 4, &mut self.pointer_backbuffer, - pointer_src_rect_width * 4, + self.pointer_src_rect.width() as usize * 4, (0, 0), - (pointer_src_rect_width, pointer_src_rect_height), - (width, height), + ( + self.pointer_src_rect.width() as usize, + self.pointer_src_rect.height() as usize, + ), + (self.width as usize, self.height as usize), false, ); // Draw pointer (with compositing) copy_cursor_data( pointer.bitmap_data.as_slice(), - ( - usize::from(self.pointer_src_rect.left), - usize::from(self.pointer_src_rect.top), - ), + (self.pointer_src_rect.left as usize, self.pointer_src_rect.top as usize), usize::from(pointer.width) * 4, &mut self.data, - width * 4, - (pointer_draw_x, pointer_draw_y), - (pointer_src_rect_width, pointer_src_rect_height), - (width, height), + self.width as usize * 4, + (self.pointer_draw_x as usize, self.pointer_draw_y as usize), + ( + self.pointer_src_rect.width() as usize, + self.pointer_src_rect.height() as usize, + ), + (self.width as usize, self.height as usize), true, ); } @@ -318,6 +312,7 @@ impl DecodedImage { } } + #[expect(clippy::cast_possible_wrap)] // FIXME fn recalculate_pointer_geometry(&mut self) { let x = self.pointer_x; let y = self.pointer_y; @@ -327,10 +322,10 @@ impl DecodedImage { _ => return, }; - let left_virtual = i32::from(x) - i32::from(pointer.hotspot_x); - let top_virtual = i32::from(y) - i32::from(pointer.hotspot_y); - let right_virtual = left_virtual + i32::from(pointer.width) - 1; - let bottom_virtual = top_virtual + i32::from(pointer.height) - 1; + let left_virtual = x as i16 - pointer.hotspot_x as i16; + let top_virtual = y as i16 - pointer.hotspot_y as i16; + let right_virtual = left_virtual + pointer.width as i16 - 1; + let bottom_virtual = top_virtual + pointer.height as i16 - 1; let (left, draw_x) = if left_virtual < 0 { // Cut left side if required @@ -347,7 +342,7 @@ impl DecodedImage { }; // Cut right side if required - let right = if right_virtual >= i32::from(self.width - 1) { + let right = if right_virtual >= (self.width - 1) as i16 { if draw_x + 1 >= self.width { // Pointer is completely out of bounds horizontally self.pointer_visible_on_screen = false; @@ -360,7 +355,7 @@ impl DecodedImage { }; // Cut bottom side if required - let bottom = if bottom_virtual >= i32::from(self.height - 1) { + let bottom = if bottom_virtual >= (self.height - 1) as i16 { if (draw_y + 1) >= self.height { // Pointer is completely out of bounds vertically self.pointer_visible_on_screen = false; @@ -544,7 +539,7 @@ impl DecodedImage { const SRC_COLOR_DEPTH: usize = 2; const DST_COLOR_DEPTH: usize = 4; - let image_width = usize::from(self.width); + let image_width = self.width as usize; let rectangle_width = usize::from(update_rectangle.width()); let top = usize::from(update_rectangle.top); let left = usize::from(update_rectangle.left); @@ -591,7 +586,7 @@ impl DecodedImage { const SRC_COLOR_DEPTH: usize = 3; const DST_COLOR_DEPTH: usize = 4; - let image_width = usize::from(self.width); + let image_width = self.width as usize; let top = usize::from(update_rectangle.top); let left = usize::from(update_rectangle.left); @@ -641,7 +636,7 @@ impl DecodedImage { const SRC_COLOR_DEPTH: usize = 4; const DST_COLOR_DEPTH: usize = 4; - let image_width = usize::from(self.width); + let image_width = self.width as usize; let rectangle_width = usize::from(update_rectangle.width()); let top = usize::from(update_rectangle.top); let left = usize::from(update_rectangle.left); diff --git a/crates/ironrdp-session/src/lib.rs b/crates/ironrdp-session/src/lib.rs index 8b3d62a4..54a3721c 100644 --- a/crates/ironrdp-session/src/lib.rs +++ b/crates/ironrdp-session/src/lib.rs @@ -110,7 +110,7 @@ pub trait SessionResultExt { impl SessionResultExt for SessionResult { fn with_context(self, context: &'static str) -> Self { self.map_err(|mut e| { - e.set_context(context); + e.context = context; e }) } diff --git a/crates/ironrdp-session/src/rfx.rs b/crates/ironrdp-session/src/rfx.rs index 4f115a6b..7bd21d6d 100644 --- a/crates/ironrdp-session/src/rfx.rs +++ b/crates/ironrdp-session/src/rfx.rs @@ -187,11 +187,10 @@ struct DecodingTileContext { impl DecodingTileContext { fn new() -> Self { - let tile_size = usize::from(TILE_SIZE); Self { - tile_output: vec![0; tile_size * tile_size * 4], - ycbcr_buffer: vec![vec![0; tile_size * tile_size]; 3], - ycbcr_temp_buffer: vec![0; tile_size * tile_size], + tile_output: vec![0; TILE_SIZE as usize * TILE_SIZE as usize * 4], + ycbcr_buffer: vec![vec![0; TILE_SIZE as usize * TILE_SIZE as usize]; 3], + ycbcr_temp_buffer: vec![0; TILE_SIZE as usize * TILE_SIZE as usize], } } } diff --git a/crates/ironrdp-testsuite-core/Cargo.toml b/crates/ironrdp-testsuite-core/Cargo.toml index e2e29a1d..217cc8a9 100644 --- a/crates/ironrdp-testsuite-core/Cargo.toml +++ b/crates/ironrdp-testsuite-core/Cargo.toml @@ -26,6 +26,7 @@ array-concat = "0.5" expect-test = "1" ironrdp-core.path = "../ironrdp-core" ironrdp-pdu.path = "../ironrdp-pdu" +lazy_static.workspace = true # TODO: remove in favor of https://doc.rust-lang.org/std/sync/struct.OnceLock.html paste = "1" visibility = { version = "0.1", optional = true } diff --git a/crates/ironrdp-testsuite-core/src/capsets.rs b/crates/ironrdp-testsuite-core/src/capsets.rs index 1f9974d6..be4c8b56 100644 --- a/crates/ironrdp-testsuite-core/src/capsets.rs +++ b/crates/ironrdp-testsuite-core/src/capsets.rs @@ -1,9 +1,8 @@ -use std::sync::LazyLock; - use ironrdp_core::decode; use ironrdp_pdu::rdp::capability_sets::{ CapabilitySet, ClientConfirmActive, DemandActive, ServerDemandActive, SERVER_CHANNEL_ID, }; +use lazy_static::lazy_static; pub const SERVER_DEMAND_ACTIVE_BUFFER: [u8; 357] = [ 0x04, 0x00, // source descriptor length @@ -265,29 +264,28 @@ pub const CLIENT_MULTI_FRAGMENT_UPDATE_CAPABILITY_SET: [u8; 4] = [0x0, 0x0, 0x0, pub const CLIENT_WINDOW_LIST_CAPABILITY_SET: [u8; 7] = [0x1, 0x0, 0x0, 0x0, 0x3, 0xc, 0x0]; -pub static SERVER_DEMAND_ACTIVE: LazyLock = LazyLock::new(|| ServerDemandActive { - pdu: DemandActive { - source_descriptor: String::from("RDP"), - capability_sets: vec![ - CapabilitySet::Share(SERVER_SHARE_CAPABILITY_SET.to_vec()), - CapabilitySet::General(decode(SERVER_GENERAL_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::VirtualChannel(decode(SERVER_VIRTUAL_CHANNEL_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::DrawGdiPlus(SERVER_DRAW_GDI_PLUS_CAPABILITY_SET.to_vec()), - CapabilitySet::Font(SERVER_FONT_CAPABILITY_SET.to_vec()), - CapabilitySet::Bitmap(decode(SERVER_BITMAP_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::Order(decode(SERVER_ORDER_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::ColorCache(SERVER_COLOR_CACHE_CAPABILITY_SET.to_vec()), - CapabilitySet::BitmapCacheHostSupport(SERVER_BITMAP_CACHE_HOST_SUPPORT_CAPABILITY_SET.to_vec()), - CapabilitySet::Pointer(decode(SERVER_POINTER_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::Input(decode(SERVER_INPUT_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::Rail(SERVER_RAIL_CAPABILITY_SET.to_vec()), - CapabilitySet::WindowList(SERVER_WINDOW_LIST_CAPABILITY_SET.to_vec()), - ], - }, -}); - -pub static CLIENT_DEMAND_ACTIVE_WITH_INCOMPLETE_CAPABILITY_SET: LazyLock = - LazyLock::new(|| ClientConfirmActive { +lazy_static! { + pub static ref SERVER_DEMAND_ACTIVE: ServerDemandActive = ServerDemandActive { + pdu: DemandActive { + source_descriptor: String::from("RDP"), + capability_sets: vec![ + CapabilitySet::Share(SERVER_SHARE_CAPABILITY_SET.to_vec()), + CapabilitySet::General(decode(SERVER_GENERAL_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::VirtualChannel(decode(SERVER_VIRTUAL_CHANNEL_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::DrawGdiPlus(SERVER_DRAW_GDI_PLUS_CAPABILITY_SET.to_vec()), + CapabilitySet::Font(SERVER_FONT_CAPABILITY_SET.to_vec()), + CapabilitySet::Bitmap(decode(SERVER_BITMAP_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::Order(decode(SERVER_ORDER_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::ColorCache(SERVER_COLOR_CACHE_CAPABILITY_SET.to_vec()), + CapabilitySet::BitmapCacheHostSupport(SERVER_BITMAP_CACHE_HOST_SUPPORT_CAPABILITY_SET.to_vec()), + CapabilitySet::Pointer(decode(SERVER_POINTER_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::Input(decode(SERVER_INPUT_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::Rail(SERVER_RAIL_CAPABILITY_SET.to_vec()), + CapabilitySet::WindowList(SERVER_WINDOW_LIST_CAPABILITY_SET.to_vec()), + ], + } + }; + pub static ref CLIENT_DEMAND_ACTIVE_WITH_INCOMPLETE_CAPABILITY_SET: ClientConfirmActive = ClientConfirmActive { originator_id: SERVER_CHANNEL_ID, pdu: DemandActive { source_descriptor: String::from("MSTSC"), @@ -308,41 +306,41 @@ pub static CLIENT_DEMAND_ACTIVE_WITH_INCOMPLETE_CAPABILITY_SET: LazyLock = LazyLock::new(|| ClientConfirmActive { - originator_id: SERVER_CHANNEL_ID, - pdu: DemandActive { - source_descriptor: String::from("MSTSC"), - capability_sets: vec![ - CapabilitySet::General(decode(CLIENT_GENERAL_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::Bitmap(decode(CLIENT_BITMAP_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::Order(decode(CLIENT_ORDER_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::BitmapCacheRev2(decode(CLIENT_BITMAP_CACHE_REV_2_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::ColorCache(CLIENT_COLOR_CACHE_CAPABILITY_SET.to_vec()), - CapabilitySet::WindowActivation(CLIENT_WINDOW_ACTIVATION_CAPABILITY_SET.to_vec()), - CapabilitySet::Control(CLIENT_CONTROL_CAPABILITY_SET.to_vec()), - CapabilitySet::Pointer(decode(CLIENT_POINTER_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::Share(CLIENT_SHARE_CAPABILITY_SET.to_vec()), - CapabilitySet::Input(decode(CLIENT_INPUT_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::Sound(decode(CLIENT_SOUND_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::Font(CLIENT_FONT_CAPABILITY_SET.to_vec()), - CapabilitySet::GlyphCache(decode(CLIENT_GLYPH_CACHE_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::Brush(decode(CLIENT_BRUSH_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::OffscreenBitmapCache(decode(CLIENT_OFFSCREEN_BITMAP_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::VirtualChannel(decode(CLIENT_VIRTUAL_CHANNEL_CAPABILITY_SET.as_ref()).unwrap()), - CapabilitySet::DrawNineGridCache(CLIENT_DRAW_NINE_GRID_CACHE_CAPABILITY_SET.to_vec()), - CapabilitySet::DrawGdiPlus(CLIENT_DRAW_GDI_PLUS_CAPABILITY_SET.to_vec()), - ], - }, -}); + } + }; + pub static ref CLIENT_DEMAND_ACTIVE: ClientConfirmActive = ClientConfirmActive { + originator_id: SERVER_CHANNEL_ID, + pdu: DemandActive { + source_descriptor: String::from("MSTSC"), + capability_sets: vec![ + CapabilitySet::General(decode(CLIENT_GENERAL_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::Bitmap(decode(CLIENT_BITMAP_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::Order(decode(CLIENT_ORDER_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::BitmapCacheRev2(decode(CLIENT_BITMAP_CACHE_REV_2_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::ColorCache(CLIENT_COLOR_CACHE_CAPABILITY_SET.to_vec()), + CapabilitySet::WindowActivation(CLIENT_WINDOW_ACTIVATION_CAPABILITY_SET.to_vec()), + CapabilitySet::Control(CLIENT_CONTROL_CAPABILITY_SET.to_vec()), + CapabilitySet::Pointer(decode(CLIENT_POINTER_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::Share(CLIENT_SHARE_CAPABILITY_SET.to_vec()), + CapabilitySet::Input(decode(CLIENT_INPUT_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::Sound(decode(CLIENT_SOUND_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::Font(CLIENT_FONT_CAPABILITY_SET.to_vec()), + CapabilitySet::GlyphCache(decode(CLIENT_GLYPH_CACHE_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::Brush(decode(CLIENT_BRUSH_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::OffscreenBitmapCache(decode(CLIENT_OFFSCREEN_BITMAP_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::VirtualChannel(decode(CLIENT_VIRTUAL_CHANNEL_CAPABILITY_SET.as_ref()).unwrap()), + CapabilitySet::DrawNineGridCache(CLIENT_DRAW_NINE_GRID_CACHE_CAPABILITY_SET.to_vec()), + CapabilitySet::DrawGdiPlus(CLIENT_DRAW_GDI_PLUS_CAPABILITY_SET.to_vec()), + ], + } + }; +} diff --git a/crates/ironrdp-testsuite-core/src/client_info.rs b/crates/ironrdp-testsuite-core/src/client_info.rs index 12c21b11..2db443c6 100644 --- a/crates/ironrdp-testsuite-core/src/client_info.rs +++ b/crates/ironrdp-testsuite-core/src/client_info.rs @@ -1,5 +1,3 @@ -use std::sync::LazyLock; - use ironrdp_pdu::rdp::client_info::{ AddressFamily, ClientInfo, ClientInfoFlags, CompressionType, Credentials, DayOfWeek, DayOfWeekOccurrence, ExtendedClientInfo, ExtendedClientOptionalInfo, Month, OptionalSystemTime, PerformanceFlags, SystemTime, @@ -83,73 +81,75 @@ pub const CLIENT_INFO_BUFFER_ANSI: [u8; 301] = [ 0x01, 0x00, 0x00, 0x00, // performance flags ]; -pub static CLIENT_INFO_UNICODE: LazyLock = LazyLock::new(|| ClientInfo { - code_page: 0x0409_0409, - flags: ClientInfoFlags::MOUSE - | ClientInfoFlags::DISABLE_CTRL_ALT_DEL - | ClientInfoFlags::UNICODE - | ClientInfoFlags::MAXIMIZE_SHELL - | ClientInfoFlags::COMPRESSION - | ClientInfoFlags::ENABLE_WINDOWS_KEY - | ClientInfoFlags::FORCE_ENCRYPTED_CS_PDU, - compression_type: CompressionType::K64, - credentials: Credentials { - username: String::from("eltons"), - password: String::from(""), - domain: Some(String::from("NTDEV")), - }, - alternate_shell: String::from(""), - work_dir: String::from(""), - extra_info: ExtendedClientInfo { - address_family: AddressFamily::INET, - address: String::from("157.59.242.156"), - dir: String::from("C:\\depots\\w2k3_1\\termsrv\\newclient\\lib\\win32\\obj\\i386\\mstscax.dll"), - optional_data: ExtendedClientOptionalInfo::builder() - .timezone(TimezoneInfo { - bias: 480, - standard_name: String::from("Pacific Standard Time"), - standard_date: OptionalSystemTime(Some(SystemTime { - month: Month::October, - day_of_week: DayOfWeek::Sunday, - day: DayOfWeekOccurrence::Last, - hour: 2, - minute: 0, - second: 0, - milliseconds: 0, - })), - standard_bias: 0, - daylight_name: String::from("Pacific Daylight Time"), - daylight_date: OptionalSystemTime(Some(SystemTime { - month: Month::April, - day_of_week: DayOfWeek::Sunday, - day: DayOfWeekOccurrence::First, - hour: 2, - minute: 0, - second: 0, - milliseconds: 0, - })), - daylight_bias: -60, - }) - .session_id(0) - .performance_flags(PerformanceFlags::DISABLE_WALLPAPER) - .build(), - }, -}); +lazy_static::lazy_static! { + pub static ref CLIENT_INFO_UNICODE: ClientInfo = ClientInfo { + code_page: 0x0409_0409, + flags: ClientInfoFlags::MOUSE + | ClientInfoFlags::DISABLE_CTRL_ALT_DEL + | ClientInfoFlags::UNICODE + | ClientInfoFlags::MAXIMIZE_SHELL + | ClientInfoFlags::COMPRESSION + | ClientInfoFlags::ENABLE_WINDOWS_KEY + | ClientInfoFlags::FORCE_ENCRYPTED_CS_PDU, + compression_type: CompressionType::K64, + credentials: Credentials { + username: String::from("eltons"), + password: String::from(""), + domain: Some(String::from("NTDEV")) + }, + alternate_shell: String::from(""), + work_dir: String::from(""), + extra_info: ExtendedClientInfo { + address_family: AddressFamily::INET, + address: String::from("157.59.242.156"), + dir: String::from("C:\\depots\\w2k3_1\\termsrv\\newclient\\lib\\win32\\obj\\i386\\mstscax.dll"), + optional_data: ExtendedClientOptionalInfo::builder() + .timezone(TimezoneInfo { + bias: 480, + standard_name: String::from("Pacific Standard Time"), + standard_date: OptionalSystemTime(Some(SystemTime { + month: Month::October, + day_of_week: DayOfWeek::Sunday, + day: DayOfWeekOccurrence::Last, + hour: 2, + minute: 0, + second: 0, + milliseconds: 0, + })), + standard_bias: 0, + daylight_name: String::from("Pacific Daylight Time"), + daylight_date: OptionalSystemTime(Some(SystemTime { + month: Month::April, + day_of_week: DayOfWeek::Sunday, + day: DayOfWeekOccurrence::First, + hour: 2, + minute: 0, + second: 0, + milliseconds: 0, + })), + daylight_bias: -60, + }) + .session_id(0) + .performance_flags(PerformanceFlags::DISABLE_WALLPAPER) + .build(), + }, + }; -pub static CLIENT_INFO_ANSI: LazyLock = LazyLock::new(|| { - let mut client_info = CLIENT_INFO_UNICODE.clone(); - client_info.flags -= ClientInfoFlags::UNICODE; - client_info -}); + pub static ref CLIENT_INFO_ANSI: ClientInfo = { + let mut client_info = CLIENT_INFO_UNICODE.clone(); + client_info.flags -= ClientInfoFlags::UNICODE; + client_info + }; -pub static CLIENT_INFO_UNICODE_WITHOUT_OPTIONAL_FIELDS: LazyLock = LazyLock::new(|| { - let mut client_info = CLIENT_INFO_UNICODE.clone(); - client_info.extra_info.optional_data = ExtendedClientOptionalInfo::default(); - client_info -}); + pub static ref CLIENT_INFO_UNICODE_WITHOUT_OPTIONAL_FIELDS: ClientInfo = { + let mut client_info = CLIENT_INFO_UNICODE.clone(); + client_info.extra_info.optional_data = ExtendedClientOptionalInfo::default(); + client_info + }; -pub static CLIENT_INFO_BUFFER_UNICODE_WITHOUT_OPTIONAL_FIELDS: LazyLock> = LazyLock::new(|| { - let mut buffer = CLIENT_INFO_BUFFER_UNICODE.to_vec(); - buffer.truncate(CLIENT_INFO_BUFFER_UNICODE_WITHOUT_OPTIONAL_FIELDS_LEN); - buffer -}); + pub static ref CLIENT_INFO_BUFFER_UNICODE_WITHOUT_OPTIONAL_FIELDS: Vec = { + let mut buffer = CLIENT_INFO_BUFFER_UNICODE.to_vec(); + buffer.truncate(CLIENT_INFO_BUFFER_UNICODE_WITHOUT_OPTIONAL_FIELDS_LEN); + buffer + }; +} diff --git a/crates/ironrdp-testsuite-core/src/cluster_data.rs b/crates/ironrdp-testsuite-core/src/cluster_data.rs index 165430a9..7729c00f 100644 --- a/crates/ironrdp-testsuite-core/src/cluster_data.rs +++ b/crates/ironrdp-testsuite-core/src/cluster_data.rs @@ -1,11 +1,12 @@ -use std::sync::LazyLock; - use ironrdp_pdu::gcc::{ClientClusterData, RedirectionFlags, RedirectionVersion}; +use lazy_static::lazy_static; pub const CLUSTER_DATA_BUFFER: [u8; 8] = [0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; -pub static CLUSTER_DATA: LazyLock = LazyLock::new(|| ClientClusterData { - flags: RedirectionFlags::REDIRECTION_SUPPORTED, - redirection_version: RedirectionVersion::V4, - redirected_session_id: 0, -}); +lazy_static! { + pub static ref CLUSTER_DATA: ClientClusterData = ClientClusterData { + flags: RedirectionFlags::REDIRECTION_SUPPORTED, + redirection_version: RedirectionVersion::V4, + redirected_session_id: 0, + }; +} diff --git a/crates/ironrdp-testsuite-core/src/conference_create.rs b/crates/ironrdp-testsuite-core/src/conference_create.rs index 92ab3344..d90398fb 100644 --- a/crates/ironrdp-testsuite-core/src/conference_create.rs +++ b/crates/ironrdp-testsuite-core/src/conference_create.rs @@ -1,7 +1,6 @@ -use std::sync::LazyLock; - use array_concat::{concat_arrays, concat_arrays_size}; use ironrdp_pdu::gcc::{ConferenceCreateRequest, ConferenceCreateResponse}; +use lazy_static::lazy_static; use crate::gcc; @@ -15,12 +14,13 @@ pub const CONFERENCE_CREATE_RESPONSE_PREFIX_BUFFER: [u8; 24] = [ 0x63, 0x44, 0x6e, 0x81, 0x08, ]; -pub static CONFERENCE_CREATE_REQUEST: LazyLock = LazyLock::new(|| { - ConferenceCreateRequest::new(gcc::CLIENT_GCC_WITH_CLUSTER_OPTIONAL_FIELD.clone()).expect("should not fail") -}); -pub static CONFERENCE_CREATE_RESPONSE: LazyLock = LazyLock::new(|| { - ConferenceCreateResponse::new(0x79f3, gcc::SERVER_GCC_WITHOUT_OPTIONAL_FIELDS.clone()).expect("should not fail") -}); +lazy_static! { + pub static ref CONFERENCE_CREATE_REQUEST: ConferenceCreateRequest = + ConferenceCreateRequest::new(gcc::CLIENT_GCC_WITH_CLUSTER_OPTIONAL_FIELD.clone()).expect("should not fail"); + pub static ref CONFERENCE_CREATE_RESPONSE: ConferenceCreateResponse = + ConferenceCreateResponse::new(0x79f3, gcc::SERVER_GCC_WITHOUT_OPTIONAL_FIELDS.clone(),) + .expect("should not fail"); +} pub const CONFERENCE_CREATE_REQUEST_BUFFER: [u8; concat_arrays_size!( CONFERENCE_CREATE_REQUEST_PREFIX_BUFFER, diff --git a/crates/ironrdp-testsuite-core/src/core_data.rs b/crates/ironrdp-testsuite-core/src/core_data.rs index 78a08d8f..e552727b 100644 --- a/crates/ironrdp-testsuite-core/src/core_data.rs +++ b/crates/ironrdp-testsuite-core/src/core_data.rs @@ -1,5 +1,3 @@ -use std::sync::LazyLock; - use array_concat::{concat_arrays, concat_arrays_size}; use ironrdp_pdu::gcc::{ ClientCoreData, ClientCoreOptionalData, ClientEarlyCapabilityFlags, ColorDepth, ConnectionType, HighColorDepth, @@ -7,6 +5,7 @@ use ironrdp_pdu::gcc::{ SupportedColorDepths, }; use ironrdp_pdu::nego::SecurityProtocol; +use lazy_static::lazy_static; pub const CLIENT_CORE_DATA_BUFFER: [u8; 128] = [ 0x04, 0x00, 0x08, 0x00, // version @@ -58,59 +57,55 @@ pub const CLIENT_OPTIONAL_CORE_DATA_FROM_DESKTOP_PHYSICAL_WIDTH_TO_DEVICE_SCALE_ 0x8c, 0x00, 0x00, 0x00, // device scale factor ]; -pub static CLIENT_CORE_DATA_WITHOUT_OPTIONAL_FIELDS: LazyLock = LazyLock::new(|| ClientCoreData { - version: RdpVersion::V5_PLUS, - desktop_width: 1280, - desktop_height: 1024, - color_depth: ColorDepth::Bpp4, - sec_access_sequence: SecureAccessSequence::Del, - keyboard_layout: 1033, - client_build: 3790, - client_name: String::from("ELTONS-DEV2"), - keyboard_type: KeyboardType::IbmEnhanced, - keyboard_subtype: 0, - keyboard_functional_keys_count: 12, - ime_file_name: String::new(), - optional_data: ClientCoreOptionalData::default(), -}); - -pub static CLIENT_OPTIONAL_CORE_DATA_TO_HIGH_COLOR_DEPTH: LazyLock = LazyLock::new(|| { - let mut data = CLIENT_CORE_DATA_WITHOUT_OPTIONAL_FIELDS.clone(); - data.optional_data.post_beta2_color_depth = Some(ColorDepth::Bpp8); - data.optional_data.client_product_id = Some(1); - data.optional_data.serial_number = Some(0); - data -}); - -pub static CLIENT_OPTIONAL_CORE_DATA_TO_SERVER_SELECTED_PROTOCOL: LazyLock = LazyLock::new(|| { - let mut data = CLIENT_OPTIONAL_CORE_DATA_TO_HIGH_COLOR_DEPTH.clone(); - data.optional_data.high_color_depth = Some(HighColorDepth::Bpp24); - data.optional_data.supported_color_depths = - Some(SupportedColorDepths::BPP24 | SupportedColorDepths::BPP16 | SupportedColorDepths::BPP15); - data.optional_data.early_capability_flags = Some(ClientEarlyCapabilityFlags::SUPPORT_ERR_INFO_PDU); - data.optional_data.dig_product_id = Some(String::from("69712-783-0357974-42714")); - data.optional_data.connection_type = Some(ConnectionType::NotUsed); - data.optional_data.server_selected_protocol = Some(SecurityProtocol::empty()); - data -}); - -pub static CLIENT_CORE_DATA_WITH_ALL_OPTIONAL_FIELDS: LazyLock = LazyLock::new(|| { - let mut data = CLIENT_OPTIONAL_CORE_DATA_TO_SERVER_SELECTED_PROTOCOL.clone(); - data.optional_data.desktop_physical_width = Some(5000); - data.optional_data.desktop_physical_height = Some(3000); - data.optional_data.desktop_orientation = Some(90); - data.optional_data.desktop_scale_factor = Some(200); - data.optional_data.device_scale_factor = Some(140); - data -}); -pub static CLIENT_CORE_DATA_WITH_ALL_OPTIONAL_FIELDS_WITH_WANT_32_BPP_EARLY_FLAG: LazyLock = - LazyLock::new(|| { +lazy_static! { + pub static ref CLIENT_CORE_DATA_WITHOUT_OPTIONAL_FIELDS: ClientCoreData = ClientCoreData { + version: RdpVersion::V5_PLUS, + desktop_width: 1280, + desktop_height: 1024, + color_depth: ColorDepth::Bpp4, + sec_access_sequence: SecureAccessSequence::Del, + keyboard_layout: 1033, + client_build: 3790, + client_name: String::from("ELTONS-DEV2"), + keyboard_type: KeyboardType::IbmEnhanced, + keyboard_subtype: 0, + keyboard_functional_keys_count: 12, + ime_file_name: String::new(), + optional_data: ClientCoreOptionalData::default(), + }; + pub static ref CLIENT_OPTIONAL_CORE_DATA_TO_HIGH_COLOR_DEPTH: ClientCoreData = { + let mut data = CLIENT_CORE_DATA_WITHOUT_OPTIONAL_FIELDS.clone(); + data.optional_data.post_beta2_color_depth = Some(ColorDepth::Bpp8); + data.optional_data.client_product_id = Some(1); + data.optional_data.serial_number = Some(0); + data + }; + pub static ref CLIENT_OPTIONAL_CORE_DATA_TO_SERVER_SELECTED_PROTOCOL: ClientCoreData = { + let mut data = CLIENT_OPTIONAL_CORE_DATA_TO_HIGH_COLOR_DEPTH.clone(); + data.optional_data.high_color_depth = Some(HighColorDepth::Bpp24); + data.optional_data.supported_color_depths = + Some(SupportedColorDepths::BPP24 | SupportedColorDepths::BPP16 | SupportedColorDepths::BPP15); + data.optional_data.early_capability_flags = Some(ClientEarlyCapabilityFlags::SUPPORT_ERR_INFO_PDU); + data.optional_data.dig_product_id = Some(String::from("69712-783-0357974-42714")); + data.optional_data.connection_type = Some(ConnectionType::NotUsed); + data.optional_data.server_selected_protocol = Some(SecurityProtocol::empty()); + data + }; + pub static ref CLIENT_CORE_DATA_WITH_ALL_OPTIONAL_FIELDS: ClientCoreData = { + let mut data = CLIENT_OPTIONAL_CORE_DATA_TO_SERVER_SELECTED_PROTOCOL.clone(); + data.optional_data.desktop_physical_width = Some(5000); + data.optional_data.desktop_physical_height = Some(3000); + data.optional_data.desktop_orientation = Some(90); + data.optional_data.desktop_scale_factor = Some(200); + data.optional_data.device_scale_factor = Some(140); + data + }; + pub static ref CLIENT_CORE_DATA_WITH_ALL_OPTIONAL_FIELDS_WITH_WANT_32_BPP_EARLY_FLAG: ClientCoreData = { let mut data = CLIENT_CORE_DATA_WITH_ALL_OPTIONAL_FIELDS.clone(); data.optional_data.early_capability_flags = Some(ClientEarlyCapabilityFlags::WANT_32_BPP_SESSION); data - }); -pub static CLIENT_CORE_DATA_WITH_ALL_OPTIONAL_FIELDS_WITH_WANT_32_BPP_EARLY_FLAG_BUFFER: LazyLock> = - LazyLock::new(|| { + }; + pub static ref CLIENT_CORE_DATA_WITH_ALL_OPTIONAL_FIELDS_WITH_WANT_32_BPP_EARLY_FLAG_BUFFER: Vec = { let early_capability_flags = ClientEarlyCapabilityFlags::WANT_32_BPP_SESSION.bits().to_le_bytes(); let mut from_high_color_to_server_protocol = @@ -124,7 +119,8 @@ pub static CLIENT_CORE_DATA_WITH_ALL_OPTIONAL_FIELDS_WITH_WANT_32_BPP_EARLY_FLAG buffer.extend(CLIENT_OPTIONAL_CORE_DATA_FROM_DESKTOP_PHYSICAL_WIDTH_TO_DEVICE_SCALE_FACTOR_BUFFER.as_ref()); buffer - }); + }; +} pub const CLIENT_OPTIONAL_CORE_DATA_TO_HIGH_COLOR_DEPTH_BUFFER_BUFFER: [u8; concat_arrays_size!( CLIENT_CORE_DATA_BUFFER, @@ -162,28 +158,29 @@ pub const FLAGS_BUFFER: [u8; 4] = [ 0x01, 0x00, 0x00, 0x00, // early capability flags ]; -pub static SERVER_CORE_DATA: LazyLock = LazyLock::new(|| ServerCoreData { - version: RdpVersion::V5_PLUS, - optional_data: ServerCoreOptionalData { - client_requested_protocols: None, - early_capability_flags: None, - }, -}); -pub static SERVER_CORE_DATA_TO_FLAGS: LazyLock = LazyLock::new(|| ServerCoreData { - version: RdpVersion::V5_PLUS, - optional_data: ServerCoreOptionalData { - client_requested_protocols: Some(SecurityProtocol::empty()), - early_capability_flags: None, - }, -}); - -pub static SERVER_CORE_DATA_WITH_ALL_OPTIONAL_FIELDS: LazyLock = LazyLock::new(|| ServerCoreData { - version: RdpVersion::V5_PLUS, - optional_data: ServerCoreOptionalData { - client_requested_protocols: Some(SecurityProtocol::empty()), - early_capability_flags: Some(ServerEarlyCapabilityFlags::EDGE_ACTIONS_SUPPORTED_V1), - }, -}); +lazy_static! { + pub static ref SERVER_CORE_DATA: ServerCoreData = ServerCoreData { + version: RdpVersion::V5_PLUS, + optional_data: ServerCoreOptionalData { + client_requested_protocols: None, + early_capability_flags: None, + }, + }; + pub static ref SERVER_CORE_DATA_TO_FLAGS: ServerCoreData = ServerCoreData { + version: RdpVersion::V5_PLUS, + optional_data: ServerCoreOptionalData { + client_requested_protocols: Some(SecurityProtocol::empty()), + early_capability_flags: None, + }, + }; + pub static ref SERVER_CORE_DATA_WITH_ALL_OPTIONAL_FIELDS: ServerCoreData = ServerCoreData { + version: RdpVersion::V5_PLUS, + optional_data: ServerCoreOptionalData { + client_requested_protocols: Some(SecurityProtocol::empty()), + early_capability_flags: Some(ServerEarlyCapabilityFlags::EDGE_ACTIONS_SUPPORTED_V1), + }, + }; +} pub const SERVER_CORE_DATA_TO_REQUESTED_PROTOCOL_BUFFER: [u8; concat_arrays_size!( SERVER_CORE_DATA_BUFFER, diff --git a/crates/ironrdp-testsuite-core/src/gcc.rs b/crates/ironrdp-testsuite-core/src/gcc.rs index 1ebe270e..6c9a0466 100644 --- a/crates/ironrdp-testsuite-core/src/gcc.rs +++ b/crates/ironrdp-testsuite-core/src/gcc.rs @@ -1,7 +1,6 @@ -use std::sync::LazyLock; - use array_concat::{concat_arrays, concat_arrays_size}; use ironrdp_pdu::gcc::{ClientGccBlocks, ClientGccType, ServerGccBlocks, ServerGccType}; +use lazy_static::lazy_static; use crate::cluster_data::{CLUSTER_DATA, CLUSTER_DATA_BUFFER}; use crate::core_data::{ @@ -42,7 +41,6 @@ const fn make_gcc_block_buffer(data_type: u16, buffer: &[u8]) -> let array = copy_slice(&data_type.to_le_bytes(), [0; N], 0); - #[expect(clippy::as_conversions, reason = "must be const casts")] let length = (buffer.len() + USER_HEADER_LEN) as u16; let array = copy_slice(&length.to_le_bytes(), array, 2); @@ -127,42 +125,43 @@ pub const SERVER_GCC_WITH_OPTIONAL_FIELDS_IN_DIFFERENT_ORDER_BUFFER: [u8; concat SERVER_GCC_MULTI_TRANSPORT_CHANNEL_BLOCK_BUFFER ); -pub static CLIENT_GCC_WITHOUT_OPTIONAL_FIELDS: LazyLock = LazyLock::new(|| ClientGccBlocks { - core: CLIENT_OPTIONAL_CORE_DATA_TO_SERVER_SELECTED_PROTOCOL.clone(), - security: CLIENT_SECURITY_DATA.clone(), - network: Some(CLIENT_NETWORK_DATA_WITH_CHANNELS.clone()), - cluster: None, - monitor: None, - message_channel: None, - multi_transport_channel: None, - monitor_extended: None, -}); -pub static CLIENT_GCC_WITH_CLUSTER_OPTIONAL_FIELD: LazyLock = LazyLock::new(|| { - let mut data = CLIENT_GCC_WITHOUT_OPTIONAL_FIELDS.clone(); - data.cluster = Some(CLUSTER_DATA.clone()); - data -}); -pub static CLIENT_GCC_WITH_ALL_OPTIONAL_FIELDS: LazyLock = LazyLock::new(|| { - let mut data = CLIENT_GCC_WITH_CLUSTER_OPTIONAL_FIELD.clone(); - data.monitor = Some(crate::monitor_data::MONITOR_DATA_WITH_MONITORS.clone()); - data.monitor_extended = Some(crate::monitor_extended_data::MONITOR_DATA_WITH_MONITORS.clone()); - data -}); -pub static SERVER_GCC_WITHOUT_OPTIONAL_FIELDS: LazyLock = LazyLock::new(|| ServerGccBlocks { - core: SERVER_CORE_DATA_TO_FLAGS.clone(), - network: SERVER_NETWORK_DATA_WITH_CHANNELS_ID.clone(), - security: SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS.clone(), - message_channel: None, - multi_transport_channel: None, -}); -pub static SERVER_GCC_WITH_OPTIONAL_FIELDS: LazyLock = LazyLock::new(|| { - let mut data = SERVER_GCC_WITHOUT_OPTIONAL_FIELDS.clone(); - data.message_channel = Some(SERVER_GCC_MESSAGE_CHANNEL_BLOCK.clone()); - data.multi_transport_channel = Some(SERVER_GCC_MULTI_TRANSPORT_CHANNEL_BLOCK.clone()); - data -}); +lazy_static! { + pub static ref CLIENT_GCC_WITHOUT_OPTIONAL_FIELDS: ClientGccBlocks = ClientGccBlocks { + core: CLIENT_OPTIONAL_CORE_DATA_TO_SERVER_SELECTED_PROTOCOL.clone(), + security: CLIENT_SECURITY_DATA.clone(), + network: Some(CLIENT_NETWORK_DATA_WITH_CHANNELS.clone()), + cluster: None, + monitor: None, + message_channel: None, + multi_transport_channel: None, + monitor_extended: None, + }; + pub static ref CLIENT_GCC_WITH_CLUSTER_OPTIONAL_FIELD: ClientGccBlocks = { + let mut data = CLIENT_GCC_WITHOUT_OPTIONAL_FIELDS.clone(); + data.cluster = Some(CLUSTER_DATA.clone()); + data + }; + pub static ref CLIENT_GCC_WITH_ALL_OPTIONAL_FIELDS: ClientGccBlocks = { + let mut data = CLIENT_GCC_WITH_CLUSTER_OPTIONAL_FIELD.clone(); + data.monitor = Some(crate::monitor_data::MONITOR_DATA_WITH_MONITORS.clone()); + data.monitor_extended = Some(crate::monitor_extended_data::MONITOR_DATA_WITH_MONITORS.clone()); + data + }; + pub static ref SERVER_GCC_WITHOUT_OPTIONAL_FIELDS: ServerGccBlocks = ServerGccBlocks { + core: SERVER_CORE_DATA_TO_FLAGS.clone(), + network: SERVER_NETWORK_DATA_WITH_CHANNELS_ID.clone(), + security: SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS.clone(), + message_channel: None, + multi_transport_channel: None, + }; + pub static ref SERVER_GCC_WITH_OPTIONAL_FIELDS: ServerGccBlocks = { + let mut data = SERVER_GCC_WITHOUT_OPTIONAL_FIELDS.clone(); + data.message_channel = Some(SERVER_GCC_MESSAGE_CHANNEL_BLOCK.clone()); + data.multi_transport_channel = Some(SERVER_GCC_MULTI_TRANSPORT_CHANNEL_BLOCK.clone()); + data + }; +} -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const CLIENT_GCC_CORE_BLOCK_BUFFER: [u8; gcc_block_size( CLIENT_OPTIONAL_CORE_DATA_TO_SERVER_SELECTED_PROTOCOL_BUFFER, )] = make_gcc_block_buffer( @@ -170,22 +169,18 @@ pub const CLIENT_GCC_CORE_BLOCK_BUFFER: [u8; gcc_block_size( &CLIENT_OPTIONAL_CORE_DATA_TO_SERVER_SELECTED_PROTOCOL_BUFFER, ); -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const CLIENT_GCC_SECURITY_BLOCK_BUFFER: [u8; gcc_block_size(CLIENT_SECURITY_DATA_BUFFER)] = make_gcc_block_buffer(ClientGccType::SecurityData as u16, &CLIENT_SECURITY_DATA_BUFFER); -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const CLIENT_GCC_NETWORK_BLOCK_BUFFER: [u8; gcc_block_size(CLIENT_NETWORK_DATA_WITH_CHANNELS_BUFFER)] = make_gcc_block_buffer( ClientGccType::NetworkData as u16, &CLIENT_NETWORK_DATA_WITH_CHANNELS_BUFFER, ); -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const CLIENT_GCC_CLUSTER_BLOCK_BUFFER: [u8; gcc_block_size(CLUSTER_DATA_BUFFER)] = make_gcc_block_buffer(ClientGccType::ClusterData as u16, &CLUSTER_DATA_BUFFER); -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const CLIENT_GCC_MONITOR_BLOCK_BUFFER: [u8; gcc_block_size( crate::monitor_data::MONITOR_DATA_WITH_MONITORS_BUFFER, )] = make_gcc_block_buffer( @@ -193,7 +188,6 @@ pub const CLIENT_GCC_MONITOR_BLOCK_BUFFER: [u8; gcc_block_size( &crate::monitor_data::MONITOR_DATA_WITH_MONITORS_BUFFER, ); -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const CLIENT_GCC_MONITOR_EXTENDED_BLOCK_BUFFER: [u8; gcc_block_size( crate::monitor_extended_data::MONITOR_DATA_WITH_MONITORS_BUFFER, )] = make_gcc_block_buffer( @@ -201,28 +195,24 @@ pub const CLIENT_GCC_MONITOR_EXTENDED_BLOCK_BUFFER: [u8; gcc_block_size( &crate::monitor_extended_data::MONITOR_DATA_WITH_MONITORS_BUFFER, ); -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const SERVER_GCC_CORE_BLOCK_BUFFER: [u8; gcc_block_size(SERVER_CORE_DATA_TO_REQUESTED_PROTOCOL_BUFFER)] = make_gcc_block_buffer( ServerGccType::CoreData as u16, &SERVER_CORE_DATA_TO_REQUESTED_PROTOCOL_BUFFER, ); -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const SERVER_GCC_NETWORK_BLOCK_BUFFER: [u8; gcc_block_size(SERVER_NETWORK_DATA_WITH_CHANNELS_ID_BUFFER)] = make_gcc_block_buffer( ServerGccType::NetworkData as u16, &SERVER_NETWORK_DATA_WITH_CHANNELS_ID_BUFFER, ); -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const SERVER_GCC_SECURITY_BLOCK_BUFFER: [u8; gcc_block_size(SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_BUFFER)] = make_gcc_block_buffer( ServerGccType::SecurityData as u16, &SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_BUFFER, ); -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const SERVER_GCC_MESSAGE_CHANNEL_BLOCK_BUFFER: [u8; gcc_block_size( crate::message_channel_data::SERVER_GCC_MESSAGE_CHANNEL_BLOCK_BUFFER, )] = make_gcc_block_buffer( @@ -230,7 +220,6 @@ pub const SERVER_GCC_MESSAGE_CHANNEL_BLOCK_BUFFER: [u8; gcc_block_size( &crate::message_channel_data::SERVER_GCC_MESSAGE_CHANNEL_BLOCK_BUFFER, ); -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const SERVER_GCC_MULTI_TRANSPORT_CHANNEL_BLOCK_BUFFER: [u8; gcc_block_size( crate::multi_transport_channel_data::SERVER_GCC_MULTI_TRANSPORT_CHANNEL_BLOCK_BUFFER, )] = make_gcc_block_buffer( diff --git a/crates/ironrdp-testsuite-core/src/gfx.rs b/crates/ironrdp-testsuite-core/src/gfx.rs index b9616048..9adf797f 100644 --- a/crates/ironrdp-testsuite-core/src/gfx.rs +++ b/crates/ironrdp-testsuite-core/src/gfx.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_pdu::rdp::vc::dvc::gfx::{ClientPdu, ServerPdu}; +use lazy_static::lazy_static; use crate::graphics_messages::{ FRAME_ACKNOWLEDGE, FRAME_ACKNOWLEDGE_BUFFER, WIRE_TO_SURFACE_1, WIRE_TO_SURFACE_1_BUFFER, @@ -9,11 +8,11 @@ use crate::graphics_messages::{ pub const WIRE_TO_SURFACE_1_HEADER_BUFFER: [u8; 8] = [0x01, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00]; pub const FRAME_ACKNOWLEDGE_HEADER_BUFFER: [u8; 8] = [0x0d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00]; -pub static HEADER_WITH_WIRE_TO_SURFACE_1_BUFFER: LazyLock> = - LazyLock::new(|| [&WIRE_TO_SURFACE_1_HEADER_BUFFER[..], &WIRE_TO_SURFACE_1_BUFFER[..]].concat()); -pub static HEADER_WITH_FRAME_ACKNOWLEDGE_BUFFER: LazyLock> = - LazyLock::new(|| [&FRAME_ACKNOWLEDGE_HEADER_BUFFER[..], &FRAME_ACKNOWLEDGE_BUFFER[..]].concat()); -pub static HEADER_WITH_WIRE_TO_SURFACE_1: LazyLock = - LazyLock::new(|| ServerPdu::WireToSurface1(WIRE_TO_SURFACE_1.clone())); -pub static HEADER_WITH_FRAME_ACKNOWLEDGE: LazyLock = - LazyLock::new(|| ClientPdu::FrameAcknowledge(FRAME_ACKNOWLEDGE.clone())); +lazy_static! { + pub static ref HEADER_WITH_WIRE_TO_SURFACE_1_BUFFER: Vec = + [&WIRE_TO_SURFACE_1_HEADER_BUFFER[..], &WIRE_TO_SURFACE_1_BUFFER[..],].concat(); + pub static ref HEADER_WITH_FRAME_ACKNOWLEDGE_BUFFER: Vec = + [&FRAME_ACKNOWLEDGE_HEADER_BUFFER[..], &FRAME_ACKNOWLEDGE_BUFFER[..],].concat(); + pub static ref HEADER_WITH_WIRE_TO_SURFACE_1: ServerPdu = ServerPdu::WireToSurface1(WIRE_TO_SURFACE_1.clone()); + pub static ref HEADER_WITH_FRAME_ACKNOWLEDGE: ClientPdu = ClientPdu::FrameAcknowledge(FRAME_ACKNOWLEDGE.clone()); +} diff --git a/crates/ironrdp-testsuite-core/src/graphics_messages.rs b/crates/ironrdp-testsuite-core/src/graphics_messages.rs index ee0b4f0d..395f59c5 100644 --- a/crates/ironrdp-testsuite-core/src/graphics_messages.rs +++ b/crates/ironrdp-testsuite-core/src/graphics_messages.rs @@ -1,5 +1,3 @@ -use std::sync::LazyLock; - use ironrdp_pdu::gcc::{Monitor, MonitorFlags}; use ironrdp_pdu::geometry::InclusiveRectangle; use ironrdp_pdu::rdp::vc::dvc::gfx::{ @@ -10,6 +8,7 @@ use ironrdp_pdu::rdp::vc::dvc::gfx::{ PixelFormat, Point, QuantQuality, QueueDepth, ResetGraphicsPdu, SolidFillPdu, StartFramePdu, SurfaceToCachePdu, SurfaceToSurfacePdu, Timestamp, WireToSurface1Pdu, WireToSurface2Pdu, }; +use lazy_static::lazy_static; pub const WIRE_TO_SURFACE_1_BUFFER: [u8; 218] = [ 0x00, 0x00, 0x08, 0x00, 0x20, 0xa5, 0x03, 0xde, 0x02, 0xab, 0x03, 0xe7, 0x02, 0xc9, 0x00, 0x00, 0x00, 0x01, 0x0e, @@ -235,221 +234,222 @@ pub const AVC_444_MESSAGE_CORRECT_LEN: [u8; 88] = [ 0x1d, 0xe7, 0x97, 0xab, 0x80, 0x80, 0x80, ]; -pub static WIRE_TO_SURFACE_1: LazyLock = LazyLock::new(|| WireToSurface1Pdu { - surface_id: 0, - codec_id: Codec1Type::ClearCodec, - pixel_format: PixelFormat::XRgb, - destination_rectangle: InclusiveRectangle { - left: 933, - top: 734, - right: 939, - bottom: 743, - }, - bitmap_data: WIRE_TO_SURFACE_1_BUFFER[17..].to_vec(), -}); -pub static WIRE_TO_SURFACE_1_BITMAP_DATA: LazyLock> = LazyLock::new(|| WIRE_TO_SURFACE_1_BUFFER[17..].to_vec()); -pub static WIRE_TO_SURFACE_2: LazyLock = LazyLock::new(|| WireToSurface2Pdu { - surface_id: 0, - codec_id: Codec2Type::RemoteFxProgressive, - codec_context_id: 4, - pixel_format: PixelFormat::XRgb, - bitmap_data: WIRE_TO_SURFACE_2_BUFFER[13..].to_vec(), -}); -pub static WIRE_TO_SURFACE_2_BITMAP_DATA: LazyLock> = LazyLock::new(|| WIRE_TO_SURFACE_2_BUFFER[13..].to_vec()); -pub static DELETE_ENCODING_CONTEXT: LazyLock = LazyLock::new(|| DeleteEncodingContextPdu { - surface_id: 0, - codec_context_id: 1, -}); -pub static SOLID_FILL: LazyLock = LazyLock::new(|| SolidFillPdu { - surface_id: 0, - fill_pixel: Color { - b: 0, - g: 0, - r: 0, - xa: 0, - }, - rectangles: vec![InclusiveRectangle { - left: 0, - top: 0, - right: 64, - bottom: 64, - }], -}); -pub static SURFACE_TO_SURFACE: LazyLock = LazyLock::new(|| SurfaceToSurfacePdu { - source_surface_id: 0, - destination_surface_id: 0, - source_rectangle: InclusiveRectangle { - left: 200, - top: 60, - right: 676, - bottom: 148, - }, - destination_points: vec![Point { x: 128, y: 60 }], -}); -pub static SURFACE_TO_CACHE: LazyLock = LazyLock::new(|| SurfaceToCachePdu { - surface_id: 0, - cache_key: 0x113D_86DA_A6A3_7FB7, - cache_slot: 14, - source_rectangle: InclusiveRectangle { - left: 640, - top: 0, - right: 704, - bottom: 64, - }, -}); -pub static CACHE_TO_SURFACE: LazyLock = LazyLock::new(|| CacheToSurfacePdu { - cache_slot: 2, - surface_id: 0, - destination_points: vec![Point { x: 768, y: 320 }], -}); -pub static CREATE_SURFACE: LazyLock = LazyLock::new(|| CreateSurfacePdu { - surface_id: 0, - width: 1024, - height: 768, - pixel_format: PixelFormat::ARgb, -}); -pub static DELETE_SURFACE: LazyLock = LazyLock::new(|| DeleteSurfacePdu { surface_id: 0 }); -pub static RESET_GRAPHICS: LazyLock = LazyLock::new(|| ResetGraphicsPdu { - width: 1024, - height: 768, - monitors: vec![Monitor { - left: 0, - top: 0, - right: 1023, - bottom: 767, - flags: MonitorFlags::PRIMARY, - }], -}); -pub static MAP_SURFACE_TO_OUTPUT: LazyLock = LazyLock::new(|| MapSurfaceToOutputPdu { - surface_id: 0, - output_origin_x: 1, - output_origin_y: 2, -}); -pub static EVICT_CACHE_ENTRY: LazyLock = LazyLock::new(|| EvictCacheEntryPdu { cache_slot: 0 }); -pub static START_FRAME: LazyLock = LazyLock::new(|| StartFramePdu { - timestamp: Timestamp { - milliseconds: 247, - seconds: 58, - minutes: 27, - hours: 22, - }, - frame_id: 5, -}); -pub static END_FRAME: LazyLock = LazyLock::new(|| EndFramePdu { frame_id: 1 }); -pub static CAPABILITIES_CONFIRM: LazyLock = LazyLock::new(|| { - CapabilitiesConfirmPdu(CapabilitySet::V10_5 { +lazy_static! { + pub static ref WIRE_TO_SURFACE_1: WireToSurface1Pdu = WireToSurface1Pdu { + surface_id: 0, + codec_id: Codec1Type::ClearCodec, + pixel_format: PixelFormat::XRgb, + destination_rectangle: InclusiveRectangle { + left: 933, + top: 734, + right: 939, + bottom: 743 + }, + bitmap_data: WIRE_TO_SURFACE_1_BUFFER[17..].to_vec(), + }; + pub static ref WIRE_TO_SURFACE_1_BITMAP_DATA: Vec = WIRE_TO_SURFACE_1_BUFFER[17..].to_vec(); + pub static ref WIRE_TO_SURFACE_2: WireToSurface2Pdu = WireToSurface2Pdu { + surface_id: 0, + codec_id: Codec2Type::RemoteFxProgressive, + codec_context_id: 4, + pixel_format: PixelFormat::XRgb, + bitmap_data: WIRE_TO_SURFACE_2_BUFFER[13..].to_vec(), + }; + pub static ref WIRE_TO_SURFACE_2_BITMAP_DATA: Vec = WIRE_TO_SURFACE_2_BUFFER[13..].to_vec(); + pub static ref DELETE_ENCODING_CONTEXT: DeleteEncodingContextPdu = DeleteEncodingContextPdu { + surface_id: 0, + codec_context_id: 1, + }; + pub static ref SOLID_FILL: SolidFillPdu = SolidFillPdu { + surface_id: 0, + fill_pixel: Color { + b: 0, + g: 0, + r: 0, + xa: 0, + }, + rectangles: vec![InclusiveRectangle { + left: 0, + top: 0, + right: 64, + bottom: 64 + }], + }; + pub static ref SURFACE_TO_SURFACE: SurfaceToSurfacePdu = SurfaceToSurfacePdu { + source_surface_id: 0, + destination_surface_id: 0, + source_rectangle: InclusiveRectangle { + left: 200, + top: 60, + right: 676, + bottom: 148 + }, + destination_points: vec![Point { x: 128, y: 60 }], + }; + pub static ref SURFACE_TO_CACHE: SurfaceToCachePdu = SurfaceToCachePdu { + surface_id: 0, + cache_key: 0x113D_86DA_A6A3_7FB7, + cache_slot: 14, + source_rectangle: InclusiveRectangle { + left: 640, + top: 0, + right: 704, + bottom: 64 + }, + }; + pub static ref CACHE_TO_SURFACE: CacheToSurfacePdu = CacheToSurfacePdu { + cache_slot: 2, + surface_id: 0, + destination_points: vec![Point { x: 768, y: 320 }], + }; + pub static ref CREATE_SURFACE: CreateSurfacePdu = CreateSurfacePdu { + surface_id: 0, + width: 1024, + height: 768, + pixel_format: PixelFormat::ARgb, + }; + pub static ref DELETE_SURFACE: DeleteSurfacePdu = DeleteSurfacePdu { surface_id: 0 }; + pub static ref RESET_GRAPHICS: ResetGraphicsPdu = ResetGraphicsPdu { + width: 1024, + height: 768, + monitors: vec![Monitor { + left: 0, + top: 0, + right: 1023, + bottom: 767, + flags: MonitorFlags::PRIMARY, + }], + }; + pub static ref MAP_SURFACE_TO_OUTPUT: MapSurfaceToOutputPdu = MapSurfaceToOutputPdu { + surface_id: 0, + output_origin_x: 1, + output_origin_y: 2, + }; + pub static ref EVICT_CACHE_ENTRY: EvictCacheEntryPdu = EvictCacheEntryPdu { cache_slot: 0 }; + pub static ref START_FRAME: StartFramePdu = StartFramePdu { + timestamp: Timestamp { + milliseconds: 247, + seconds: 58, + minutes: 27, + hours: 22, + }, + frame_id: 5 + }; + pub static ref END_FRAME: EndFramePdu = EndFramePdu { frame_id: 1 }; + pub static ref CAPABILITIES_CONFIRM: CapabilitiesConfirmPdu = CapabilitiesConfirmPdu(CapabilitySet::V10_5 { flags: CapabilitiesV104Flags::AVC_DISABLED, - }) -}); -pub static CAPABILITIES_ADVERTISE: LazyLock = LazyLock::new(|| { - CapabilitiesAdvertisePdu(vec![ + }); + pub static ref CAPABILITIES_ADVERTISE: CapabilitiesAdvertisePdu = CapabilitiesAdvertisePdu(vec![ CapabilitySet::V8 { - flags: CapabilitiesV8Flags::THIN_CLIENT, + flags: CapabilitiesV8Flags::THIN_CLIENT }, CapabilitySet::V8_1 { - flags: CapabilitiesV81Flags::THIN_CLIENT, + flags: CapabilitiesV81Flags::THIN_CLIENT }, CapabilitySet::V10 { - flags: CapabilitiesV10Flags::AVC_DISABLED, + flags: CapabilitiesV10Flags::AVC_DISABLED }, CapabilitySet::V10_1, CapabilitySet::V10_2 { - flags: CapabilitiesV10Flags::AVC_DISABLED, + flags: CapabilitiesV10Flags::AVC_DISABLED }, CapabilitySet::V10_3 { - flags: CapabilitiesV103Flags::AVC_DISABLED, + flags: CapabilitiesV103Flags::AVC_DISABLED }, CapabilitySet::V10_4 { - flags: CapabilitiesV104Flags::AVC_DISABLED, + flags: CapabilitiesV104Flags::AVC_DISABLED }, CapabilitySet::V10_5 { - flags: CapabilitiesV104Flags::AVC_DISABLED, + flags: CapabilitiesV104Flags::AVC_DISABLED }, CapabilitySet::V10_6 { - flags: CapabilitiesV104Flags::AVC_DISABLED, + flags: CapabilitiesV104Flags::AVC_DISABLED + } + ]); + pub static ref FRAME_ACKNOWLEDGE: FrameAcknowledgePdu = FrameAcknowledgePdu { + queue_depth: QueueDepth::Unavailable, + frame_id: 1, + total_frames_decoded: 1 + }; + pub static ref CACHE_IMPORT_REPLY: CacheImportReplyPdu = CacheImportReplyPdu { + cache_slots: vec![ + 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, + 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, + 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, + 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, + 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10a, 0x10b, 0x10c, 0x10d, 0x10e, + 0x10f, 0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118, 0x119, 0x11a, 0x11b, 0x11c, 0x11d, + 0x11e, 0x11f, 0x120, 0x121, 0x122, 0x123, 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12a, 0x12b, 0x12c, + 0x12d, 0x12e, 0x12f, 0x130, 0x131, 0x132, 0x133, 0x134, 0x135, 0x136, 0x137, 0x138, 0x139, 0x13a, 0x13b, + 0x13c, 0x13d, 0x13e, 0x13f, 0x140, 0x141, 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14a, + 0x14b, 0x14c, 0x14d, 0x14e, 0x14f, 0x150, 0x151, 0x152, 0x153, 0x154, 0x155, 0x156, 0x157, 0x158, 0x159, + 0x15a, 0x15b, 0x15c, 0x15d, 0x15e, 0x15f, 0x160, 0x161, 0x162, 0x163, 0x164, 0x165, 0x166, 0x167, 0x168, + 0x169, 0x16a, 0x16b, 0x16c, 0x16d, 0x16e, 0x16f, 0x170, 0x171, 0x172, 0x173, 0x174, 0x175, 0x176, 0x177, + 0x178, 0x179, 0x17a, 0x17b, 0x17c, 0x17d, 0x17e, 0x17f, 0x180, 0x181, 0x182, 0x183, 0x184, 0x185, 0x186, + 0x187, 0x188, 0x189, 0x18a, 0x18b, 0x18c, 0x18d, 0x18e, 0x18f, 0x190, 0x191, 0x192, 0x193, 0x194, 0x195, + 0x196, 0x197, 0x198, 0x199, 0x19a, 0x19b, 0x19c, 0x19d, 0x19e, 0x19f, 0x1a0, 0x1a1, 0x1a2, 0x1a3, 0x1a4, + 0x1a5, 0x1a6, 0x1a7, 0x1a8, 0x1a9, 0x1aa, 0x1ab, 0x1ac, 0x1ad, 0x1ae, 0x1af, 0x1b0, 0x1b1, 0x1b2, 0x1b3, + 0x1b4, 0x1b5, 0x1b6, 0x1b7, 0x1b8, 0x1b9, 0x1ba, 0x1bb, 0x1bc, 0x1bd, 0x1be, 0x1bf, 0x1c0, 0x1c1, 0x1c2, + 0x1c3, 0x1c4, 0x1c5, 0x1c6, 0x1c7, 0x1c8, 0x1c9, 0x1ca, 0x1cb, 0x1cc, 0x1cd, 0x1ce, 0x1cf, 0x1d0, 0x1d1, + 0x1d2, 0x1d3, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d8, 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1df, 0x1e0, + 0x1e1, 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e6, 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ee, 0x1ef, + 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, 0x1f7, 0x1f8, 0x1f9, 0x1fa, 0x1fb, 0x1fc, 0x1fd, 0x1fe, + 0x1ff, 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, 0x20c, 0x20d, + 0x20e, 0x20f, 0x210, 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a, 0x21b, 0x21c, + 0x21d, 0x21e, 0x21f, 0x220, 0x221, 0x222, 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a, 0x22b, + 0x22c, 0x22d, 0x22e, 0x22f, 0x230, 0x231, 0x232, 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, + 0x23b, 0x23c, 0x23d, 0x23e, 0x23f, 0x240, 0x241, 0x242, 0x243, 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, + 0x24a, 0x24b, 0x24c, 0x24d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, 0x257, 0x258, + 0x259, 0x25a, 0x25b, 0x25c, 0x25d, 0x25e, 0x25f, 0x260, 0x261, 0x262, 0x263, 0x264, 0x265, 0x266, 0x267, + 0x268, 0x269, 0x26a, 0x26b, 0x26c, 0x26d, 0x26e, 0x26f, 0x270, 0x271, 0x272, 0x273, 0x274, 0x275, 0x276, + 0x277, 0x278, 0x279, 0x27a, 0x27b, 0x27c, 0x27d, 0x27e, 0x27f, 0x280, 0x281, 0x282, 0x283, 0x284, 0x285, + 0x286, 0x287, 0x288, 0x289, 0x28a, 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x291, 0x292, 0x293, 0x294, + 0x295, 0x296, 0x297, 0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x29d, 0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a3, + 0x2a4, 0x2a5, 0x2a6, 0x2a7, 0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ad, 0x2ae, 0x2af, 0x2b0, 0x2b1, 0x2b2, + 0x2b3, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b8, 0x2b9, 0x2ba, 0x2bb, 0x2bc, 0x2bd, 0x2be, 0x2bf, 0x2c0, 0x2c1, + 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c6, 0x2c7, 0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2cf, 0x2d0, + 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d7, 0x2d8, 0x2d9, 0x2da, 0x2db, 0x2dc, 0x2dd, 0x2de, 0x2df, + 0x2e0, 0x2e1, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e6, 0x2e7, 0x2e8, 0x2e9, 0x2ea, 0x2eb, 0x2ec, 0x2ed, 0x2ee, + 0x2ef, 0x2f0, 0x2f1, 0x2f2, 0x2f3, 0x2f4, 0x2f5, 0x2f6, 0x2f7, 0x2f8, 0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fd, + 0x2fe, 0x2ff, 0x300, 0x301, 0x302, 0x303, 0x304, 0x305, 0x306, 0x307, 0x308, 0x309, 0x30a, 0x30b, 0x30c, + 0x30d, 0x30e, 0x30f, 0x310, 0x311, 0x312, 0x313, 0x314, 0x315, 0x316, 0x317, 0x318, 0x319, 0x31a, 0x31b, + 0x31c, 0x31d, 0x31e, 0x31f, 0x320, 0x321, 0x322, 0x323, 0x324, 0x325, 0x326, 0x327, 0x328, 0x329, 0x32a, + 0x32b, 0x32c, 0x32d, 0x32e, 0x32f, 0x330, 0x331, 0x332, 0x333, 0x334, 0x335, 0x336, 0x337, 0x338, 0x339, + 0x33a, 0x33b, 0x33c, 0x33d, 0x33e, 0x33f, 0x340, 0x341, 0x342, 0x343, 0x344, 0x345, 0x346, 0x347, 0x348, + 0x349, 0x34a, 0x34b, 0x34c, 0x34d, 0x34e, 0x34f, 0x350, 0x351, 0x352, 0x353, 0x354, 0x355, 0x356, 0x357, + 0x358, 0x359, 0x35a, 0x35b, 0x35c, 0x35d, 0x35e, 0x35f, 0x360, 0x361, 0x362, 0x363, 0x364, 0x365, 0x366, + 0x367, 0x368, 0x369, 0x36a, 0x36b, 0x36c, 0x36d, 0x36e, 0x36f, 0x370, 0x371, 0x372, 0x373, 0x374, 0x375, + 0x376, 0x377, 0x378, 0x379, 0x37a, 0x37b, 0x37c, 0x37d, 0x37e, 0x37f, 0x380, 0x381, 0x382, 0x383, 0x384, + 0x385, 0x386, 0x387, 0x388, 0x389, 0x38a, 0x38b, 0x38c, 0x38d, 0x38e, 0x38f, 0x390, 0x391, 0x392, 0x393, + 0x394, 0x395, 0x396, 0x397, 0x398 + ] + }; + pub static ref AVC_444_BITMAP: Avc444BitmapStream<'static> = Avc444BitmapStream { + encoding: Encoding::CHROMA, + stream1: Avc420BitmapStream { + rectangles: vec![InclusiveRectangle { + left: 1792, + top: 1056, + right: 1808, + bottom: 1072, + }], + quant_qual_vals: vec![QuantQuality { + quantization_parameter: 22, + progressive: false, + quality: 100, + }], + data: &AVC_444_MESSAGE_CORRECT_LEN[18..] }, - ]) -}); -pub static FRAME_ACKNOWLEDGE: LazyLock = LazyLock::new(|| FrameAcknowledgePdu { - queue_depth: QueueDepth::Unavailable, - frame_id: 1, - total_frames_decoded: 1, -}); -pub static CACHE_IMPORT_REPLY: LazyLock = LazyLock::new(|| CacheImportReplyPdu { - cache_slots: vec![ - 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, - 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, - 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, - 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, - 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, - 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, - 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, - 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, - 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, - 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, - 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x100, - 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10a, 0x10b, 0x10c, 0x10d, 0x10e, 0x10f, 0x110, - 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118, 0x119, 0x11a, 0x11b, 0x11c, 0x11d, 0x11e, 0x11f, 0x120, - 0x121, 0x122, 0x123, 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12a, 0x12b, 0x12c, 0x12d, 0x12e, 0x12f, 0x130, - 0x131, 0x132, 0x133, 0x134, 0x135, 0x136, 0x137, 0x138, 0x139, 0x13a, 0x13b, 0x13c, 0x13d, 0x13e, 0x13f, 0x140, - 0x141, 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14a, 0x14b, 0x14c, 0x14d, 0x14e, 0x14f, 0x150, - 0x151, 0x152, 0x153, 0x154, 0x155, 0x156, 0x157, 0x158, 0x159, 0x15a, 0x15b, 0x15c, 0x15d, 0x15e, 0x15f, 0x160, - 0x161, 0x162, 0x163, 0x164, 0x165, 0x166, 0x167, 0x168, 0x169, 0x16a, 0x16b, 0x16c, 0x16d, 0x16e, 0x16f, 0x170, - 0x171, 0x172, 0x173, 0x174, 0x175, 0x176, 0x177, 0x178, 0x179, 0x17a, 0x17b, 0x17c, 0x17d, 0x17e, 0x17f, 0x180, - 0x181, 0x182, 0x183, 0x184, 0x185, 0x186, 0x187, 0x188, 0x189, 0x18a, 0x18b, 0x18c, 0x18d, 0x18e, 0x18f, 0x190, - 0x191, 0x192, 0x193, 0x194, 0x195, 0x196, 0x197, 0x198, 0x199, 0x19a, 0x19b, 0x19c, 0x19d, 0x19e, 0x19f, 0x1a0, - 0x1a1, 0x1a2, 0x1a3, 0x1a4, 0x1a5, 0x1a6, 0x1a7, 0x1a8, 0x1a9, 0x1aa, 0x1ab, 0x1ac, 0x1ad, 0x1ae, 0x1af, 0x1b0, - 0x1b1, 0x1b2, 0x1b3, 0x1b4, 0x1b5, 0x1b6, 0x1b7, 0x1b8, 0x1b9, 0x1ba, 0x1bb, 0x1bc, 0x1bd, 0x1be, 0x1bf, 0x1c0, - 0x1c1, 0x1c2, 0x1c3, 0x1c4, 0x1c5, 0x1c6, 0x1c7, 0x1c8, 0x1c9, 0x1ca, 0x1cb, 0x1cc, 0x1cd, 0x1ce, 0x1cf, 0x1d0, - 0x1d1, 0x1d2, 0x1d3, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d8, 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1df, 0x1e0, - 0x1e1, 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e6, 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ee, 0x1ef, 0x1f0, - 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5, 0x1f6, 0x1f7, 0x1f8, 0x1f9, 0x1fa, 0x1fb, 0x1fc, 0x1fd, 0x1fe, 0x1ff, 0x200, - 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, 0x20c, 0x20d, 0x20e, 0x20f, 0x210, - 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a, 0x21b, 0x21c, 0x21d, 0x21e, 0x21f, 0x220, - 0x221, 0x222, 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a, 0x22b, 0x22c, 0x22d, 0x22e, 0x22f, 0x230, - 0x231, 0x232, 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, 0x23b, 0x23c, 0x23d, 0x23e, 0x23f, 0x240, - 0x241, 0x242, 0x243, 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b, 0x24c, 0x24d, 0x24e, 0x24f, 0x250, - 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c, 0x25d, 0x25e, 0x25f, 0x260, - 0x261, 0x262, 0x263, 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26a, 0x26b, 0x26c, 0x26d, 0x26e, 0x26f, 0x270, - 0x271, 0x272, 0x273, 0x274, 0x275, 0x276, 0x277, 0x278, 0x279, 0x27a, 0x27b, 0x27c, 0x27d, 0x27e, 0x27f, 0x280, - 0x281, 0x282, 0x283, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28a, 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, - 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297, 0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x29d, 0x29e, 0x29f, 0x2a0, - 0x2a1, 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a6, 0x2a7, 0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ad, 0x2ae, 0x2af, 0x2b0, - 0x2b1, 0x2b2, 0x2b3, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b8, 0x2b9, 0x2ba, 0x2bb, 0x2bc, 0x2bd, 0x2be, 0x2bf, 0x2c0, - 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c6, 0x2c7, 0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2cf, 0x2d0, - 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d7, 0x2d8, 0x2d9, 0x2da, 0x2db, 0x2dc, 0x2dd, 0x2de, 0x2df, 0x2e0, - 0x2e1, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e6, 0x2e7, 0x2e8, 0x2e9, 0x2ea, 0x2eb, 0x2ec, 0x2ed, 0x2ee, 0x2ef, 0x2f0, - 0x2f1, 0x2f2, 0x2f3, 0x2f4, 0x2f5, 0x2f6, 0x2f7, 0x2f8, 0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fd, 0x2fe, 0x2ff, 0x300, - 0x301, 0x302, 0x303, 0x304, 0x305, 0x306, 0x307, 0x308, 0x309, 0x30a, 0x30b, 0x30c, 0x30d, 0x30e, 0x30f, 0x310, - 0x311, 0x312, 0x313, 0x314, 0x315, 0x316, 0x317, 0x318, 0x319, 0x31a, 0x31b, 0x31c, 0x31d, 0x31e, 0x31f, 0x320, - 0x321, 0x322, 0x323, 0x324, 0x325, 0x326, 0x327, 0x328, 0x329, 0x32a, 0x32b, 0x32c, 0x32d, 0x32e, 0x32f, 0x330, - 0x331, 0x332, 0x333, 0x334, 0x335, 0x336, 0x337, 0x338, 0x339, 0x33a, 0x33b, 0x33c, 0x33d, 0x33e, 0x33f, 0x340, - 0x341, 0x342, 0x343, 0x344, 0x345, 0x346, 0x347, 0x348, 0x349, 0x34a, 0x34b, 0x34c, 0x34d, 0x34e, 0x34f, 0x350, - 0x351, 0x352, 0x353, 0x354, 0x355, 0x356, 0x357, 0x358, 0x359, 0x35a, 0x35b, 0x35c, 0x35d, 0x35e, 0x35f, 0x360, - 0x361, 0x362, 0x363, 0x364, 0x365, 0x366, 0x367, 0x368, 0x369, 0x36a, 0x36b, 0x36c, 0x36d, 0x36e, 0x36f, 0x370, - 0x371, 0x372, 0x373, 0x374, 0x375, 0x376, 0x377, 0x378, 0x379, 0x37a, 0x37b, 0x37c, 0x37d, 0x37e, 0x37f, 0x380, - 0x381, 0x382, 0x383, 0x384, 0x385, 0x386, 0x387, 0x388, 0x389, 0x38a, 0x38b, 0x38c, 0x38d, 0x38e, 0x38f, 0x390, - 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, - ], -}); -pub static AVC_444_BITMAP: LazyLock> = LazyLock::new(|| Avc444BitmapStream { - encoding: Encoding::CHROMA, - stream1: Avc420BitmapStream { - rectangles: vec![InclusiveRectangle { - left: 1792, - top: 1056, - right: 1808, - bottom: 1072, - }], - quant_qual_vals: vec![QuantQuality { - quantization_parameter: 22, - progressive: false, - quality: 100, - }], - data: &AVC_444_MESSAGE_CORRECT_LEN[18..], - }, - stream2: None, -}); + stream2: None + }; +} diff --git a/crates/ironrdp-testsuite-core/src/mcs.rs b/crates/ironrdp-testsuite-core/src/mcs.rs index 5836945d..0a23f38a 100644 --- a/crates/ironrdp-testsuite-core/src/mcs.rs +++ b/crates/ironrdp-testsuite-core/src/mcs.rs @@ -1,5 +1,4 @@ use std::borrow::Cow; -use std::sync::LazyLock; use array_concat::{concat_arrays, concat_arrays_size}; use ironrdp_pdu::mcs::{ @@ -7,6 +6,7 @@ use ironrdp_pdu::mcs::{ DisconnectProviderUltimatum, DisconnectReason, DomainParameters, ErectDomainPdu, OwnedSendDataIndication, OwnedSendDataRequest, SendDataIndication, SendDataRequest, }; +use lazy_static::lazy_static; use crate::conference_create::{ CONFERENCE_CREATE_REQUEST, CONFERENCE_CREATE_REQUEST_BUFFER, CONFERENCE_CREATE_RESPONSE, @@ -105,53 +105,55 @@ pub const CONNECT_RESPONSE_BUFFER: [u8; concat_arrays_size!( CONFERENCE_CREATE_RESPONSE_BUFFER )] = concat_arrays!(CONNECT_RESPONSE_PREFIX_BUFFER, CONFERENCE_CREATE_RESPONSE_BUFFER); -pub static CONNECT_INITIAL: LazyLock = LazyLock::new(|| ConnectInitial { - calling_domain_selector: vec![0x01], - called_domain_selector: vec![0x01], - upward_flag: true, - target_parameters: DomainParameters { - max_channel_ids: 34, - max_user_ids: 2, - max_token_ids: 0, - num_priorities: 1, - min_throughput: 0, - max_height: 1, - max_mcs_pdu_size: 65535, - protocol_version: 2, - }, - min_parameters: DomainParameters { - max_channel_ids: 1, - max_user_ids: 1, - max_token_ids: 1, - num_priorities: 1, - min_throughput: 0, - max_height: 1, - max_mcs_pdu_size: 1056, - protocol_version: 2, - }, - max_parameters: DomainParameters { - max_channel_ids: 65535, - max_user_ids: 64535, - max_token_ids: 65535, - num_priorities: 1, - min_throughput: 0, - max_height: 1, - max_mcs_pdu_size: 65535, - protocol_version: 2, - }, - conference_create_request: CONFERENCE_CREATE_REQUEST.clone(), -}); -pub static CONNECT_RESPONSE: LazyLock = LazyLock::new(|| ConnectResponse { - called_connect_id: 0, - domain_parameters: DomainParameters { - max_channel_ids: 34, - max_user_ids: 3, - max_token_ids: 0, - num_priorities: 1, - min_throughput: 0, - max_height: 1, - max_mcs_pdu_size: 65528, - protocol_version: 2, - }, - conference_create_response: CONFERENCE_CREATE_RESPONSE.clone(), -}); +lazy_static! { + pub static ref CONNECT_INITIAL: ConnectInitial = ConnectInitial { + calling_domain_selector: vec![0x01], + called_domain_selector: vec![0x01], + upward_flag: true, + target_parameters: DomainParameters { + max_channel_ids: 34, + max_user_ids: 2, + max_token_ids: 0, + num_priorities: 1, + min_throughput: 0, + max_height: 1, + max_mcs_pdu_size: 65535, + protocol_version: 2, + }, + min_parameters: DomainParameters { + max_channel_ids: 1, + max_user_ids: 1, + max_token_ids: 1, + num_priorities: 1, + min_throughput: 0, + max_height: 1, + max_mcs_pdu_size: 1056, + protocol_version: 2, + }, + max_parameters: DomainParameters { + max_channel_ids: 65535, + max_user_ids: 64535, + max_token_ids: 65535, + num_priorities: 1, + min_throughput: 0, + max_height: 1, + max_mcs_pdu_size: 65535, + protocol_version: 2, + }, + conference_create_request: CONFERENCE_CREATE_REQUEST.clone(), + }; + pub static ref CONNECT_RESPONSE: ConnectResponse = ConnectResponse { + called_connect_id: 0, + domain_parameters: DomainParameters { + max_channel_ids: 34, + max_user_ids: 3, + max_token_ids: 0, + num_priorities: 1, + min_throughput: 0, + max_height: 1, + max_mcs_pdu_size: 65528, + protocol_version: 2, + }, + conference_create_response: CONFERENCE_CREATE_RESPONSE.clone(), + }; +} diff --git a/crates/ironrdp-testsuite-core/src/monitor_data.rs b/crates/ironrdp-testsuite-core/src/monitor_data.rs index 1bd15bc0..b39aa67e 100644 --- a/crates/ironrdp-testsuite-core/src/monitor_data.rs +++ b/crates/ironrdp-testsuite-core/src/monitor_data.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_pdu::gcc::{ClientMonitorData, Monitor, MonitorFlags}; +use lazy_static::lazy_static; pub const MONITOR_DATA_WITHOUT_MONITORS_BUFFER: [u8; 8] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; @@ -10,23 +9,24 @@ pub const MONITOR_DATA_WITH_MONITORS_BUFFER: [u8; 48] = [ 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; -pub static MONITOR_DATA_WITHOUT_MONITORS: LazyLock = - LazyLock::new(|| ClientMonitorData { monitors: Vec::new() }); -pub static MONITOR_DATA_WITH_MONITORS: LazyLock = LazyLock::new(|| ClientMonitorData { - monitors: vec![ - Monitor { - left: 0, - top: 0, - right: 1919, - bottom: 1079, - flags: MonitorFlags::PRIMARY, - }, - Monitor { - left: -1280, - top: 0, - right: -1, - bottom: 1023, - flags: MonitorFlags::empty(), - }, - ], -}); +lazy_static! { + pub static ref MONITOR_DATA_WITHOUT_MONITORS: ClientMonitorData = ClientMonitorData { monitors: Vec::new() }; + pub static ref MONITOR_DATA_WITH_MONITORS: ClientMonitorData = ClientMonitorData { + monitors: vec![ + Monitor { + left: 0, + top: 0, + right: 1919, + bottom: 1079, + flags: MonitorFlags::PRIMARY, + }, + Monitor { + left: -1280, + top: 0, + right: -1, + bottom: 1023, + flags: MonitorFlags::empty(), + } + ] + }; +} diff --git a/crates/ironrdp-testsuite-core/src/monitor_extended_data.rs b/crates/ironrdp-testsuite-core/src/monitor_extended_data.rs index 089f9679..31a09e34 100644 --- a/crates/ironrdp-testsuite-core/src/monitor_extended_data.rs +++ b/crates/ironrdp-testsuite-core/src/monitor_extended_data.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_pdu::gcc::{ClientMonitorExtendedData, ExtendedMonitorInfo, MonitorOrientation}; +use lazy_static::lazy_static; pub const MONITOR_DATA_WITHOUT_MONITORS_BUFFER: [u8; 12] = [0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; @@ -11,12 +10,11 @@ pub const MONITOR_DATA_WITH_MONITORS_BUFFER: [u8; 52] = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; -pub static MONITOR_DATA_WITHOUT_MONITORS: LazyLock = - LazyLock::new(|| ClientMonitorExtendedData { - extended_monitors_info: Vec::new(), - }); -pub static MONITOR_DATA_WITH_MONITORS: LazyLock = - LazyLock::new(|| ClientMonitorExtendedData { +lazy_static! { + pub static ref MONITOR_DATA_WITHOUT_MONITORS: ClientMonitorExtendedData = ClientMonitorExtendedData { + extended_monitors_info: Vec::new() + }; + pub static ref MONITOR_DATA_WITH_MONITORS: ClientMonitorExtendedData = ClientMonitorExtendedData { extended_monitors_info: vec![ ExtendedMonitorInfo { physical_width: 0, @@ -31,6 +29,7 @@ pub static MONITOR_DATA_WITH_MONITORS: LazyLock = orientation: MonitorOrientation::Landscape, desktop_scale_factor: 0, device_scale_factor: 0, - }, - ], - }); + } + ] + }; +} diff --git a/crates/ironrdp-testsuite-core/src/multi_transport_channel_data.rs b/crates/ironrdp-testsuite-core/src/multi_transport_channel_data.rs index c950d891..fc485140 100644 --- a/crates/ironrdp-testsuite-core/src/multi_transport_channel_data.rs +++ b/crates/ironrdp-testsuite-core/src/multi_transport_channel_data.rs @@ -1,12 +1,12 @@ -use std::sync::LazyLock; - use ironrdp_pdu::gcc::{MultiTransportChannelData, MultiTransportFlags}; +use lazy_static::lazy_static; pub const SERVER_GCC_MULTI_TRANSPORT_CHANNEL_BLOCK_BUFFER: [u8; 4] = [0x01, 0x03, 0x00, 0x00]; -pub static SERVER_GCC_MULTI_TRANSPORT_CHANNEL_BLOCK: LazyLock = - LazyLock::new(|| MultiTransportChannelData { +lazy_static! { + pub static ref SERVER_GCC_MULTI_TRANSPORT_CHANNEL_BLOCK: MultiTransportChannelData = MultiTransportChannelData { flags: MultiTransportFlags::TRANSPORT_TYPE_UDP_FECR | MultiTransportFlags::TRANSPORT_TYPE_UDP_PREFERRED | MultiTransportFlags::SOFT_SYNC_TCP_TO_UDP, - }); + }; +} diff --git a/crates/ironrdp-testsuite-core/src/network_data.rs b/crates/ironrdp-testsuite-core/src/network_data.rs index ad8b4196..3c94472c 100644 --- a/crates/ironrdp-testsuite-core/src/network_data.rs +++ b/crates/ironrdp-testsuite-core/src/network_data.rs @@ -1,6 +1,5 @@ -use std::sync::LazyLock; - use ironrdp_pdu::gcc::{ChannelDef, ChannelName, ChannelOptions, ClientNetworkData, ServerNetworkData}; +use lazy_static::lazy_static; pub const CLIENT_NETWORK_DATA_WITH_CHANNELS_BUFFER: [u8; 40] = [ 0x03, 0x00, 0x00, 0x00, // channels count @@ -30,32 +29,33 @@ pub const SERVER_NETWORK_DATA_WITHOUT_CHANNELS_ID_BUFFER: [u8; 4] = [ 0x00, 0x00, // channels count ]; -pub static CLIENT_NETWORK_DATA_WITH_CHANNELS: LazyLock = LazyLock::new(|| ClientNetworkData { - channels: vec![ - ChannelDef { - name: ChannelName::from_utf8("rdpdr").unwrap(), - options: ChannelOptions::INITIALIZED | ChannelOptions::COMPRESS_RDP, - }, - ChannelDef { - name: ChannelName::from_utf8("cliprdr").unwrap(), - options: ChannelOptions::INITIALIZED - | ChannelOptions::COMPRESS_RDP - | ChannelOptions::ENCRYPT_RDP - | ChannelOptions::SHOW_PROTOCOL, - }, - ChannelDef { - name: ChannelName::from_utf8("rdpsnd").unwrap(), - options: ChannelOptions::INITIALIZED | ChannelOptions::ENCRYPT_RDP, - }, - ], -}); -pub static SERVER_NETWORK_DATA_WITH_CHANNELS_ID: LazyLock = LazyLock::new(|| ServerNetworkData { - io_channel: 1003, - channel_ids: vec![1004, 1005, 1006], -}); -pub static CLIENT_NETWORK_DATA_WITHOUT_CHANNELS: LazyLock = - LazyLock::new(|| ClientNetworkData { channels: Vec::new() }); -pub static SERVER_NETWORK_DATA_WITHOUT_CHANNELS_ID: LazyLock = LazyLock::new(|| ServerNetworkData { - io_channel: 1003, - channel_ids: Vec::new(), -}); +lazy_static! { + pub static ref CLIENT_NETWORK_DATA_WITH_CHANNELS: ClientNetworkData = ClientNetworkData { + channels: vec![ + ChannelDef { + name: ChannelName::from_utf8("rdpdr").unwrap(), + options: ChannelOptions::INITIALIZED | ChannelOptions::COMPRESS_RDP, + }, + ChannelDef { + name: ChannelName::from_utf8("cliprdr").unwrap(), + options: ChannelOptions::INITIALIZED + | ChannelOptions::COMPRESS_RDP + | ChannelOptions::ENCRYPT_RDP + | ChannelOptions::SHOW_PROTOCOL, + }, + ChannelDef { + name: ChannelName::from_utf8("rdpsnd").unwrap(), + options: ChannelOptions::INITIALIZED | ChannelOptions::ENCRYPT_RDP, + }, + ], + }; + pub static ref SERVER_NETWORK_DATA_WITH_CHANNELS_ID: ServerNetworkData = ServerNetworkData { + io_channel: 1003, + channel_ids: vec![1004, 1005, 1006], + }; + pub static ref CLIENT_NETWORK_DATA_WITHOUT_CHANNELS: ClientNetworkData = ClientNetworkData { channels: Vec::new() }; + pub static ref SERVER_NETWORK_DATA_WITHOUT_CHANNELS_ID: ServerNetworkData = ServerNetworkData { + io_channel: 1003, + channel_ids: Vec::new(), + }; +} diff --git a/crates/ironrdp-testsuite-core/src/rdp.rs b/crates/ironrdp-testsuite-core/src/rdp.rs index ae4a91a7..488b2c90 100644 --- a/crates/ironrdp-testsuite-core/src/rdp.rs +++ b/crates/ironrdp-testsuite-core/src/rdp.rs @@ -1,5 +1,3 @@ -use std::sync::LazyLock; - use array_concat::{concat_arrays, concat_arrays_size}; use ironrdp_pdu::gcc; use ironrdp_pdu::rdp::finalization_messages::{ @@ -14,6 +12,7 @@ use ironrdp_pdu::rdp::server_license::{ PreambleType, PreambleVersion, }; use ironrdp_pdu::rdp::{client_info, ClientInfoPdu}; +use lazy_static::lazy_static; use crate::capsets::{ CLIENT_DEMAND_ACTIVE, CLIENT_DEMAND_ACTIVE_BUFFER, SERVER_DEMAND_ACTIVE, SERVER_DEMAND_ACTIVE_BUFFER, @@ -159,143 +158,145 @@ pub const SERVER_LICENSE_BUFFER: [u8; 20] = [ 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, ]; -pub static CLIENT_INFO_PDU: LazyLock = LazyLock::new(|| ClientInfoPdu { - security_header: BasicSecurityHeader { - flags: BasicSecurityHeaderFlags::INFO_PKT, - }, - client_info: CLIENT_INFO_UNICODE.clone(), -}); -pub static SERVER_LICENSE_PDU: LazyLock = LazyLock::new(|| { - let mut pdu = LicensingErrorMessage { - license_header: LicenseHeader { - security_header: BasicSecurityHeader { - flags: BasicSecurityHeaderFlags::LICENSE_PKT, - }, - preamble_message_type: PreambleType::ErrorAlert, - preamble_flags: PreambleFlags::empty(), - preamble_version: PreambleVersion::V3, - preamble_message_size: 0, +lazy_static! { + pub static ref CLIENT_INFO_PDU: ClientInfoPdu = ClientInfoPdu { + security_header: BasicSecurityHeader { + flags: BasicSecurityHeaderFlags::INFO_PKT, }, - error_code: LicenseErrorCode::StatusValidClient, - state_transition: LicensingStateTransition::NoTransition, - error_info: Vec::new(), + client_info: CLIENT_INFO_UNICODE.clone(), }; - pdu.license_header.preamble_message_size = u16::try_from(pdu.size()).unwrap(); - pdu.into() -}); -pub static SERVER_DEMAND_ACTIVE_PDU: LazyLock = LazyLock::new(|| ShareControlHeader { - share_control_pdu: ShareControlPdu::ServerDemandActive(SERVER_DEMAND_ACTIVE.clone()), - pdu_source: 1002, - share_id: 66_538, -}); -pub static CLIENT_DEMAND_ACTIVE_PDU: LazyLock = LazyLock::new(|| ShareControlHeader { - share_control_pdu: ShareControlPdu::ClientConfirmActive(CLIENT_DEMAND_ACTIVE.clone()), - pdu_source: 1007, - share_id: 66_538, -}); -pub static CLIENT_SYNCHRONIZE: LazyLock = LazyLock::new(|| ShareControlHeader { - share_control_pdu: ShareControlPdu::Data(ShareDataHeader { - share_data_pdu: ShareDataPdu::Synchronize(SynchronizePdu { target_user_id: 0x03ea }), - stream_priority: StreamPriority::Low, - compression_flags: CompressionFlags::empty(), - compression_type: client_info::CompressionType::K8, - }), - pdu_source: 1007, - share_id: 66_538, -}); -pub static CONTROL_COOPERATE: LazyLock = LazyLock::new(|| ShareControlHeader { - share_control_pdu: ShareControlPdu::Data(ShareDataHeader { - share_data_pdu: ShareDataPdu::Control(ControlPdu { - action: ControlAction::Cooperate, - grant_id: 0, - control_id: 0, + pub static ref SERVER_LICENSE_PDU: LicensePdu = { + let mut pdu = LicensingErrorMessage { + license_header: LicenseHeader { + security_header: BasicSecurityHeader { + flags: BasicSecurityHeaderFlags::LICENSE_PKT, + }, + preamble_message_type: PreambleType::ErrorAlert, + preamble_flags: PreambleFlags::empty(), + preamble_version: PreambleVersion::V3, + preamble_message_size: 0, + }, + error_code: LicenseErrorCode::StatusValidClient, + state_transition: LicensingStateTransition::NoTransition, + error_info: Vec::new(), + }; + pdu.license_header.preamble_message_size = pdu.size() as u16; + pdu.into() + }; + pub static ref SERVER_DEMAND_ACTIVE_PDU: ShareControlHeader = ShareControlHeader { + share_control_pdu: ShareControlPdu::ServerDemandActive(SERVER_DEMAND_ACTIVE.clone()), + pdu_source: 1002, + share_id: 66_538, + }; + pub static ref CLIENT_DEMAND_ACTIVE_PDU: ShareControlHeader = ShareControlHeader { + share_control_pdu: ShareControlPdu::ClientConfirmActive(CLIENT_DEMAND_ACTIVE.clone()), + pdu_source: 1007, + share_id: 66_538, + }; + pub static ref CLIENT_SYNCHRONIZE: ShareControlHeader = ShareControlHeader { + share_control_pdu: ShareControlPdu::Data(ShareDataHeader { + share_data_pdu: ShareDataPdu::Synchronize(SynchronizePdu { target_user_id: 0x03ea }), + stream_priority: StreamPriority::Low, + compression_flags: CompressionFlags::empty(), + compression_type: client_info::CompressionType::K8, }), - stream_priority: StreamPriority::Low, - compression_flags: CompressionFlags::empty(), - compression_type: client_info::CompressionType::K8, - }), - pdu_source: 1007, - share_id: 66_538, -}); -pub static CONTROL_REQUEST_CONTROL: LazyLock = LazyLock::new(|| ShareControlHeader { - share_control_pdu: ShareControlPdu::Data(ShareDataHeader { - share_data_pdu: ShareDataPdu::Control(ControlPdu { - action: ControlAction::RequestControl, - grant_id: 0, - control_id: 0, + pdu_source: 1007, + share_id: 66_538, + }; + pub static ref CONTROL_COOPERATE: ShareControlHeader = ShareControlHeader { + share_control_pdu: ShareControlPdu::Data(ShareDataHeader { + share_data_pdu: ShareDataPdu::Control(ControlPdu { + action: ControlAction::Cooperate, + grant_id: 0, + control_id: 0, + }), + stream_priority: StreamPriority::Low, + compression_flags: CompressionFlags::empty(), + compression_type: client_info::CompressionType::K8, }), - stream_priority: StreamPriority::Low, - compression_flags: CompressionFlags::empty(), - compression_type: client_info::CompressionType::K8, - }), - pdu_source: 1007, - share_id: 66_538, -}); -pub static SERVER_GRANTED_CONTROL: LazyLock = LazyLock::new(|| ShareControlHeader { - share_control_pdu: ShareControlPdu::Data(ShareDataHeader { - share_data_pdu: ShareDataPdu::Control(ControlPdu { - action: ControlAction::GrantedControl, - grant_id: 1007, - control_id: 1002, + pdu_source: 1007, + share_id: 66_538, + }; + pub static ref CONTROL_REQUEST_CONTROL: ShareControlHeader = ShareControlHeader { + share_control_pdu: ShareControlPdu::Data(ShareDataHeader { + share_data_pdu: ShareDataPdu::Control(ControlPdu { + action: ControlAction::RequestControl, + grant_id: 0, + control_id: 0, + }), + stream_priority: StreamPriority::Low, + compression_flags: CompressionFlags::empty(), + compression_type: client_info::CompressionType::K8, }), - stream_priority: StreamPriority::Medium, - compression_flags: CompressionFlags::empty(), - compression_type: client_info::CompressionType::K8, - }), - pdu_source: 1002, - share_id: 66_538, -}); -pub static CLIENT_FONT_LIST: LazyLock = LazyLock::new(|| ShareControlHeader { - share_control_pdu: ShareControlPdu::Data(ShareDataHeader { - share_data_pdu: ShareDataPdu::FontList(FontPdu { - number: 0, - total_number: 0, - flags: SequenceFlags::FIRST | SequenceFlags::LAST, - entry_size: 50, + pdu_source: 1007, + share_id: 66_538, + }; + pub static ref SERVER_GRANTED_CONTROL: ShareControlHeader = ShareControlHeader { + share_control_pdu: ShareControlPdu::Data(ShareDataHeader { + share_data_pdu: ShareDataPdu::Control(ControlPdu { + action: ControlAction::GrantedControl, + grant_id: 1007, + control_id: 1002, + }), + stream_priority: StreamPriority::Medium, + compression_flags: CompressionFlags::empty(), + compression_type: client_info::CompressionType::K8, }), - stream_priority: StreamPriority::Low, - compression_flags: CompressionFlags::empty(), - compression_type: client_info::CompressionType::K8, - }), - pdu_source: 1007, - share_id: 66_538, -}); -pub static SERVER_FONT_MAP: LazyLock = LazyLock::new(|| ShareControlHeader { - share_control_pdu: ShareControlPdu::Data(ShareDataHeader { - share_data_pdu: ShareDataPdu::FontMap(FontPdu { - number: 0, - total_number: 0, - flags: SequenceFlags::FIRST | SequenceFlags::LAST, - entry_size: 4, + pdu_source: 1002, + share_id: 66_538, + }; + pub static ref CLIENT_FONT_LIST: ShareControlHeader = ShareControlHeader { + share_control_pdu: ShareControlPdu::Data(ShareDataHeader { + share_data_pdu: ShareDataPdu::FontList(FontPdu { + number: 0, + total_number: 0, + flags: SequenceFlags::FIRST | SequenceFlags::LAST, + entry_size: 50, + }), + stream_priority: StreamPriority::Low, + compression_flags: CompressionFlags::empty(), + compression_type: client_info::CompressionType::K8, }), - stream_priority: StreamPriority::Medium, - compression_flags: CompressionFlags::empty(), - compression_type: client_info::CompressionType::K8, - }), - pdu_source: 1002, - share_id: 66_538, -}); -pub static MONITOR_LAYOUT_PDU: LazyLock = LazyLock::new(|| ShareControlHeader { - share_control_pdu: ShareControlPdu::Data(ShareDataHeader { - share_data_pdu: ShareDataPdu::MonitorLayout(MonitorLayoutPdu { - monitors: crate::monitor_data::MONITOR_DATA_WITH_MONITORS.monitors.clone(), + pdu_source: 1007, + share_id: 66_538, + }; + pub static ref SERVER_FONT_MAP: ShareControlHeader = ShareControlHeader { + share_control_pdu: ShareControlPdu::Data(ShareDataHeader { + share_data_pdu: ShareDataPdu::FontMap(FontPdu { + number: 0, + total_number: 0, + flags: SequenceFlags::FIRST | SequenceFlags::LAST, + entry_size: 4, + }), + stream_priority: StreamPriority::Medium, + compression_flags: CompressionFlags::empty(), + compression_type: client_info::CompressionType::K8, }), - stream_priority: StreamPriority::Low, - compression_flags: CompressionFlags::empty(), - compression_type: client_info::CompressionType::K8, - }), - pdu_source: 1007, - share_id: 66_538, -}); -pub static MONITOR_LAYOUT_PDU_BUFFER: LazyLock> = LazyLock::new(|| { - let mut buffer = MONITOR_LAYOUT_HEADERS_BUFFER.to_vec(); - buffer.extend( - MONITOR_DATA_WITH_MONITORS_BUFFER - .to_vec() - .split_off(gcc::MONITOR_FLAGS_SIZE), - ); - buffer -}); + pdu_source: 1002, + share_id: 66_538, + }; + pub static ref MONITOR_LAYOUT_PDU: ShareControlHeader = ShareControlHeader { + share_control_pdu: ShareControlPdu::Data(ShareDataHeader { + share_data_pdu: ShareDataPdu::MonitorLayout(MonitorLayoutPdu { + monitors: crate::monitor_data::MONITOR_DATA_WITH_MONITORS.monitors.clone(), + }), + stream_priority: StreamPriority::Low, + compression_flags: CompressionFlags::empty(), + compression_type: client_info::CompressionType::K8, + }), + pdu_source: 1007, + share_id: 66_538, + }; + pub static ref MONITOR_LAYOUT_PDU_BUFFER: Vec = { + let mut buffer = MONITOR_LAYOUT_HEADERS_BUFFER.to_vec(); + buffer.extend( + MONITOR_DATA_WITH_MONITORS_BUFFER + .to_vec() + .split_off(gcc::MONITOR_FLAGS_SIZE), + ); + buffer + }; +} pub const CLIENT_INFO_PDU_BUFFER: [u8; concat_arrays_size!( CLIENT_INFO_PDU_SECURITY_HEADER_BUFFER, diff --git a/crates/ironrdp-testsuite-core/src/security_data.rs b/crates/ironrdp-testsuite-core/src/security_data.rs index 87a65c8e..96a1a2f4 100644 --- a/crates/ironrdp-testsuite-core/src/security_data.rs +++ b/crates/ironrdp-testsuite-core/src/security_data.rs @@ -1,7 +1,6 @@ -use std::sync::LazyLock; - use array_concat::concat_arrays; use ironrdp_pdu::gcc::{ClientSecurityData, EncryptionLevel, EncryptionMethod, ServerSecurityData}; +use lazy_static::lazy_static; pub const CLIENT_SECURITY_DATA_BUFFER: [u8; 8] = [ 0x1b, 0x00, 0x00, 0x00, // encryption methods @@ -36,36 +35,35 @@ pub const SERVER_CERT_BUFFER: [u8; 184] = [ 0x6c, 0xd6, 0x76, 0x84, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; -pub static CLIENT_SECURITY_DATA: LazyLock = LazyLock::new(|| ClientSecurityData { - encryption_methods: EncryptionMethod::BIT_40 - | EncryptionMethod::BIT_128 - | EncryptionMethod::BIT_56 - | EncryptionMethod::FIPS, - ext_encryption_methods: 0, -}); -pub static SERVER_SECURITY_DATA_WITHOUT_OPTIONAL_FIELDS: LazyLock = - LazyLock::new(|| ServerSecurityData { +lazy_static! { + pub static ref CLIENT_SECURITY_DATA: ClientSecurityData = ClientSecurityData { + encryption_methods: EncryptionMethod::BIT_40 + | EncryptionMethod::BIT_128 + | EncryptionMethod::BIT_56 + | EncryptionMethod::FIPS, + ext_encryption_methods: 0, + }; + pub static ref SERVER_SECURITY_DATA_WITHOUT_OPTIONAL_FIELDS: ServerSecurityData = ServerSecurityData { encryption_method: EncryptionMethod::empty(), encryption_level: EncryptionLevel::None, server_random: None, server_cert: Vec::new(), - }); -pub static SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS: LazyLock = - LazyLock::new(|| ServerSecurityData { + }; + pub static ref SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS: ServerSecurityData = ServerSecurityData { encryption_method: EncryptionMethod::BIT_128, encryption_level: EncryptionLevel::ClientCompatible, server_random: Some(SERVER_RANDOM_BUFFER), server_cert: SERVER_CERT_BUFFER.to_vec(), - }); -pub static SERVER_SECURITY_DATA_WITH_MISMATCH_OF_REQUIRED_AND_OPTIONAL_FIELDS: LazyLock = - LazyLock::new(|| ServerSecurityData { - encryption_method: EncryptionMethod::empty(), - encryption_level: EncryptionLevel::None, - server_random: Some(SERVER_RANDOM_BUFFER), - server_cert: SERVER_CERT_BUFFER.to_vec(), - }); + }; + pub static ref SERVER_SECURITY_DATA_WITH_MISMATCH_OF_REQUIRED_AND_OPTIONAL_FIELDS: ServerSecurityData = + ServerSecurityData { + encryption_method: EncryptionMethod::empty(), + encryption_level: EncryptionLevel::None, + server_random: Some(SERVER_RANDOM_BUFFER), + server_cert: SERVER_CERT_BUFFER.to_vec(), + }; +} -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_BUFFER: [u8; 232] = concat_arrays!( SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_PREFIX_BUFFER, (SERVER_RANDOM_BUFFER.len() as u32).to_le_bytes(), @@ -74,7 +72,6 @@ pub const SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_BUFFER: [u8; 232] = concat_a SERVER_CERT_BUFFER ); -#[expect(clippy::as_conversions, reason = "must be const casts")] pub const SERVER_SECURITY_DATA_WITH_INVALID_SERVER_RANDOM_BUFFER: [u8; 233] = concat_arrays!( SERVER_SECURITY_DATA_WITH_OPTIONAL_FIELDS_PREFIX_BUFFER, (SERVER_RANDOM_BUFFER.len() as u32 + 1).to_le_bytes(), diff --git a/crates/ironrdp-testsuite-core/tests/clipboard/mod.rs b/crates/ironrdp-testsuite-core/tests/clipboard/mod.rs index dc0641f4..bbcee7af 100644 --- a/crates/ironrdp-testsuite-core/tests/clipboard/mod.rs +++ b/crates/ironrdp-testsuite-core/tests/clipboard/mod.rs @@ -356,7 +356,7 @@ fn metafile_pdu_ms() { assert_eq!(metafile.y_ext, 423); // Just check some known arbitrary byte in raw metafile data - assert_eq!(metafile.data[metafile.data.len() - 6], 0x03); + assert_eq!(metafile.data()[metafile.data().len() - 6], 0x03); } else { panic!("Expected FormatDataResponse"); }; diff --git a/crates/ironrdp-testsuite-core/tests/dvc/data_first.rs b/crates/ironrdp-testsuite-core/tests/dvc/data_first.rs index aee11e2b..81c7605c 100644 --- a/crates/ironrdp-testsuite-core/tests/dvc/data_first.rs +++ b/crates/ironrdp-testsuite-core/tests/dvc/data_first.rs @@ -9,7 +9,6 @@ const DATA: [u8; 12] = [0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x const EDGE_CASE_LENGTH: u32 = 0x639; const EDGE_CASE_CHANNEL_ID: u32 = 0x07; const EDGE_CASE_PREFIX: [u8; 4] = [0x24, 0x7, 0x39, 0x6]; -#[expect(clippy::as_conversions)] const EDGE_CASE_DATA: [u8; EDGE_CASE_LENGTH as usize] = [ 0xe0, 0x24, 0xa9, 0xba, 0xe0, 0x68, 0xa9, 0xba, 0x8a, 0x73, 0x41, 0x25, 0x12, 0x12, 0x1c, 0x28, 0x3b, 0xa6, 0x34, 0x8, 0x8, 0x7a, 0x38, 0x34, 0x2c, 0xe8, 0xf8, 0xd0, 0xef, 0x18, 0xc2, 0xc, 0x27, 0x1f, 0xb1, 0x83, 0x3c, 0x58, diff --git a/crates/ironrdp-testsuite-core/tests/graphics/rle.rs b/crates/ironrdp-testsuite-core/tests/graphics/rle.rs new file mode 100644 index 00000000..a13a8cba --- /dev/null +++ b/crates/ironrdp-testsuite-core/tests/graphics/rle.rs @@ -0,0 +1,57 @@ +use rstest::rstest; + +/// 64x64 tile samples were generated using rdp-rs crate +#[rstest] +#[case::x27019fd9f222cebce9dfebcddb12bfa0( + include_bytes!("../../test_data/rle/tile-27019fd9f222cebce9dfebcddb12bfa0-compressed.bin"), + include_bytes!("../../test_data/rle/tile-27019fd9f222cebce9dfebcddb12bfa0-decompressed.bin"), +)] +#[case::x284f668a9366a95e45f15b6bf634a633( + include_bytes!("../../test_data/rle/tile-284f668a9366a95e45f15b6bf634a633-compressed.bin"), + include_bytes!("../../test_data/rle/tile-284f668a9366a95e45f15b6bf634a633-decompressed.bin"), +)] +#[case::x28c08e75c82ab598c5ab85d1bfc00253( + include_bytes!("../../test_data/rle/tile-28c08e75c82ab598c5ab85d1bfc00253-compressed.bin"), + include_bytes!("../../test_data/rle/tile-28c08e75c82ab598c5ab85d1bfc00253-decompressed.bin"), +)] +#[case::x2de3f3262a5eeecc3152552c178b782a( + include_bytes!("../../test_data/rle/tile-2de3f3262a5eeecc3152552c178b782a-compressed.bin"), + include_bytes!("../../test_data/rle/tile-2de3f3262a5eeecc3152552c178b782a-decompressed.bin"), +)] +#[case::x3fc8124af9be2fe88b445db60c36eddc( + include_bytes!("../../test_data/rle/tile-3fc8124af9be2fe88b445db60c36eddc-compressed.bin"), + include_bytes!("../../test_data/rle/tile-3fc8124af9be2fe88b445db60c36eddc-decompressed.bin"), +)] +#[case::x4d75aa6a18c435c6230ba739b802a861( + include_bytes!("../../test_data/rle/tile-4d75aa6a18c435c6230ba739b802a861-compressed.bin"), + include_bytes!("../../test_data/rle/tile-4d75aa6a18c435c6230ba739b802a861-decompressed.bin"), +)] +#[case::x8b8ccc77526730d0cd8989901cc031ec( + include_bytes!("../../test_data/rle/tile-8b8ccc77526730d0cd8989901cc031ec-compressed.bin"), + include_bytes!("../../test_data/rle/tile-8b8ccc77526730d0cd8989901cc031ec-decompressed.bin"), +)] +#[case::x94bb5b131eb3bc110905dfcb0f60da79( + include_bytes!("../../test_data/rle/tile-94bb5b131eb3bc110905dfcb0f60da79-compressed.bin"), + include_bytes!("../../test_data/rle/tile-94bb5b131eb3bc110905dfcb0f60da79-decompressed.bin"), +)] +#[case::x9b06660a1da806d2d48ce3f46b45d571( + include_bytes!("../../test_data/rle/tile-9b06660a1da806d2d48ce3f46b45d571-compressed.bin"), + include_bytes!("../../test_data/rle/tile-9b06660a1da806d2d48ce3f46b45d571-decompressed.bin"), +)] +#[case::xa412fbe2b435ac627ce39048aa3d3fb3( + include_bytes!("../../test_data/rle/tile-a412fbe2b435ac627ce39048aa3d3fb3-compressed.bin"), + include_bytes!("../../test_data/rle/tile-a412fbe2b435ac627ce39048aa3d3fb3-decompressed.bin"), +)] +#[case::xaa326e7a536cc8a0420c44bdf4ef8d97( + include_bytes!("../../test_data/rle/tile-aa326e7a536cc8a0420c44bdf4ef8d97-compressed.bin"), + include_bytes!("../../test_data/rle/tile-aa326e7a536cc8a0420c44bdf4ef8d97-decompressed.bin"), +)] +#[case::xfbcefc9af4db651aefd91bcabc8ea9fc( + include_bytes!("../../test_data/rle/tile-fbcefc9af4db651aefd91bcabc8ea9fc-compressed.bin"), + include_bytes!("../../test_data/rle/tile-fbcefc9af4db651aefd91bcabc8ea9fc-decompressed.bin"), +)] +fn decompress_bpp_16(#[case] src: &[u8], #[case] expected: &[u8]) { + let mut out = Vec::new(); + ironrdp_graphics::rle::decompress_16_bpp(src, &mut out, 64, 64).expect("decompress 16 bpp"); + assert_eq!(out, expected); +} diff --git a/crates/ironrdp-testsuite-core/tests/graphics/rle/mod.rs b/crates/ironrdp-testsuite-core/tests/graphics/rle/mod.rs deleted file mode 100644 index 6b1f155a..00000000 --- a/crates/ironrdp-testsuite-core/tests/graphics/rle/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -use rstest::rstest; - -/// 64x64 tile samples were generated using rdp-rs crate -#[rstest] -#[case::x27019fd9f222cebce9dfebcddb12bfa0( - include_bytes!("../../../test_data/rle/tile-27019fd9f222cebce9dfebcddb12bfa0-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-27019fd9f222cebce9dfebcddb12bfa0-decompressed.bin"), -)] -#[case::x284f668a9366a95e45f15b6bf634a633( - include_bytes!("../../../test_data/rle/tile-284f668a9366a95e45f15b6bf634a633-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-284f668a9366a95e45f15b6bf634a633-decompressed.bin"), -)] -#[case::x28c08e75c82ab598c5ab85d1bfc00253( - include_bytes!("../../../test_data/rle/tile-28c08e75c82ab598c5ab85d1bfc00253-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-28c08e75c82ab598c5ab85d1bfc00253-decompressed.bin"), -)] -#[case::x2de3f3262a5eeecc3152552c178b782a( - include_bytes!("../../../test_data/rle/tile-2de3f3262a5eeecc3152552c178b782a-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-2de3f3262a5eeecc3152552c178b782a-decompressed.bin"), -)] -#[case::x3fc8124af9be2fe88b445db60c36eddc( - include_bytes!("../../../test_data/rle/tile-3fc8124af9be2fe88b445db60c36eddc-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-3fc8124af9be2fe88b445db60c36eddc-decompressed.bin"), -)] -#[case::x4d75aa6a18c435c6230ba739b802a861( - include_bytes!("../../../test_data/rle/tile-4d75aa6a18c435c6230ba739b802a861-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-4d75aa6a18c435c6230ba739b802a861-decompressed.bin"), -)] -#[case::x8b8ccc77526730d0cd8989901cc031ec( - include_bytes!("../../../test_data/rle/tile-8b8ccc77526730d0cd8989901cc031ec-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-8b8ccc77526730d0cd8989901cc031ec-decompressed.bin"), -)] -#[case::x94bb5b131eb3bc110905dfcb0f60da79( - include_bytes!("../../../test_data/rle/tile-94bb5b131eb3bc110905dfcb0f60da79-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-94bb5b131eb3bc110905dfcb0f60da79-decompressed.bin"), -)] -#[case::x9b06660a1da806d2d48ce3f46b45d571( - include_bytes!("../../../test_data/rle/tile-9b06660a1da806d2d48ce3f46b45d571-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-9b06660a1da806d2d48ce3f46b45d571-decompressed.bin"), -)] -#[case::xa412fbe2b435ac627ce39048aa3d3fb3( - include_bytes!("../../../test_data/rle/tile-a412fbe2b435ac627ce39048aa3d3fb3-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-a412fbe2b435ac627ce39048aa3d3fb3-decompressed.bin"), -)] -#[case::xaa326e7a536cc8a0420c44bdf4ef8d97( - include_bytes!("../../../test_data/rle/tile-aa326e7a536cc8a0420c44bdf4ef8d97-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-aa326e7a536cc8a0420c44bdf4ef8d97-decompressed.bin"), -)] -#[case::xfbcefc9af4db651aefd91bcabc8ea9fc( - include_bytes!("../../../test_data/rle/tile-fbcefc9af4db651aefd91bcabc8ea9fc-compressed.bin"), - include_bytes!("../../../test_data/rle/tile-fbcefc9af4db651aefd91bcabc8ea9fc-decompressed.bin"), -)] -fn decompress_bpp_16(#[case] src: &[u8], #[case] expected: &[u8]) { - let mut out = Vec::new(); - ironrdp_graphics::rle::decompress_16_bpp(src, &mut out, 64, 64).expect("decompress 16 bpp"); - assert_eq!(out, expected); -} diff --git a/crates/ironrdp-testsuite-core/tests/pdu/input.rs b/crates/ironrdp-testsuite-core/tests/pdu/input.rs index 7b31672c..6bc1b54d 100644 --- a/crates/ironrdp-testsuite-core/tests/pdu/input.rs +++ b/crates/ironrdp-testsuite-core/tests/pdu/input.rs @@ -1,5 +1,3 @@ -use std::sync::LazyLock; - use ironrdp_core::{decode_cursor, encode_vec, ReadCursor}; use ironrdp_pdu::input::fast_path::{FastPathInput, FastPathInputEvent}; use ironrdp_pdu::input::mouse::PointerFlags; @@ -11,47 +9,46 @@ const FASTPATH_INPUT_MESSAGE: [u8; 44] = [ 0x0, 0x28, 0x4, ]; -static FASTPATH_INPUT: LazyLock = LazyLock::new(|| { - FastPathInput::new(vec![ +lazy_static::lazy_static! { + pub static ref FASTPATH_INPUT: FastPathInput = FastPathInput(vec![ FastPathInputEvent::MouseEvent(MousePdu { flags: PointerFlags::DOWN | PointerFlags::LEFT_BUTTON, number_of_wheel_rotation_units: 0, x_position: 26, - y_position: 1062, + y_position: 1062 }), FastPathInputEvent::MouseEvent(MousePdu { flags: PointerFlags::MOVE, number_of_wheel_rotation_units: 0, x_position: 27, - y_position: 1062, + y_position: 1062 }), FastPathInputEvent::MouseEvent(MousePdu { flags: PointerFlags::LEFT_BUTTON, number_of_wheel_rotation_units: 0, x_position: 27, - y_position: 1062, + y_position: 1062 }), FastPathInputEvent::MouseEvent(MousePdu { flags: PointerFlags::MOVE, number_of_wheel_rotation_units: 0, x_position: 26, - y_position: 1063, + y_position: 1063 }), FastPathInputEvent::MouseEvent(MousePdu { flags: PointerFlags::MOVE, number_of_wheel_rotation_units: 0, x_position: 25, - y_position: 1063, + y_position: 1063 }), FastPathInputEvent::MouseEvent(MousePdu { flags: PointerFlags::MOVE, number_of_wheel_rotation_units: 0, x_position: 25, - y_position: 1064, - }), - ]) - .expect("can't panic") -}); + y_position: 1064 + }) + ]); +} #[test] fn from_buffer_correctly_parses_fastpath_input_message() { diff --git a/crates/ironrdp-testsuite-core/tests/pdu/pointer/mod.rs b/crates/ironrdp-testsuite-core/tests/pdu/pointer.rs similarity index 96% rename from crates/ironrdp-testsuite-core/tests/pdu/pointer/mod.rs rename to crates/ironrdp-testsuite-core/tests/pdu/pointer.rs index 5c0d0216..ad058ff4 100644 --- a/crates/ironrdp-testsuite-core/tests/pdu/pointer/mod.rs +++ b/crates/ironrdp-testsuite-core/tests/pdu/pointer.rs @@ -38,7 +38,7 @@ fn expect_pointer_png(pointer: &DecodedPointer, expected_file_path: &str) { #[test] fn new_pointer_32bpp() { - let data = include_bytes!("../../../test_data/pdu/pointer/new_pointer_32bpp.bin"); + let data = include_bytes!("../../test_data/pdu/pointer/new_pointer_32bpp.bin"); let mut parsed = ironrdp_core::decode::>(data).unwrap(); let decoded = DecodedPointer::decode_pointer_attribute(&parsed, PointerBitmapTarget::Software).unwrap(); expect_pointer_png(&decoded, "pdu/pointer/new_pointer_32bpp.png"); @@ -69,7 +69,7 @@ fn new_pointer_32bpp() { #[test] fn large_pointer_32bpp() { - let data = include_bytes!("../../../test_data/pdu/pointer/large_pointer_32bpp.bin"); + let data = include_bytes!("../../test_data/pdu/pointer/large_pointer_32bpp.bin"); let mut parsed = ironrdp_core::decode::>(data).unwrap(); let decoded = DecodedPointer::decode_large_pointer_attribute(&parsed, PointerBitmapTarget::Software).unwrap(); expect_pointer_png(&decoded, "pdu/pointer/large_pointer_32bpp.png"); @@ -98,7 +98,7 @@ fn large_pointer_32bpp() { #[test] fn color_pointer_24bpp() { - let data = include_bytes!("../../../test_data/pdu/pointer/color_pointer_24bpp.bin"); + let data = include_bytes!("../../test_data/pdu/pointer/color_pointer_24bpp.bin"); let mut parsed = ironrdp_core::decode::>(data).unwrap(); let decoded = DecodedPointer::decode_color_pointer_attribute(&parsed, PointerBitmapTarget::Software).unwrap(); expect_pointer_png(&decoded, "pdu/pointer/color_pointer_24bpp.png"); diff --git a/crates/ironrdp-testsuite-core/tests/pdu/rfx.rs b/crates/ironrdp-testsuite-core/tests/pdu/rfx.rs index c6221933..9a8f968b 100644 --- a/crates/ironrdp-testsuite-core/tests/pdu/rfx.rs +++ b/crates/ironrdp-testsuite-core/tests/pdu/rfx.rs @@ -1,5 +1,3 @@ -use std::sync::LazyLock; - use ironrdp_pdu::codecs::rfx::*; use ironrdp_pdu::decode; use ironrdp_testsuite_core::encode_decode_test; @@ -254,14 +252,12 @@ const FRAME_BEGIN_PDU: Block<'_> = Block::CodecChannel(CodecChannel::FrameBegin( const FRAME_END_PDU: Block<'_> = Block::CodecChannel(CodecChannel::FrameEnd(FrameEndPdu)); -static CHANNELS_PDU: LazyLock> = LazyLock::new(|| { - Block::Channels(ChannelsPdu(vec![ +lazy_static::lazy_static! { + static ref CHANNELS_PDU: Block<'static> = Block::Channels(ChannelsPdu(vec![ RfxChannel { width: 64, height: 64 }, - RfxChannel { width: 32, height: 32 }, - ])) -}); -static REGION_PDU: LazyLock> = LazyLock::new(|| { - Block::CodecChannel(CodecChannel::Region(RegionPdu { + RfxChannel { width: 32, height: 32 } + ])); + static ref REGION_PDU: Block<'static> = Block::CodecChannel(CodecChannel::Region(RegionPdu { rectangles: vec![ RfxRectangle { x: 0, @@ -275,11 +271,9 @@ static REGION_PDU: LazyLock> = LazyLock::new(|| { width: 0xff, height: 0xff, }, - ], - })) -}); -static TILESET_PDU: LazyLock> = LazyLock::new(|| { - Block::CodecChannel(CodecChannel::TileSet(TileSetPdu { + ] + })); + static ref TILESET_PDU: Block<'static> = Block::CodecChannel(CodecChannel::TileSet(TileSetPdu { entropy_algorithm: EntropyAlgorithm::Rlgr3, quants: vec![ Quant { @@ -322,8 +316,8 @@ static TILESET_PDU: LazyLock> = LazyLock::new(|| { cr_data: &TILE2_CR_DATA, }, ], - })) -}); + })); +} #[test] fn from_buffer_for_block_header_returns_error_on_zero_data_length() { diff --git a/crates/ironrdp-testsuite-core/tests/rdcleanpath.rs b/crates/ironrdp-testsuite-core/tests/rdcleanpath.rs index 9c4cf28d..4c91f3b3 100644 --- a/crates/ironrdp-testsuite-core/tests/rdcleanpath.rs +++ b/crates/ironrdp-testsuite-core/tests/rdcleanpath.rs @@ -1,7 +1,4 @@ -use expect_test::{expect, Expect}; -use ironrdp_rdcleanpath::{ - DetectionResult, RDCleanPathErr, RDCleanPathPdu, GENERAL_ERROR_CODE, NEGOTIATION_ERROR_CODE, VERSION_1, -}; +use ironrdp_rdcleanpath::{DetectionResult, RDCleanPathPdu, VERSION_1}; use rstest::rstest; fn request() -> RDCleanPathPdu { @@ -126,62 +123,3 @@ fn detect_not_enough(#[case] payload: &[u8]) { let result = RDCleanPathPdu::detect(payload); assert_eq!(result, DetectionResult::NotEnoughBytes); } - -#[rstest] -#[case::http( - RDCleanPathErr { - error_code: GENERAL_ERROR_CODE, - http_status_code: Some(404), - wsa_last_error: None, - tls_alert_code: None, - }, - expect!["general error (code 1); HTTP 404 not found"], -)] -#[case::wsa( - RDCleanPathErr { - error_code: GENERAL_ERROR_CODE, - http_status_code: None, - wsa_last_error: Some(10061), - tls_alert_code: None, - }, - expect!["general error (code 1); WSA 10061 connection refused"], -)] -#[case::tls( - RDCleanPathErr { - error_code: GENERAL_ERROR_CODE, - http_status_code: None, - wsa_last_error: None, - tls_alert_code: Some(40), - }, - expect!["general error (code 1); TLS alert 40 handshake failure"], -)] -#[case::nego( - RDCleanPathErr { - error_code: NEGOTIATION_ERROR_CODE, - http_status_code: None, - wsa_last_error: None, - tls_alert_code: None, - }, - expect!["negotiation error (code 2)"], -)] -#[case::combined( - RDCleanPathErr { - error_code: GENERAL_ERROR_CODE, - http_status_code: Some(502), - wsa_last_error: Some(10060), - tls_alert_code: Some(45), - }, - expect!["general error (code 1); HTTP 502 bad gateway; WSA 10060 connection timed out; TLS alert 45 certificate expired"], -)] -#[case::unknown_codes( - RDCleanPathErr { - error_code: 99, - http_status_code: Some(999), - wsa_last_error: Some(65000), - tls_alert_code: Some(255), - }, - expect!["unknown error (code 99); HTTP 999 unknown HTTP status; WSA 65000 unknown WSA error; TLS alert 255 unknown TLS alert"], -)] -fn error_display(#[case] error: RDCleanPathErr, #[case] expected: Expect) { - expected.assert_eq(&error.to_string()); -} diff --git a/crates/ironrdp-testsuite-extra/tests/mod.rs b/crates/ironrdp-testsuite-extra/tests/tests.rs similarity index 96% rename from crates/ironrdp-testsuite-extra/tests/mod.rs rename to crates/ironrdp-testsuite-extra/tests/tests.rs index 8cc24fab..7127fa5f 100644 --- a/crates/ironrdp-testsuite-extra/tests/mod.rs +++ b/crates/ironrdp-testsuite-extra/tests/tests.rs @@ -87,7 +87,7 @@ async fn test_deactivation_reactivation() { desktop_size, enable_server_pointer, pointer_software_rendering, - } = connection_activation.connection_activation_state() + } = connection_activation.state { debug!(?desktop_size, "Deactivation-Reactivation Sequence completed"); // Update image size with the new desktop size. @@ -205,20 +205,18 @@ where .await .expect("begin connection"); let initial_stream = framed.into_inner_no_leftover(); - let (upgraded_stream, tls_cert) = ironrdp_tls::upgrade(initial_stream, "localhost") + let (upgraded_stream, server_public_key) = ironrdp_tls::upgrade(initial_stream, "localhost") .await .expect("TLS upgrade"); let upgraded = ironrdp_tokio::mark_as_upgraded(should_upgrade, &mut connector); let mut upgraded_framed = ironrdp_tokio::TokioFramed::new(upgraded_stream); - let server_public_key = - ironrdp_tls::extract_tls_server_public_key(&tls_cert).expect("extract server public key"); let connection_result = ironrdp_async::connect_finalize( upgraded, - connector, &mut upgraded_framed, - &mut ironrdp_tokio::reqwest::ReqwestNetworkClient::new(), + connector, "localhost".into(), - server_public_key.to_owned(), + server_public_key, + None, None, ) .await diff --git a/crates/ironrdp-tls/CHANGELOG.md b/crates/ironrdp-tls/CHANGELOG.md index 2aaa1c25..455742e7 100644 --- a/crates/ironrdp-tls/CHANGELOG.md +++ b/crates/ironrdp-tls/CHANGELOG.md @@ -6,15 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.2.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-tls-v0.1.4...ironrdp-tls-v0.2.0)] - 2025-12-18 - -### Features - -- [**breaking**] Return x509_cert::Certificate from upgrade() ([#1054](https://github.com/Devolutions/IronRDP/issues/1054)) ([bd2aed7686](https://github.com/Devolutions/IronRDP/commit/bd2aed76867f4038c32df9a0d24532ee40d2f14c)) - - This allows client applications to verify details of the certificate, - possibly with the user, when connecting to a server using TLS. - ## [[0.1.4](https://github.com/Devolutions/IronRDP/compare/ironrdp-tls-v0.1.3...ironrdp-tls-v0.1.4)] - 2025-08-29 ### Build diff --git a/crates/ironrdp-tls/Cargo.toml b/crates/ironrdp-tls/Cargo.toml index 1c719be0..55556ffd 100644 --- a/crates/ironrdp-tls/Cargo.toml +++ b/crates/ironrdp-tls/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-tls" -version = "0.2.0" +version = "0.1.4" readme = "README.md" description = "TLS boilerplate common with most IronRDP clients" edition.workspace = true @@ -23,7 +23,7 @@ stub = [] [dependencies] tokio = { version = "1.47" } -x509-cert = { version = "0.2", default-features = false, features = ["std"], optional = true } # public +x509-cert = { version = "0.2", default-features = false, features = ["std"], optional = true } tokio-native-tls = { version = "0.3", optional = true } # public tokio-rustls = { version = "0.26", optional = true } # public diff --git a/crates/ironrdp-tls/src/lib.rs b/crates/ironrdp-tls/src/lib.rs index 58349712..63261890 100644 --- a/crates/ironrdp-tls/src/lib.rs +++ b/crates/ironrdp-tls/src/lib.rs @@ -25,9 +25,21 @@ compile_error!("a TLS backend must be selected by enabling a single feature out #[cfg(any(feature = "stub", feature = "native-tls", feature = "rustls"))] pub use impl_::{upgrade, TlsStream}; -pub fn extract_tls_server_public_key(cert: &x509_cert::Certificate) -> Option<&[u8]> { - cert.tbs_certificate +#[cfg(any(feature = "native-tls", feature = "rustls"))] +pub(crate) fn extract_tls_server_public_key(cert: &[u8]) -> std::io::Result> { + use std::io; + + use x509_cert::der::Decode as _; + + let cert = x509_cert::Certificate::from_der(cert).map_err(io::Error::other)?; + + let server_public_key = cert + .tbs_certificate .subject_public_key_info .subject_public_key .as_bytes() + .ok_or_else(|| io::Error::other("subject public key BIT STRING is not aligned"))? + .to_owned(); + + Ok(server_public_key) } diff --git a/crates/ironrdp-tls/src/native_tls.rs b/crates/ironrdp-tls/src/native_tls.rs index f3b7d0d0..0e652e7e 100644 --- a/crates/ironrdp-tls/src/native_tls.rs +++ b/crates/ironrdp-tls/src/native_tls.rs @@ -4,7 +4,7 @@ use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt as _}; pub type TlsStream = tokio_native_tls::TlsStream; -pub async fn upgrade(stream: S, server_name: &str) -> io::Result<(TlsStream, x509_cert::Certificate)> +pub async fn upgrade(stream: S, server_name: &str) -> io::Result<(TlsStream, Vec)> where S: Unpin + AsyncRead + AsyncWrite, { @@ -24,18 +24,15 @@ where tls_stream.flush().await?; - let tls_cert = { - use x509_cert::der::Decode as _; - + let server_public_key = { let cert = tls_stream .get_ref() .peer_certificate() .map_err(|e| io::Error::new(io::ErrorKind::Other, e))? .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "peer certificate is missing"))?; let cert = cert.to_der().map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - - x509_cert::Certificate::from_der(&cert).map_err(io::Error::other)? + crate::extract_tls_server_public_key(&cert)? }; - Ok((tls_stream, tls_cert)) + Ok((tls_stream, server_public_key)) } diff --git a/crates/ironrdp-tls/src/rustls.rs b/crates/ironrdp-tls/src/rustls.rs index ca8778d5..10c8d8ab 100644 --- a/crates/ironrdp-tls/src/rustls.rs +++ b/crates/ironrdp-tls/src/rustls.rs @@ -1,12 +1,12 @@ use std::io; use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt as _}; -use tokio_rustls::rustls; use tokio_rustls::rustls::pki_types::ServerName; +use tokio_rustls::rustls::{self}; pub type TlsStream = tokio_rustls::client::TlsStream; -pub async fn upgrade(stream: S, server_name: &str) -> io::Result<(TlsStream, x509_cert::Certificate)> +pub async fn upgrade(stream: S, server_name: &str) -> io::Result<(TlsStream, Vec)> where S: Unpin + AsyncRead + AsyncWrite, { @@ -35,20 +35,17 @@ where tls_stream.flush().await?; - let tls_cert = { - use x509_cert::der::Decode as _; - + let server_public_key = { let cert = tls_stream .get_ref() .1 .peer_certificates() .and_then(|certificates| certificates.first()) .ok_or_else(|| io::Error::other("peer certificate is missing"))?; - - x509_cert::Certificate::from_der(cert).map_err(io::Error::other)? + crate::extract_tls_server_public_key(cert)? }; - Ok((tls_stream, tls_cert)) + Ok((tls_stream, server_public_key)) } mod danger { diff --git a/crates/ironrdp-tokio/CHANGELOG.md b/crates/ironrdp-tokio/CHANGELOG.md index db3bd881..4265c72b 100644 --- a/crates/ironrdp-tokio/CHANGELOG.md +++ b/crates/ironrdp-tokio/CHANGELOG.md @@ -6,49 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.8.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-tokio-v0.7.0...ironrdp-tokio-v0.8.0)] - 2025-12-18 - -### Features - -- Add MovableTokioFramed for Send+!Sync context ([#1033](https://github.com/Devolutions/IronRDP/issues/1033)) ([966ba8a53e](https://github.com/Devolutions/IronRDP/commit/966ba8a53e43a193271f40b9db80e45e495e2f24)) - - The `ironrdp-tokio` crate currently provides the following two - `Framed` implementations using the standard `tokio::io` traits: - - `type TokioFramed = Framed>` where `S: Send + Sync + - Unpin` - - `type LocalTokioFramed = Framed>` where `S: - Unpin` - - The former is meant for multi-threaded runtimes and the latter is meant - for single-threaded runtimes. - - This PR adds a third `Framed` implementation: - - `pub type MovableTokioFramed = Framed>` where - `S: Send + Unpin` - - This is a valid usecase as some implementations of the `tokio::io` - traits are `Send` but `!Sync`. Without this new third type, consumers of - `Framed` who have a `S: Send + !Sync` trait for their streams are - forced to downgrade to `LocalTokioFramed` and do some hacky workaround - with `tokio::task::spawn_blocking` since the defined associated futures, - `ReadFut` and `WriteAllFut`, are neither `Send` nor `Sync`. - -### Bug Fixes - -- [**breaking**] Use static dispatch for NetworkClient trait ([#1043](https://github.com/Devolutions/IronRDP/issues/1043)) ([bca6d190a8](https://github.com/Devolutions/IronRDP/commit/bca6d190a870708468534d224ff225a658767a9a)) - - - Rename `AsyncNetworkClient` to `NetworkClient` - - Replace dynamic dispatch (`Option<&mut dyn ...>`) with static dispatch - using generics (`&mut N where N: NetworkClient`) - - Reorder `connect_finalize` parameters for consistency across crates - -### Build - -- Bump picky and sspi ([#1028](https://github.com/Devolutions/IronRDP/issues/1028)) ([5bd319126d](https://github.com/Devolutions/IronRDP/commit/5bd319126d32fbd8e505508e27ab2b1a18a83d04)) - - This fixes build issues with some dependencies. - ## [[0.6.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-tokio-v0.5.1...ironrdp-tokio-v0.6.0)] - 2025-07-08 ### Build diff --git a/crates/ironrdp-tokio/Cargo.toml b/crates/ironrdp-tokio/Cargo.toml index abb08162..e129ac44 100644 --- a/crates/ironrdp-tokio/Cargo.toml +++ b/crates/ironrdp-tokio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp-tokio" -version = "0.8.0" +version = "0.7.0" readme = "README.md" description = "`Framed*` traits implementation above Tokio’s traits" edition.workspace = true @@ -23,11 +23,11 @@ reqwest-native-tls = ["reqwest", "reqwest?/native-tls"] [dependencies] bytes = "1" -ironrdp-async = { path = "../ironrdp-async", version = "0.8" } # public -ironrdp-connector = { path = "../ironrdp-connector", version = "0.8", optional = true } +ironrdp-async = { path = "../ironrdp-async", version = "0.7" } # public +ironrdp-connector = { path = "../ironrdp-connector", version = "0.7", optional = true } tokio = { version = "1", features = ["io-util"] } reqwest = { version = "0.12", default-features = false, features = ["http2", "system-proxy"], optional = true } -sspi = { version = "0.18", features = ["network_client", "dns_resolver"], optional = true } +sspi = { version = "0.16", features = ["network_client", "dns_resolver"], optional = true } url = { version = "2.5", optional = true } [lints] diff --git a/crates/ironrdp-tokio/src/lib.rs b/crates/ironrdp-tokio/src/lib.rs index b188e84b..010b2219 100644 --- a/crates/ironrdp-tokio/src/lib.rs +++ b/crates/ironrdp-tokio/src/lib.rs @@ -158,66 +158,3 @@ where }) } } - -pub type MovableTokioFramed = Framed>; - -pub struct MovableTokioStream { - inner: S, -} - -impl StreamWrapper for MovableTokioStream { - type InnerStream = S; - - fn from_inner(stream: Self::InnerStream) -> Self { - Self { inner: stream } - } - - fn into_inner(self) -> Self::InnerStream { - self.inner - } - - fn get_inner(&self) -> &Self::InnerStream { - &self.inner - } - - fn get_inner_mut(&mut self) -> &mut Self::InnerStream { - &mut self.inner - } -} - -impl FramedRead for MovableTokioStream -where - S: Send + Unpin + AsyncRead, -{ - type ReadFut<'read> - = Pin> + Send + 'read>> - where - Self: 'read; - - fn read<'a>(&'a mut self, buf: &'a mut BytesMut) -> Self::ReadFut<'a> { - use tokio::io::AsyncReadExt as _; - - Box::pin(async { self.inner.read_buf(buf).await }) - } -} - -impl FramedWrite for MovableTokioStream -where - S: Send + Unpin + AsyncWrite, -{ - type WriteAllFut<'write> - = Pin> + Send + 'write>> - where - Self: 'write; - - fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> Self::WriteAllFut<'a> { - use tokio::io::AsyncWriteExt as _; - - Box::pin(async { - self.inner.write_all(buf).await?; - self.inner.flush().await?; - - Ok(()) - }) - } -} diff --git a/crates/ironrdp-tokio/src/reqwest.rs b/crates/ironrdp-tokio/src/reqwest.rs index deeee192..68060c27 100644 --- a/crates/ironrdp-tokio/src/reqwest.rs +++ b/crates/ironrdp-tokio/src/reqwest.rs @@ -1,21 +1,26 @@ +use core::future::Future; use core::net::{IpAddr, Ipv4Addr}; +use core::pin::Pin; -use ironrdp_connector::{custom_err, general_err, ConnectorResult}; +use ironrdp_connector::{custom_err, ConnectorResult}; use reqwest::Client; use sspi::{Error, ErrorKind}; use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _}; use tokio::net::{TcpStream, UdpSocket}; use url::Url; -use crate::NetworkClient; +use crate::AsyncNetworkClient; pub struct ReqwestNetworkClient { client: Option, } -impl NetworkClient for ReqwestNetworkClient { - async fn send(&mut self, network_request: &sspi::generator::NetworkRequest) -> ConnectorResult> { - ReqwestNetworkClient::send_request(self, network_request).await +impl AsyncNetworkClient for ReqwestNetworkClient { + fn send<'a>( + &'a mut self, + network_request: &'a sspi::generator::NetworkRequest, + ) -> Pin>> + 'a>> { + Box::pin(ReqwestNetworkClient::send_request(self, network_request)) } } @@ -57,10 +62,7 @@ impl ReqwestNetworkClient { .map_err(|e| Error::new(ErrorKind::NoAuthenticatingAuthority, format!("{e:?}"))) .map_err(|e| custom_err!("failed to send KDC request over TCP", e))?; - let len = usize::try_from(len) - .map_err(|_| general_err!("invalid buffer length: out of range integral type conversion"))?; - - let mut buf = vec![0; len + 4]; + let mut buf = vec![0; len as usize + 4]; buf[0..4].copy_from_slice(&(len.to_be_bytes())); stream diff --git a/crates/ironrdp-web/src/canvas.rs b/crates/ironrdp-web/src/canvas.rs index 96b9df50..fcb7464e 100644 --- a/crates/ironrdp-web/src/canvas.rs +++ b/crates/ironrdp-web/src/canvas.rs @@ -1,6 +1,5 @@ use core::num::NonZeroU32; -use anyhow::Context as _; use ironrdp::pdu::geometry::{InclusiveRectangle, Rectangle as _}; use softbuffer::{NoDisplayHandle, NoWindowHandle}; use web_sys::HtmlCanvasElement; @@ -62,7 +61,7 @@ impl Canvas { let region_width_usize = usize::from(region_width); for dst_row in dst - .chunks_exact_mut(usize::try_from(self.width.get()).context("canvas width")?) + .chunks_exact_mut(self.width.get() as usize) .skip(region_top_usize) .take(region_height_usize) { diff --git a/crates/ironrdp-web/src/error.rs b/crates/ironrdp-web/src/error.rs index 93772856..4e159ef9 100644 --- a/crates/ironrdp-web/src/error.rs +++ b/crates/ironrdp-web/src/error.rs @@ -15,7 +15,7 @@ impl IronError { impl iron_remote_desktop::IronError for IronError { fn backtrace(&self) -> String { - format!("{:#}", self.source) + format!("{:?}", self.source) } fn kind(&self) -> IronErrorKind { @@ -27,7 +27,7 @@ impl From for IronError { fn from(e: connector::ConnectorError) -> Self { use sspi::credssp::NStatusCode; - let kind = match e.kind() { + let kind = match e.kind { ConnectorErrorKind::Credssp(sspi::Error { nstatus: Some(NStatusCode::WRONG_PASSWORD), .. diff --git a/crates/ironrdp-web/src/network_client.rs b/crates/ironrdp-web/src/network_client.rs index 0e32efe8..f22a3b03 100644 --- a/crates/ironrdp-web/src/network_client.rs +++ b/crates/ironrdp-web/src/network_client.rs @@ -1,45 +1,53 @@ +use core::pin::Pin; + +use futures_util::Future; use ironrdp::connector::sspi::generator::NetworkRequest; use ironrdp::connector::sspi::network_client::NetworkProtocol; use ironrdp::connector::{custom_err, reason_err, ConnectorResult}; -use ironrdp_futures::NetworkClient; +use ironrdp_futures::AsyncNetworkClient; use tracing::debug; #[derive(Debug)] pub(crate) struct WasmNetworkClient; -impl NetworkClient for WasmNetworkClient { - async fn send(&mut self, network_request: &NetworkRequest) -> ConnectorResult> { - debug!(?network_request.protocol, ?network_request.url); +impl AsyncNetworkClient for WasmNetworkClient { + fn send<'a>( + &'a mut self, + network_request: &'a NetworkRequest, + ) -> Pin>> + 'a>> { + Box::pin(async move { + debug!(?network_request.protocol, ?network_request.url); - match &network_request.protocol { - NetworkProtocol::Http | NetworkProtocol::Https => { - let body = js_sys::Uint8Array::from(network_request.data.as_slice()); + match &network_request.protocol { + NetworkProtocol::Http | NetworkProtocol::Https => { + let body = js_sys::Uint8Array::from(network_request.data.as_slice()); - let response = gloo_net::http::Request::post(network_request.url.as_str()) - .header("keep-alive", "true") - .body(body) - .map_err(|e| custom_err!("failed to send KDC request", e))? - .send() - .await - .map_err(|e| custom_err!("failed to send KDC request", e))?; + let response = gloo_net::http::Request::post(network_request.url.as_str()) + .header("keep-alive", "true") + .body(body) + .map_err(|e| custom_err!("failed to send KDC request", e))? + .send() + .await + .map_err(|e| custom_err!("failed to send KDC request", e))?; - if !response.ok() { - return Err(reason_err!( - "KdcProxy", - "HTTP status error ({} {})", - response.status(), - response.status_text(), - )); + if !response.ok() { + return Err(reason_err!( + "KdcProxy", + "HTTP status error ({} {})", + response.status(), + response.status_text(), + )); + } + + let body = response + .binary() + .await + .map_err(|e| custom_err!("failed to retrieve HTTP response", e))?; + + Ok(body) } - - let body = response - .binary() - .await - .map_err(|e| custom_err!("failed to retrieve HTTP response", e))?; - - Ok(body) + unsupported => Err(reason_err!("CredSSP", "unsupported protocol: {unsupported:?}")), } - unsupported => Err(reason_err!("CredSSP", "unsupported protocol: {unsupported:?}")), - } + }) } } diff --git a/crates/ironrdp-web/src/session.rs b/crates/ironrdp-web/src/session.rs index 6d0e018a..e5933bad 100644 --- a/crates/ironrdp-web/src/session.rs +++ b/crates/ironrdp-web/src/session.rs @@ -69,7 +69,7 @@ struct SessionBuilderInner { use_display_control: bool, enable_credssp: bool, - outbound_message_size_limit: Option, + outbound_message_size_limit: Option, } impl Default for SessionBuilderInner { @@ -216,8 +216,8 @@ impl iron_remote_desktop::SessionBuilder for SessionBuilder { |enable_credssp: bool| { self.0.borrow_mut().enable_credssp = enable_credssp }; |outbound_message_size_limit: f64| { let limit = if outbound_message_size_limit >= 0.0 && outbound_message_size_limit <= f64::from(u32::MAX) { - #[expect(clippy::as_conversions, clippy::cast_possible_truncation, clippy::cast_sign_loss)] - { outbound_message_size_limit as usize } + #[expect(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + { outbound_message_size_limit as u32 } } else { warn!(outbound_message_size_limit, "Invalid outbound message size limit; fallback to unlimited"); 0 // Fallback to no limit for invalid values. @@ -722,7 +722,7 @@ impl iron_remote_desktop::Session for Session { desktop_size, enable_server_pointer, pointer_software_rendering, - } = box_connection_activation.connection_activation_state() + } = box_connection_activation.state { debug!("Deactivation-Reactivation Sequence completed"); image = DecodedImage::new(PixelFormat::RgbA32, desktop_size.width, desktop_size.height); @@ -781,7 +781,7 @@ impl iron_remote_desktop::Session for Session { use ironrdp::pdu::input::fast_path::FastPathInput; let event = ironrdp::input::synchronize_event(scroll_lock, num_lock, caps_lock, kana_lock); - let fastpath_input = FastPathInput::single(event); + let fastpath_input = FastPathInput(vec![event]); let frame = ironrdp::core::encode_vec(&fastpath_input).context("FastPathInput encoding")?; @@ -800,10 +800,10 @@ impl iron_remote_desktop::Session for Session { Ok(()) } - async fn on_clipboard_paste(&self, content: &Self::ClipboardData) -> Result<(), Self::Error> { + async fn on_clipboard_paste(&self, content: Self::ClipboardData) -> Result<(), Self::Error> { self.input_events_tx .unbounded_send(RdpInputEvent::ClipboardBackend( - WasmClipboardBackendMessage::LocalClipboardChanged(content.clone()), + WasmClipboardBackendMessage::LocalClipboardChanged(content), )) .context("Send clipboard backend event")?; @@ -899,20 +899,20 @@ fn build_config( async fn writer_task( rx: mpsc::UnboundedReceiver>, rdp_writer: WriteHalf, - outbound_limit: Option, + outbound_limit: Option, ) { debug!("writer task started"); async fn inner( mut rx: mpsc::UnboundedReceiver>, mut rdp_writer: WriteHalf, - outbound_limit: Option, + outbound_limit: Option, ) -> anyhow::Result<()> { while let Some(frame) = rx.next().await { match outbound_limit { - Some(max_size) if frame.len() > max_size => { + Some(max_size) if frame.len() > max_size as usize => { // Send in chunks. - for chunk in frame.chunks(max_size) { + for chunk in frame.chunks(max_size as usize) { rdp_writer.write_all(chunk).await.context("couldn't write chunk")?; rdp_writer.flush().await.context("couldn't flush chunk")?; } @@ -979,11 +979,11 @@ async fn connect( let connection_result = ironrdp_futures::connect_finalize( upgraded, - connector, &mut framed, - &mut WasmNetworkClient, + connector, (&destination).into(), server_public_key, + Some(&mut WasmNetworkClient), url::Url::parse(kdc_proxy_url.unwrap_or_default().as_str()) // if kdc_proxy_url does not exit, give url parser a empty string, it will fail anyway and map to a None .ok() .map(|url| KerberosConfig { @@ -1153,7 +1153,8 @@ where } } -#[expect(clippy::as_conversions, clippy::cast_sign_loss, clippy::cast_possible_truncation)] +#[expect(clippy::cast_sign_loss)] +#[expect(clippy::cast_possible_truncation)] fn f64_to_u16_saturating_cast(value: f64) -> u16 { value as u16 } diff --git a/crates/ironrdp/CHANGELOG.md b/crates/ironrdp/CHANGELOG.md index 48a74967..848a10d0 100644 --- a/crates/ironrdp/CHANGELOG.md +++ b/crates/ironrdp/CHANGELOG.md @@ -6,14 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [[0.14.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-v0.13.0...ironrdp-v0.14.0)] - 2025-12-18 - -### Build - -- Bump picky and sspi ([#1028](https://github.com/Devolutions/IronRDP/issues/1028)) ([5bd319126d](https://github.com/Devolutions/IronRDP/commit/5bd319126d32fbd8e505508e27ab2b1a18a83d04)) - - This fixes build issues with some dependencies. - ## [[0.13.0](https://github.com/Devolutions/IronRDP/compare/ironrdp-v0.12.0...ironrdp-v0.13.0)] - 2025-09-24 ### Build diff --git a/crates/ironrdp/Cargo.toml b/crates/ironrdp/Cargo.toml index 25945735..cd7b5850 100644 --- a/crates/ironrdp/Cargo.toml +++ b/crates/ironrdp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ironrdp" -version = "0.14.0" +version = "0.13.0" readme = "README.md" description = "A meta crate re-exporting IronRDP crates for convenience" edition.workspace = true @@ -40,28 +40,28 @@ __bench = ["ironrdp-server/__bench"] [dependencies] ironrdp-core = { path = "../ironrdp-core", version = "0.1", optional = true } # public ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6", optional = true } # public -ironrdp-cliprdr = { path = "../ironrdp-cliprdr", version = "0.5", optional = true } # public -ironrdp-connector = { path = "../ironrdp-connector", version = "0.8", optional = true } # public -ironrdp-acceptor = { path = "../ironrdp-acceptor", version = "0.8", optional = true } # public -ironrdp-session = { path = "../ironrdp-session", version = "0.8", optional = true } # public -ironrdp-graphics = { path = "../ironrdp-graphics", version = "0.7", optional = true } # public +ironrdp-cliprdr = { path = "../ironrdp-cliprdr", version = "0.4", optional = true } # public +ironrdp-connector = { path = "../ironrdp-connector", version = "0.7", optional = true } # public +ironrdp-acceptor = { path = "../ironrdp-acceptor", version = "0.7", optional = true } # public +ironrdp-session = { path = "../ironrdp-session", version = "0.7", optional = true } # public +ironrdp-graphics = { path = "../ironrdp-graphics", version = "0.6", optional = true } # public ironrdp-input = { path = "../ironrdp-input", version = "0.4", optional = true } # public -ironrdp-server = { path = "../ironrdp-server", version = "0.10", optional = true, features = ["helper"] } # public +ironrdp-server = { path = "../ironrdp-server", version = "0.9", optional = true, features = ["helper"] } # public ironrdp-svc = { path = "../ironrdp-svc", version = "0.5", optional = true } # public ironrdp-dvc = { path = "../ironrdp-dvc", version = "0.4", optional = true } # public -ironrdp-rdpdr = { path = "../ironrdp-rdpdr", version = "0.5", optional = true } # public +ironrdp-rdpdr = { path = "../ironrdp-rdpdr", version = "0.4", optional = true } # public ironrdp-rdpsnd = { path = "../ironrdp-rdpsnd", version = "0.6", optional = true } # public ironrdp-displaycontrol = { path = "../ironrdp-displaycontrol", version = "0.4", optional = true } # public [dev-dependencies] -ironrdp-blocking = { path = "../ironrdp-blocking", version = "0.8.0" } -ironrdp-cliprdr-native = { path = "../ironrdp-cliprdr-native", version = "0.5.0" } +ironrdp-blocking = { path = "../ironrdp-blocking", version = "0.7.0" } +ironrdp-cliprdr-native = { path = "../ironrdp-cliprdr-native", version = "0.4.0" } anyhow = "1" async-trait = "0.1" image = { version = "0.25.6", default-features = false, features = ["png"] } pico-args = "0.5" x509-cert = { version = "0.2", default-features = false, features = ["std"] } -sspi = { version = "0.18", features = ["network_client"] } +sspi = { version = "0.16", features = ["network_client"] } tracing = { version = "0.1", features = ["log"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] } tokio-rustls = "0.26" diff --git a/crates/ironrdp/examples/screenshot.rs b/crates/ironrdp/examples/screenshot.rs index 64ff33ac..94144ce6 100644 --- a/crates/ironrdp/examples/screenshot.rs +++ b/crates/ironrdp/examples/screenshot.rs @@ -258,11 +258,11 @@ fn connect( let mut network_client = ReqwestNetworkClient; let connection_result = ironrdp_blocking::connect_finalize( upgraded, - connector, &mut upgraded_framed, - &mut network_client, + connector, server_name.into(), server_public_key, + &mut network_client, None, ) .context("finalize connection")?; diff --git a/crates/ironrdp/examples/server.rs b/crates/ironrdp/examples/server.rs index 94e4a9ac..35e8175d 100644 --- a/crates/ironrdp/examples/server.rs +++ b/crates/ironrdp/examples/server.rs @@ -364,23 +364,19 @@ fn generate_sine_wave(sample_rate: u32, frequency: f32, duration_ms: u64, phase: use core::f32::consts::PI; let total_samples = (u64::from(sample_rate) * duration_ms) / 1000; - - #[expect(clippy::as_conversions)] let delta_phase = 2.0 * PI * frequency / sample_rate as f32; - let amplitude = 32767.0; // Max amplitude for 16-bit audio - let capacity = usize::try_from(total_samples).expect("u64-to-usize") * 2; // 2 channels + let capacity = (total_samples as usize) * 2; // 2 channels let mut samples = Vec::with_capacity(capacity); for _ in 0..total_samples { let sample = (*phase).sin(); *phase += delta_phase; - - // Wrap phase to maintain precision and avoid overflow. + // Wrap phase to maintain precision and avoid overflow *phase %= 2.0 * PI; - #[expect(clippy::as_conversions, clippy::cast_possible_truncation)] + #[expect(clippy::cast_possible_truncation)] let sample_i16 = (sample * amplitude) as i16; // Write same sample to both channels (stereo) diff --git a/ffi/Cargo.toml b/ffi/Cargo.toml index 574b77d3..30d98d3d 100644 --- a/ffi/Cargo.toml +++ b/ffi/Cargo.toml @@ -18,12 +18,10 @@ ironrdp = { path = "../crates/ironrdp", features = ["session", "connector", "dvc ironrdp-cliprdr-native.path = "../crates/ironrdp-cliprdr-native" ironrdp-dvc-pipe-proxy.path = "../crates/ironrdp-dvc-pipe-proxy" ironrdp-core = { path = "../crates/ironrdp-core", features = ["alloc"] } -ironrdp-rdcleanpath.path = "../crates/ironrdp-rdcleanpath" -sspi = { version = "0.18", features = ["network_client"] } +sspi = { version = "0.16", features = ["network_client"] } thiserror = "2" tracing = { version = "0.1", features = ["log"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] } -anyhow = "1.0" [target.'cfg(windows)'.build-dependencies] embed-resource = "3.0" diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Devolutions.IronRdp.AvaloniaExample.csproj b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Devolutions.IronRdp.AvaloniaExample.csproj index 802b8ad7..e29164c4 100644 --- a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Devolutions.IronRdp.AvaloniaExample.csproj +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/Devolutions.IronRdp.AvaloniaExample.csproj @@ -10,18 +10,18 @@ - - - - + + + + - + - + diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/MainWindow.axaml.cs b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/MainWindow.axaml.cs index 4ab8ef3f..34148527 100644 --- a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/MainWindow.axaml.cs +++ b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/MainWindow.axaml.cs @@ -7,7 +7,6 @@ using Avalonia.Threading; using System; using System.ComponentModel; using System.Diagnostics; -using System.IO; using System.Net.Security; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -23,7 +22,7 @@ public partial class MainWindow : Window readonly InputDatabase? _inputDatabase = InputDatabase.New(); ActiveStage? _activeStage; DecodedImage? _decodedImage; - Framed? _framed; + Framed? _framed; WinCliprdr? _cliprdr; private readonly RendererModel _renderModel; private Image? _imageControl; @@ -78,49 +77,18 @@ public partial class MainWindow : Window var username = Environment.GetEnvironmentVariable("IRONRDP_USERNAME"); var password = Environment.GetEnvironmentVariable("IRONRDP_PASSWORD"); - var domain = Environment.GetEnvironmentVariable("IRONRDP_DOMAIN"); // Optional + var domain = Environment.GetEnvironmentVariable("IRONRDP_DOMAIN"); var server = Environment.GetEnvironmentVariable("IRONRDP_SERVER"); - var portEnv = Environment.GetEnvironmentVariable("IRONRDP_PORT"); // Optional - // Gateway configuration (optional) - var gatewayUrl = Environment.GetEnvironmentVariable("IRONRDP_GATEWAY_URL"); - var gatewayToken = Environment.GetEnvironmentVariable("IRONRDP_GATEWAY_TOKEN"); - var tokengenUrl = Environment.GetEnvironmentVariable("IRONRDP_TOKENGEN_URL"); - - if (username == null || password == null || server == null) + if (username == null || password == null || domain == null || server == null) { var errorMessage = - "Please set the IRONRDP_USERNAME, IRONRDP_PASSWORD, and IRONRDP_SERVER environment variables"; + "Please set the IRONRDP_USERNAME, IRONRDP_PASSWORD, IRONRDP_DOMAIN, and RONRDP_SERVER environment variables"; Trace.TraceError(errorMessage); Close(); throw new InvalidProgramException(errorMessage); } - // Validate server is only domain or IP (no port allowed) - // i.e. "example.com" or "10.10.0.3" the port should go to the dedicated env var IRONRDP_PORT - if (server.Contains(':')) - { - var errorMessage = $"IRONRDP_SERVER must be a domain or IP address only, not '{server}'. Use IRONRDP_PORT for the port."; - Trace.TraceError(errorMessage); - Close(); - throw new InvalidProgramException(errorMessage); - } - - // Parse port from environment variable or use default - int port = 3389; - if (!string.IsNullOrEmpty(portEnv)) - { - if (!int.TryParse(portEnv, out port) || port <= 0 || port > 65535) - { - var errorMessage = $"IRONRDP_PORT must be a valid port number (1-65535), got '{portEnv}'"; - Trace.TraceError(errorMessage); - Close(); - throw new InvalidProgramException(errorMessage); - } - } - - Trace.TraceInformation($"Target server: {server}:{port}"); - var config = BuildConfig(username, password, domain, _renderModel.Width, _renderModel.Height); CliprdrBackendFactory? factory = null; @@ -138,81 +106,15 @@ public partial class MainWindow : Window BeforeConnectSetup(); Task.Run(async () => { - try + var (res, framed) = await Connection.Connect(config, server, factory); + this._decodedImage = DecodedImage.New(PixelFormat.RgbA32, res.GetDesktopSize().GetWidth(), + res.GetDesktopSize().GetHeight()); + this._activeStage = ActiveStage.New(res); + this._framed = framed; + ReadPduAndProcessActiveStage(); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - ConnectionResult res; - - // Determine connection mode: Gateway or Direct - if (!string.IsNullOrEmpty(gatewayUrl)) - { - Trace.TraceInformation("=== GATEWAY MODE ==="); - Trace.TraceInformation($"Gateway URL: {gatewayUrl}"); - Trace.TraceInformation($"Destination: {server}:{port}"); - - var tokenGen = new TokenGenerator(tokengenUrl ?? "http://localhost:8080"); - - // Generate RDP token if not provided - if (string.IsNullOrEmpty(gatewayToken)) - { - Trace.TraceInformation("No RDP token provided, generating token..."); - - try - { - gatewayToken = await tokenGen.GenerateRdpTlsToken( - dstHost: server!, - proxyUser: string.IsNullOrEmpty(domain) ? username : $"{username}@{domain}", - proxyPassword: password!, - destUser: username!, - destPassword: password! - ); - Trace.TraceInformation($"RDP token generated successfully (length: {gatewayToken.Length})"); - } - catch (Exception ex) - { - Trace.TraceError($"Failed to generate RDP token: {ex.Message}"); - Trace.TraceInformation("Make sure tokengen server is running:"); - Trace.TraceInformation($" cargo run --manifest-path tools/tokengen/Cargo.toml -- server"); - throw; - } - } - - // Connect via gateway - destination needs "hostname:port" format for RDCleanPath - string destination = $"{server}:{port}"; - - var (gatewayRes, gatewayFramed) = await RDCleanPathConnection.ConnectRDCleanPath( - config, gatewayUrl, gatewayToken!, destination, null, factory); - res = gatewayRes; - this._framed = new Framed(gatewayFramed.GetInner().Item1); - - Trace.TraceInformation("=== GATEWAY CONNECTION SUCCESSFUL ==="); - } - else - { - Trace.TraceInformation("=== DIRECT MODE ==="); - - // Direct connection (original behavior) - var (directRes, directFramed) = await Connection.Connect(config, server, factory, port); - res = directRes; - this._framed = new Framed(directFramed.GetInner().Item1); - - Trace.TraceInformation("=== DIRECT CONNECTION SUCCESSFUL ==="); - } - - this._decodedImage = DecodedImage.New(PixelFormat.RgbA32, res.GetDesktopSize().GetWidth(), - res.GetDesktopSize().GetHeight()); - this._activeStage = ActiveStage.New(res); - ReadPduAndProcessActiveStage(); - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - HandleClipboardEvents(); - } - } - catch (Exception ex) - { - Trace.TraceError($"Connection failed: {ex.Message}"); - Trace.TraceError($"Stack trace: {ex.StackTrace}"); - throw; + HandleClipboardEvents(); } }); } @@ -358,16 +260,12 @@ public partial class MainWindow : Window }); } - private static Config BuildConfig(string username, string password, string? domain, int width, int height) + private static Config BuildConfig(string username, string password, string domain, int width, int height) { ConfigBuilder configBuilder = ConfigBuilder.New(); configBuilder.WithUsernameAndPassword(username, password); - if (domain != null) - { - configBuilder.SetDomain(domain); - } - + configBuilder.SetDomain(domain); configBuilder.SetDesktopSize((ushort)height, (ushort)width); configBuilder.SetClientName("IronRdp"); configBuilder.SetClientDir("C:\\"); @@ -520,7 +418,7 @@ public partial class MainWindow : Window var writeBuf = WriteBuf.New(); while (true) { - await Connection.SingleSequenceStep(activationSequence, writeBuf, _framed!); + await Connection.SingleSequenceStep(activationSequence, writeBuf,_framed!); if (activationSequence.GetState().GetType() != ConnectionActivationStateType.Finalized) continue; diff --git a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/TokenGenerator.cs b/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/TokenGenerator.cs deleted file mode 100644 index 00946c60..00000000 --- a/ffi/dotnet/Devolutions.IronRdp.AvaloniaExample/TokenGenerator.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System; -using System.Net.Http; -using System.Net.Http.Json; -using System.Text.Json.Serialization; -using System.Threading.Tasks; - -namespace Devolutions.IronRdp.AvaloniaExample; - -/// -/// Client for requesting JWT tokens from a Devolutions Gateway tokengen server. -/// -public class TokenGenerator : IDisposable -{ - private readonly HttpClient _client; - private readonly string _tokengenUrl; - - /// - /// Creates a new TokenGenerator instance. - /// - /// The base URL of the tokengen server (e.g., "http://localhost:8080") - public TokenGenerator(string tokengenUrl = "http://localhost:8080") - { - _tokengenUrl = tokengenUrl; - _client = new HttpClient - { - Timeout = TimeSpan.FromSeconds(30) - }; - } - - /// - /// Generates an RDP token with credential injection for gateway-based connections. - /// - /// Destination RDP server (e.g., "10.10.0.3:3389") - /// Gateway proxy username - /// Gateway proxy password - /// Destination RDP server username - /// Destination RDP server password - /// Optional session UUID - /// Token validity in seconds (default: 3600) - /// A JWT token string - public async Task GenerateRdpTlsToken( - string dstHost, - string proxyUser, - string proxyPassword, - string destUser, - string destPassword, - string? jetAid = null, - int validityDuration = 3600) - { - var request = new RdpTlsTokenRequest - { - DstHst = dstHost, - PrxUsr = proxyUser, - PrxPwd = proxyPassword, - DstUsr = destUser, - DstPwd = destPassword, - JetAid = jetAid, - ValidityDuration = validityDuration - }; - - try - { - var response = await _client.PostAsJsonAsync($"{_tokengenUrl}/rdp_tls", request); - response.EnsureSuccessStatusCode(); - - var result = await response.Content.ReadFromJsonAsync(); - if (result?.Token == null) - { - throw new Exception("Token generation failed: Empty response"); - } - - return result.Token; - } - catch (HttpRequestException ex) - { - throw new Exception($"Failed to connect to tokengen server at {_tokengenUrl}: {ex.Message}", ex); - } - catch (TaskCanceledException ex) - { - throw new Exception($"Token generation request timed out: {ex.Message}", ex); - } - } - - /// - /// Generates a forward mode token for simple RDP forwarding without credential injection. - /// - /// Destination host - /// Application protocol (default: "rdp") - /// Enable recording - /// Token validity in seconds (default: 3600) - /// A JWT token string - public async Task GenerateForwardToken( - string dstHost, - string jetAp = "rdp", - bool jetRec = false, - int validityDuration = 3600) - { - var request = new ForwardTokenRequest - { - DstHst = dstHost, - JetAp = jetAp, - JetRec = jetRec, - ValidityDuration = validityDuration - }; - - try - { - var response = await _client.PostAsJsonAsync($"{_tokengenUrl}/forward", request); - response.EnsureSuccessStatusCode(); - - var result = await response.Content.ReadFromJsonAsync(); - if (result?.Token == null) - { - throw new Exception("Token generation failed: Empty response"); - } - - return result.Token; - } - catch (HttpRequestException ex) - { - throw new Exception($"Failed to connect to tokengen server at {_tokengenUrl}: {ex.Message}", ex); - } - } - - /// - /// Checks if the tokengen server is reachable. - /// - /// True if server is reachable, false otherwise - public async Task IsServerReachable() - { - try - { - var response = await _client.GetAsync(_tokengenUrl); - return response.IsSuccessStatusCode || response.StatusCode == System.Net.HttpStatusCode.NotFound; - } - catch - { - return false; - } - } - - public void Dispose() - { - _client?.Dispose(); - } - - // Request/Response DTOs - private class RdpTlsTokenRequest - { - [JsonPropertyName("dst_hst")] - public string DstHst { get; set; } = string.Empty; - - [JsonPropertyName("prx_usr")] - public string PrxUsr { get; set; } = string.Empty; - - [JsonPropertyName("prx_pwd")] - public string PrxPwd { get; set; } = string.Empty; - - [JsonPropertyName("dst_usr")] - public string DstUsr { get; set; } = string.Empty; - - [JsonPropertyName("dst_pwd")] - public string DstPwd { get; set; } = string.Empty; - - [JsonPropertyName("jet_aid")] - public string? JetAid { get; set; } - - [JsonPropertyName("validity_duration")] - public int ValidityDuration { get; set; } - } - - private class ForwardTokenRequest - { - [JsonPropertyName("dst_hst")] - public string DstHst { get; set; } = string.Empty; - - [JsonPropertyName("jet_ap")] - public string JetAp { get; set; } = "rdp"; - - [JsonPropertyName("jet_rec")] - public bool JetRec { get; set; } - - [JsonPropertyName("validity_duration")] - public int ValidityDuration { get; set; } - } - - private class TokenResponse - { - [JsonPropertyName("token")] - public string? Token { get; set; } - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Devolutions.IronRdp.ConnectExample.csproj b/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Devolutions.IronRdp.ConnectExample.csproj index 61014ed1..1ef474af 100644 --- a/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Devolutions.IronRdp.ConnectExample.csproj +++ b/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Devolutions.IronRdp.ConnectExample.csproj @@ -16,7 +16,7 @@ https://learn.microsoft.com/en-us/dotnet/api/system.drawing?view=net-8.0 --> - + diff --git a/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Program.cs b/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Program.cs index 3c85f258..b685455c 100644 --- a/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Program.cs +++ b/ffi/dotnet/Devolutions.IronRdp.ConnectExample/Program.cs @@ -23,7 +23,7 @@ namespace Devolutions.IronRdp.ConnectExample try { - var (res, framed) = await Connection.Connect(buildConfig(username, password, domain, 1980, 1080), serverName, null); + var (res, framed) = await Connection.Connect(buildConfig(serverName, username, password, domain, 1980, 1080), serverName, null); var decodedImage = DecodedImage.New(PixelFormat.RgbA32, res.GetDesktopSize().GetWidth(), res.GetDesktopSize().GetHeight()); var activeState = ActiveStage.New(res); var keepLooping = true; @@ -175,7 +175,7 @@ namespace Devolutions.IronRdp.ConnectExample Console.WriteLine(" --help Show this message and exit."); } - private static Config buildConfig(string username, string password, string domain, int width, int height) + private static Config buildConfig(string servername, string username, string password, string domain, int width, int height) { ConfigBuilder configBuilder = ConfigBuilder.New(); diff --git a/ffi/dotnet/Devolutions.IronRdp/Devolutions.IronRdp.Build.iOS.props b/ffi/dotnet/Devolutions.IronRdp/Devolutions.IronRdp.Build.iOS.props index b692fdbb..af8d97cc 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Devolutions.IronRdp.Build.iOS.props +++ b/ffi/dotnet/Devolutions.IronRdp/Devolutions.IronRdp.Build.iOS.props @@ -1,6 +1,6 @@ - net9.0-ios + net8.0-ios 12.1 diff --git a/ffi/dotnet/Devolutions.IronRdp/Devolutions.IronRdp.csproj b/ffi/dotnet/Devolutions.IronRdp/Devolutions.IronRdp.csproj index 38fc2e65..00ba0ce5 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Devolutions.IronRdp.csproj +++ b/ffi/dotnet/Devolutions.IronRdp/Devolutions.IronRdp.csproj @@ -4,7 +4,7 @@ Devolutions Bindings to Rust IronRDP native library latest - 2025.12.4.0 + 2024.10.9.0 enable enable true diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/CertificateChainIterator.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/CertificateChainIterator.cs deleted file mode 100644 index 9830d732..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/CertificateChainIterator.cs +++ /dev/null @@ -1,109 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp; - -#nullable enable - -public partial class CertificateChainIterator: IDisposable -{ - private unsafe Raw.CertificateChainIterator* _inner; - - /// - /// Creates a managed CertificateChainIterator from a raw handle. - /// - /// - /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). - ///
- /// This constructor assumes the raw struct is allocated on Rust side. - /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. - ///
- public unsafe CertificateChainIterator(Raw.CertificateChainIterator* handle) - { - _inner = handle; - } - - /// - /// A VecU8 allocated on Rust side. - /// - public VecU8? Next() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("CertificateChainIterator"); - } - Raw.VecU8* retVal = Raw.CertificateChainIterator.Next(_inner); - if (retVal == null) - { - return null; - } - return new VecU8(retVal); - } - } - - public nuint Len() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("CertificateChainIterator"); - } - nuint retVal = Raw.CertificateChainIterator.Len(_inner); - return retVal; - } - } - - public bool IsEmpty() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("CertificateChainIterator"); - } - bool retVal = Raw.CertificateChainIterator.IsEmpty(_inner); - return retVal; - } - } - - /// - /// Returns the underlying raw handle. - /// - public unsafe Raw.CertificateChainIterator* AsFFI() - { - return _inner; - } - - /// - /// Destroys the underlying object immediately. - /// - public void Dispose() - { - unsafe - { - if (_inner == null) - { - return; - } - - Raw.CertificateChainIterator.Destroy(_inner); - _inner = null; - - GC.SuppressFinalize(this); - } - } - - ~CertificateChainIterator() - { - Dispose(); - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/Log.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/Log.cs index c0e3af52..ec2769f3 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/Log.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/Log.cs @@ -29,13 +29,6 @@ public partial class Log: IDisposable _inner = handle; } - /// - /// # Panics - /// - /// - /// - Panics if log directory creation fails. - /// - Panics if tracing initialization fails. - /// public static void InitWithEnv() { unsafe diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RDCleanPathDetectionResult.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RDCleanPathDetectionResult.cs deleted file mode 100644 index 644c997e..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RDCleanPathDetectionResult.cs +++ /dev/null @@ -1,129 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp; - -#nullable enable - -public partial class RDCleanPathDetectionResult: IDisposable -{ - private unsafe Raw.RDCleanPathDetectionResult* _inner; - - public nuint TotalLength - { - get - { - return GetTotalLength(); - } - } - - /// - /// Creates a managed RDCleanPathDetectionResult from a raw handle. - /// - /// - /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). - ///
- /// This constructor assumes the raw struct is allocated on Rust side. - /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. - ///
- public unsafe RDCleanPathDetectionResult(Raw.RDCleanPathDetectionResult* handle) - { - _inner = handle; - } - - public bool IsDetected() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathDetectionResult"); - } - bool retVal = Raw.RDCleanPathDetectionResult.IsDetected(_inner); - return retVal; - } - } - - public bool IsNotEnoughBytes() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathDetectionResult"); - } - bool retVal = Raw.RDCleanPathDetectionResult.IsNotEnoughBytes(_inner); - return retVal; - } - } - - public bool IsFailed() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathDetectionResult"); - } - bool retVal = Raw.RDCleanPathDetectionResult.IsFailed(_inner); - return retVal; - } - } - - /// - public nuint GetTotalLength() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathDetectionResult"); - } - Raw.RdcleanpathFfiResultUsizeBoxIronRdpError result = Raw.RDCleanPathDetectionResult.GetTotalLength(_inner); - if (!result.isOk) - { - throw new IronRdpException(new IronRdpError(result.Err)); - } - nuint retVal = result.Ok; - return retVal; - } - } - - /// - /// Returns the underlying raw handle. - /// - public unsafe Raw.RDCleanPathDetectionResult* AsFFI() - { - return _inner; - } - - /// - /// Destroys the underlying object immediately. - /// - public void Dispose() - { - unsafe - { - if (_inner == null) - { - return; - } - - Raw.RDCleanPathDetectionResult.Destroy(_inner); - _inner = null; - - GC.SuppressFinalize(this); - } - } - - ~RDCleanPathDetectionResult() - { - Dispose(); - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RDCleanPathPdu.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RDCleanPathPdu.cs deleted file mode 100644 index b4c5d627..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RDCleanPathPdu.cs +++ /dev/null @@ -1,424 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp; - -#nullable enable - -public partial class RDCleanPathPdu: IDisposable -{ - private unsafe Raw.RDCleanPathPdu* _inner; - - public ushort ErrorCode - { - get - { - return GetErrorCode(); - } - } - - public string ErrorMessage - { - get - { - return GetErrorMessage(); - } - } - - public ushort HttpStatusCode - { - get - { - return GetHttpStatusCode(); - } - } - - public string ServerAddr - { - get - { - return GetServerAddr(); - } - } - - public CertificateChainIterator ServerCertChain - { - get - { - return GetServerCertChain(); - } - } - - public RDCleanPathResultType Type - { - get - { - return GetType(); - } - } - - public VecU8 X224Response - { - get - { - return GetX224Response(); - } - } - - /// - /// Creates a managed RDCleanPathPdu from a raw handle. - /// - /// - /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). - ///
- /// This constructor assumes the raw struct is allocated on Rust side. - /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. - ///
- public unsafe RDCleanPathPdu(Raw.RDCleanPathPdu* handle) - { - _inner = handle; - } - - /// - /// Creates a new RDCleanPath request PDU - /// - /// - /// # Arguments - /// * `x224_pdu` - The X.224 Connection Request PDU bytes - /// * `destination` - The destination RDP server address (e.g., "10.10.0.3:3389") - /// * `proxy_auth` - The JWT authentication token - /// * `pcb` - Optional preconnection blob (for Hyper-V VM connections, empty string if not needed) - /// - /// - /// - /// A RDCleanPathPdu allocated on Rust side. - /// - public static RDCleanPathPdu NewRequest(byte[] x224Pdu, string destination, string proxyAuth, string pcb) - { - unsafe - { - byte[] destinationBuf = DiplomatUtils.StringToUtf8(destination); - byte[] proxyAuthBuf = DiplomatUtils.StringToUtf8(proxyAuth); - byte[] pcbBuf = DiplomatUtils.StringToUtf8(pcb); - nuint x224PduLength = (nuint)x224Pdu.Length; - nuint destinationBufLength = (nuint)destinationBuf.Length; - nuint proxyAuthBufLength = (nuint)proxyAuthBuf.Length; - nuint pcbBufLength = (nuint)pcbBuf.Length; - fixed (byte* x224PduPtr = x224Pdu) - { - fixed (byte* destinationBufPtr = destinationBuf) - { - fixed (byte* proxyAuthBufPtr = proxyAuthBuf) - { - fixed (byte* pcbBufPtr = pcbBuf) - { - Raw.RdcleanpathFfiResultBoxRDCleanPathPduBoxIronRdpError result = Raw.RDCleanPathPdu.NewRequest(x224PduPtr, x224PduLength, destinationBufPtr, destinationBufLength, proxyAuthBufPtr, proxyAuthBufLength, pcbBufPtr, pcbBufLength); - if (!result.isOk) - { - throw new IronRdpException(new IronRdpError(result.Err)); - } - Raw.RDCleanPathPdu* retVal = result.Ok; - return new RDCleanPathPdu(retVal); - } - } - } - } - } - } - - /// - /// Decodes a RDCleanPath PDU from DER-encoded bytes - /// - /// - /// - /// A RDCleanPathPdu allocated on Rust side. - /// - public static RDCleanPathPdu FromDer(byte[] bytes) - { - unsafe - { - nuint bytesLength = (nuint)bytes.Length; - fixed (byte* bytesPtr = bytes) - { - Raw.RdcleanpathFfiResultBoxRDCleanPathPduBoxIronRdpError result = Raw.RDCleanPathPdu.FromDer(bytesPtr, bytesLength); - if (!result.isOk) - { - throw new IronRdpException(new IronRdpError(result.Err)); - } - Raw.RDCleanPathPdu* retVal = result.Ok; - return new RDCleanPathPdu(retVal); - } - } - } - - /// - /// Encodes the RDCleanPath PDU to DER-encoded bytes - /// - /// - /// - /// A VecU8 allocated on Rust side. - /// - public VecU8 ToDer() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathPdu"); - } - Raw.RdcleanpathFfiResultBoxVecU8BoxIronRdpError result = Raw.RDCleanPathPdu.ToDer(_inner); - if (!result.isOk) - { - throw new IronRdpException(new IronRdpError(result.Err)); - } - Raw.VecU8* retVal = result.Ok; - return new VecU8(retVal); - } - } - - /// - /// Detects if the bytes contain a valid RDCleanPath PDU and returns detection result - /// - /// - /// A RDCleanPathDetectionResult allocated on Rust side. - /// - public static RDCleanPathDetectionResult Detect(byte[] bytes) - { - unsafe - { - nuint bytesLength = (nuint)bytes.Length; - fixed (byte* bytesPtr = bytes) - { - Raw.RDCleanPathDetectionResult* retVal = Raw.RDCleanPathPdu.Detect(bytesPtr, bytesLength); - return new RDCleanPathDetectionResult(retVal); - } - } - } - - /// - /// Gets the type of this RDCleanPath PDU - /// - /// - /// - /// A RDCleanPathResultType allocated on C# side. - /// - public RDCleanPathResultType GetType() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathPdu"); - } - Raw.RdcleanpathFfiResultRDCleanPathResultTypeBoxIronRdpError result = Raw.RDCleanPathPdu.GetType(_inner); - if (!result.isOk) - { - throw new IronRdpException(new IronRdpError(result.Err)); - } - Raw.RDCleanPathResultType retVal = result.Ok; - return (RDCleanPathResultType)retVal; - } - } - - /// - /// Gets the X.224 connection response bytes (for Response or NegotiationError variants) - /// - /// - /// - /// A VecU8 allocated on Rust side. - /// - public VecU8 GetX224Response() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathPdu"); - } - Raw.RdcleanpathFfiResultBoxVecU8BoxIronRdpError result = Raw.RDCleanPathPdu.GetX224Response(_inner); - if (!result.isOk) - { - throw new IronRdpException(new IronRdpError(result.Err)); - } - Raw.VecU8* retVal = result.Ok; - return new VecU8(retVal); - } - } - - /// - /// Gets the server certificate chain (for Response variant) - /// Returns a vector iterator of certificate bytes - /// - /// - /// - /// A CertificateChainIterator allocated on Rust side. - /// - public CertificateChainIterator GetServerCertChain() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathPdu"); - } - Raw.RdcleanpathFfiResultBoxCertificateChainIteratorBoxIronRdpError result = Raw.RDCleanPathPdu.GetServerCertChain(_inner); - if (!result.isOk) - { - throw new IronRdpException(new IronRdpError(result.Err)); - } - Raw.CertificateChainIterator* retVal = result.Ok; - return new CertificateChainIterator(retVal); - } - } - - /// - /// Gets the server address string (for Response variant) - /// - public void GetServerAddr(DiplomatWriteable writeable) - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathPdu"); - } - Raw.RDCleanPathPdu.GetServerAddr(_inner, &writeable); - } - } - - /// - /// Gets the server address string (for Response variant) - /// - public string GetServerAddr() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathPdu"); - } - DiplomatWriteable writeable = new DiplomatWriteable(); - Raw.RDCleanPathPdu.GetServerAddr(_inner, &writeable); - string retVal = writeable.ToUnicode(); - writeable.Dispose(); - return retVal; - } - } - - /// - /// Gets error message (for GeneralError variant) - /// - public void GetErrorMessage(DiplomatWriteable writeable) - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathPdu"); - } - Raw.RDCleanPathPdu.GetErrorMessage(_inner, &writeable); - } - } - - /// - /// Gets error message (for GeneralError variant) - /// - public string GetErrorMessage() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathPdu"); - } - DiplomatWriteable writeable = new DiplomatWriteable(); - Raw.RDCleanPathPdu.GetErrorMessage(_inner, &writeable); - string retVal = writeable.ToUnicode(); - writeable.Dispose(); - return retVal; - } - } - - /// - /// Gets the error code (for GeneralError variant) - /// - /// - public ushort GetErrorCode() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathPdu"); - } - Raw.RdcleanpathFfiResultU16BoxIronRdpError result = Raw.RDCleanPathPdu.GetErrorCode(_inner); - if (!result.isOk) - { - throw new IronRdpException(new IronRdpError(result.Err)); - } - ushort retVal = result.Ok; - return retVal; - } - } - - /// - /// Gets the HTTP status code if present (for GeneralError variant) - /// Returns error if not present or not a GeneralError variant - /// - /// - public ushort GetHttpStatusCode() - { - unsafe - { - if (_inner == null) - { - throw new ObjectDisposedException("RDCleanPathPdu"); - } - Raw.RdcleanpathFfiResultU16BoxIronRdpError result = Raw.RDCleanPathPdu.GetHttpStatusCode(_inner); - if (!result.isOk) - { - throw new IronRdpException(new IronRdpError(result.Err)); - } - ushort retVal = result.Ok; - return retVal; - } - } - - /// - /// Returns the underlying raw handle. - /// - public unsafe Raw.RDCleanPathPdu* AsFFI() - { - return _inner; - } - - /// - /// Destroys the underlying object immediately. - /// - public void Dispose() - { - unsafe - { - if (_inner == null) - { - return; - } - - Raw.RDCleanPathPdu.Destroy(_inner); - _inner = null; - - GC.SuppressFinalize(this); - } - } - - ~RDCleanPathPdu() - { - Dispose(); - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RDCleanPathResultType.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RDCleanPathResultType.cs deleted file mode 100644 index 4145574e..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RDCleanPathResultType.cs +++ /dev/null @@ -1,20 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp; - -#nullable enable - -public enum RDCleanPathResultType -{ - Request = 0, - Response = 1, - GeneralError = 2, - NegotiationError = 3, -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawCertificateChainIterator.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawCertificateChainIterator.cs deleted file mode 100644 index c451aa99..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawCertificateChainIterator.cs +++ /dev/null @@ -1,31 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp.Raw; - -#nullable enable - -[StructLayout(LayoutKind.Sequential)] -public partial struct CertificateChainIterator -{ - private const string NativeLib = "DevolutionsIronRdp"; - - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "CertificateChainIterator_next", ExactSpelling = true)] - public static unsafe extern VecU8* Next(CertificateChainIterator* self); - - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "CertificateChainIterator_len", ExactSpelling = true)] - public static unsafe extern nuint Len(CertificateChainIterator* self); - - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "CertificateChainIterator_is_empty", ExactSpelling = true)] - [return: MarshalAs(UnmanagedType.U1)] - public static unsafe extern bool IsEmpty(CertificateChainIterator* self); - - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "CertificateChainIterator_destroy", ExactSpelling = true)] - public static unsafe extern void Destroy(CertificateChainIterator* self); -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawLog.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawLog.cs index 40482702..e1f649b9 100644 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawLog.cs +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawLog.cs @@ -16,13 +16,6 @@ public partial struct Log { private const string NativeLib = "DevolutionsIronRdp"; - /// - /// # Panics - /// - /// - /// - Panics if log directory creation fails. - /// - Panics if tracing initialization fails. - /// [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Log_init_with_env", ExactSpelling = true)] public static unsafe extern void InitWithEnv(); diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRDCleanPathDetectionResult.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRDCleanPathDetectionResult.cs deleted file mode 100644 index a5f7d88d..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRDCleanPathDetectionResult.cs +++ /dev/null @@ -1,36 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp.Raw; - -#nullable enable - -[StructLayout(LayoutKind.Sequential)] -public partial struct RDCleanPathDetectionResult -{ - private const string NativeLib = "DevolutionsIronRdp"; - - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathDetectionResult_is_detected", ExactSpelling = true)] - [return: MarshalAs(UnmanagedType.U1)] - public static unsafe extern bool IsDetected(RDCleanPathDetectionResult* self); - - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathDetectionResult_is_not_enough_bytes", ExactSpelling = true)] - [return: MarshalAs(UnmanagedType.U1)] - public static unsafe extern bool IsNotEnoughBytes(RDCleanPathDetectionResult* self); - - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathDetectionResult_is_failed", ExactSpelling = true)] - [return: MarshalAs(UnmanagedType.U1)] - public static unsafe extern bool IsFailed(RDCleanPathDetectionResult* self); - - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathDetectionResult_get_total_length", ExactSpelling = true)] - public static unsafe extern RdcleanpathFfiResultUsizeBoxIronRdpError GetTotalLength(RDCleanPathDetectionResult* self); - - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathDetectionResult_destroy", ExactSpelling = true)] - public static unsafe extern void Destroy(RDCleanPathDetectionResult* self); -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRDCleanPathPdu.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRDCleanPathPdu.cs deleted file mode 100644 index 5710356a..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRDCleanPathPdu.cs +++ /dev/null @@ -1,96 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp.Raw; - -#nullable enable - -[StructLayout(LayoutKind.Sequential)] -public partial struct RDCleanPathPdu -{ - private const string NativeLib = "DevolutionsIronRdp"; - - /// - /// Creates a new RDCleanPath request PDU - /// - /// - /// # Arguments - /// * `x224_pdu` - The X.224 Connection Request PDU bytes - /// * `destination` - The destination RDP server address (e.g., "10.10.0.3:3389") - /// * `proxy_auth` - The JWT authentication token - /// * `pcb` - Optional preconnection blob (for Hyper-V VM connections, empty string if not needed) - /// - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_new_request", ExactSpelling = true)] - public static unsafe extern RdcleanpathFfiResultBoxRDCleanPathPduBoxIronRdpError NewRequest(byte* x224Pdu, nuint x224PduSz, byte* destination, nuint destinationSz, byte* proxyAuth, nuint proxyAuthSz, byte* pcb, nuint pcbSz); - - /// - /// Decodes a RDCleanPath PDU from DER-encoded bytes - /// - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_from_der", ExactSpelling = true)] - public static unsafe extern RdcleanpathFfiResultBoxRDCleanPathPduBoxIronRdpError FromDer(byte* bytes, nuint bytesSz); - - /// - /// Encodes the RDCleanPath PDU to DER-encoded bytes - /// - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_to_der", ExactSpelling = true)] - public static unsafe extern RdcleanpathFfiResultBoxVecU8BoxIronRdpError ToDer(RDCleanPathPdu* self); - - /// - /// Detects if the bytes contain a valid RDCleanPath PDU and returns detection result - /// - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_detect", ExactSpelling = true)] - public static unsafe extern RDCleanPathDetectionResult* Detect(byte* bytes, nuint bytesSz); - - /// - /// Gets the type of this RDCleanPath PDU - /// - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_get_type", ExactSpelling = true)] - public static unsafe extern RdcleanpathFfiResultRDCleanPathResultTypeBoxIronRdpError GetType(RDCleanPathPdu* self); - - /// - /// Gets the X.224 connection response bytes (for Response or NegotiationError variants) - /// - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_get_x224_response", ExactSpelling = true)] - public static unsafe extern RdcleanpathFfiResultBoxVecU8BoxIronRdpError GetX224Response(RDCleanPathPdu* self); - - /// - /// Gets the server certificate chain (for Response variant) - /// Returns a vector iterator of certificate bytes - /// - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_get_server_cert_chain", ExactSpelling = true)] - public static unsafe extern RdcleanpathFfiResultBoxCertificateChainIteratorBoxIronRdpError GetServerCertChain(RDCleanPathPdu* self); - - /// - /// Gets the server address string (for Response variant) - /// - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_get_server_addr", ExactSpelling = true)] - public static unsafe extern void GetServerAddr(RDCleanPathPdu* self, DiplomatWriteable* writeable); - - /// - /// Gets error message (for GeneralError variant) - /// - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_get_error_message", ExactSpelling = true)] - public static unsafe extern void GetErrorMessage(RDCleanPathPdu* self, DiplomatWriteable* writeable); - - /// - /// Gets the error code (for GeneralError variant) - /// - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_get_error_code", ExactSpelling = true)] - public static unsafe extern RdcleanpathFfiResultU16BoxIronRdpError GetErrorCode(RDCleanPathPdu* self); - - /// - /// Gets the HTTP status code if present (for GeneralError variant) - /// Returns error if not present or not a GeneralError variant - /// - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_get_http_status_code", ExactSpelling = true)] - public static unsafe extern RdcleanpathFfiResultU16BoxIronRdpError GetHttpStatusCode(RDCleanPathPdu* self); - - [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RDCleanPathPdu_destroy", ExactSpelling = true)] - public static unsafe extern void Destroy(RDCleanPathPdu* self); -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRDCleanPathResultType.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRDCleanPathResultType.cs deleted file mode 100644 index 393d6509..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRDCleanPathResultType.cs +++ /dev/null @@ -1,20 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp.Raw; - -#nullable enable - -public enum RDCleanPathResultType -{ - Request = 0, - Response = 1, - GeneralError = 2, - NegotiationError = 3, -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxCertificateChainIteratorBoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxCertificateChainIteratorBoxIronRdpError.cs deleted file mode 100644 index 01cb3590..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxCertificateChainIteratorBoxIronRdpError.cs +++ /dev/null @@ -1,46 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp.Raw; - -#nullable enable - -[StructLayout(LayoutKind.Sequential)] -public partial struct RdcleanpathFfiResultBoxCertificateChainIteratorBoxIronRdpError -{ - [StructLayout(LayoutKind.Explicit)] - private unsafe struct InnerUnion - { - [FieldOffset(0)] - internal CertificateChainIterator* ok; - [FieldOffset(0)] - internal IronRdpError* err; - } - - private InnerUnion _inner; - - [MarshalAs(UnmanagedType.U1)] - public bool isOk; - - public unsafe CertificateChainIterator* Ok - { - get - { - return _inner.ok; - } - } - - public unsafe IronRdpError* Err - { - get - { - return _inner.err; - } - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxRDCleanPathPduBoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxRDCleanPathPduBoxIronRdpError.cs deleted file mode 100644 index c9f33a5d..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxRDCleanPathPduBoxIronRdpError.cs +++ /dev/null @@ -1,46 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp.Raw; - -#nullable enable - -[StructLayout(LayoutKind.Sequential)] -public partial struct RdcleanpathFfiResultBoxRDCleanPathPduBoxIronRdpError -{ - [StructLayout(LayoutKind.Explicit)] - private unsafe struct InnerUnion - { - [FieldOffset(0)] - internal RDCleanPathPdu* ok; - [FieldOffset(0)] - internal IronRdpError* err; - } - - private InnerUnion _inner; - - [MarshalAs(UnmanagedType.U1)] - public bool isOk; - - public unsafe RDCleanPathPdu* Ok - { - get - { - return _inner.ok; - } - } - - public unsafe IronRdpError* Err - { - get - { - return _inner.err; - } - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxVecU8BoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxVecU8BoxIronRdpError.cs deleted file mode 100644 index 7cce2e6a..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxVecU8BoxIronRdpError.cs +++ /dev/null @@ -1,46 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp.Raw; - -#nullable enable - -[StructLayout(LayoutKind.Sequential)] -public partial struct RdcleanpathFfiResultBoxVecU8BoxIronRdpError -{ - [StructLayout(LayoutKind.Explicit)] - private unsafe struct InnerUnion - { - [FieldOffset(0)] - internal VecU8* ok; - [FieldOffset(0)] - internal IronRdpError* err; - } - - private InnerUnion _inner; - - [MarshalAs(UnmanagedType.U1)] - public bool isOk; - - public unsafe VecU8* Ok - { - get - { - return _inner.ok; - } - } - - public unsafe IronRdpError* Err - { - get - { - return _inner.err; - } - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultRDCleanPathResultTypeBoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultRDCleanPathResultTypeBoxIronRdpError.cs deleted file mode 100644 index 6a9c6e8a..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultRDCleanPathResultTypeBoxIronRdpError.cs +++ /dev/null @@ -1,46 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp.Raw; - -#nullable enable - -[StructLayout(LayoutKind.Sequential)] -public partial struct RdcleanpathFfiResultRDCleanPathResultTypeBoxIronRdpError -{ - [StructLayout(LayoutKind.Explicit)] - private unsafe struct InnerUnion - { - [FieldOffset(0)] - internal RDCleanPathResultType ok; - [FieldOffset(0)] - internal IronRdpError* err; - } - - private InnerUnion _inner; - - [MarshalAs(UnmanagedType.U1)] - public bool isOk; - - public unsafe RDCleanPathResultType Ok - { - get - { - return _inner.ok; - } - } - - public unsafe IronRdpError* Err - { - get - { - return _inner.err; - } - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultU16BoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultU16BoxIronRdpError.cs deleted file mode 100644 index 3eaf3200..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultU16BoxIronRdpError.cs +++ /dev/null @@ -1,46 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp.Raw; - -#nullable enable - -[StructLayout(LayoutKind.Sequential)] -public partial struct RdcleanpathFfiResultU16BoxIronRdpError -{ - [StructLayout(LayoutKind.Explicit)] - private unsafe struct InnerUnion - { - [FieldOffset(0)] - internal ushort ok; - [FieldOffset(0)] - internal IronRdpError* err; - } - - private InnerUnion _inner; - - [MarshalAs(UnmanagedType.U1)] - public bool isOk; - - public unsafe ushort Ok - { - get - { - return _inner.ok; - } - } - - public unsafe IronRdpError* Err - { - get - { - return _inner.err; - } - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultUsizeBoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultUsizeBoxIronRdpError.cs deleted file mode 100644 index eecbdaea..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultUsizeBoxIronRdpError.cs +++ /dev/null @@ -1,46 +0,0 @@ -// by Diplomat - -#pragma warning disable 0105 -using System; -using System.Runtime.InteropServices; - -using Devolutions.IronRdp.Diplomat; -#pragma warning restore 0105 - -namespace Devolutions.IronRdp.Raw; - -#nullable enable - -[StructLayout(LayoutKind.Sequential)] -public partial struct RdcleanpathFfiResultUsizeBoxIronRdpError -{ - [StructLayout(LayoutKind.Explicit)] - private unsafe struct InnerUnion - { - [FieldOffset(0)] - internal nuint ok; - [FieldOffset(0)] - internal IronRdpError* err; - } - - private InnerUnion _inner; - - [MarshalAs(UnmanagedType.U1)] - public bool isOk; - - public unsafe nuint Ok - { - get - { - return _inner.ok; - } - } - - public unsafe IronRdpError* Err - { - get - { - return _inner.err; - } - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp/src/Connection.cs b/ffi/dotnet/Devolutions.IronRdp/src/Connection.cs index 497e70ab..0a03fd6e 100644 --- a/ffi/dotnet/Devolutions.IronRdp/src/Connection.cs +++ b/ffi/dotnet/Devolutions.IronRdp/src/Connection.cs @@ -11,17 +11,28 @@ public static class Connection { var client = await CreateTcpConnection(serverName, port); string clientAddr = client.Client.LocalEndPoint.ToString(); - System.Diagnostics.Debug.WriteLine(clientAddr); + Console.WriteLine(clientAddr); var framed = new Framed(client.GetStream()); var connector = ClientConnector.New(config, clientAddr); - ConnectionHelpers.SetupConnector(connector, config, factory); + connector.WithDynamicChannelDisplayControl(); + var dvcPipeProxy = config.DvcPipeProxy; + if (dvcPipeProxy != null) + { + connector.WithDynamicChannelPipeProxy(dvcPipeProxy); + } + + if (factory != null) + { + var cliprdr = factory.BuildCliprdr(); + connector.AttachStaticCliprdr(cliprdr); + } await ConnectBegin(framed, connector); var (serverPublicKey, framedSsl) = await SecurityUpgrade(framed, connector); - var result = await ConnectionHelpers.ConnectFinalize(serverName, connector, serverPublicKey, framedSsl); + var result = await ConnectFinalize(serverName, connector, serverPublicKey, framedSsl); return (result, framedSsl); } @@ -56,11 +67,78 @@ public static class Connection } } - internal static async Task ResolveGenerator(CredsspProcessGenerator generator, TcpClient tcpClient) + + private static async Task ConnectFinalize(string serverName, ClientConnector connector, + byte[] serverPubKey, Framed framedSsl) + { + var writeBuf2 = WriteBuf.New(); + if (connector.ShouldPerformCredssp()) + { + await PerformCredsspSteps(connector, serverName, writeBuf2, framedSsl, serverPubKey); + } + + while (!connector.GetDynState().IsTerminal()) + { + await SingleSequenceStep(connector, writeBuf2, framedSsl); + } + + ClientConnectorState state = connector.ConsumeAndCastToClientConnectorState(); + + if (state.GetEnumType() == ClientConnectorStateType.Connected) + { + return state.GetConnectedResult(); + } + else + { + throw new IronRdpLibException(IronRdpLibExceptionType.ConnectionFailed, "Connection failed"); + } + } + + private static async Task PerformCredsspSteps(ClientConnector connector, string serverName, WriteBuf writeBuf, + Framed framedSsl, byte[] serverpubkey) + { + var credsspSequenceInitResult = CredsspSequence.Init(connector, serverName, serverpubkey, null); + var credsspSequence = credsspSequenceInitResult.GetCredsspSequence(); + var tsRequest = credsspSequenceInitResult.GetTsRequest(); + var tcpClient = new TcpClient(); + while (true) + { + var generator = credsspSequence.ProcessTsRequest(tsRequest); + var clientState = await ResolveGenerator(generator, tcpClient); + writeBuf.Clear(); + var written = credsspSequence.HandleProcessResult(clientState, writeBuf); + + if (written.GetSize().IsSome()) + { + var actualSize = (int)written.GetSize().Get(); + var response = new byte[actualSize]; + writeBuf.ReadIntoBuf(response); + await framedSsl.Write(response); + } + + var pduHint = credsspSequence.NextPduHint(); + if (pduHint == null) + { + break; + } + + var pdu = await framedSsl.ReadByHint(pduHint); + var decoded = credsspSequence.DecodeServerMessage(pdu); + + // Don't remove, DecodeServerMessage is generated, and it can return null + if (null == decoded) + { + break; + } + + tsRequest = decoded; + } + } + + private static async Task ResolveGenerator(CredsspProcessGenerator generator, TcpClient tcpClient) { var state = generator.Start(); NetworkStream? stream = null; - while (true) { if (state.IsSuspended()) @@ -69,17 +147,16 @@ public static class Connection var protocol = request.GetProtocol(); var url = request.GetUrl(); var data = request.GetData(); + if (null == stream) + { + url = url.Replace("tcp://", ""); + var split = url.Split(":"); + await tcpClient.ConnectAsync(split[0], int.Parse(split[1])); + stream = tcpClient.GetStream(); + } if (protocol == NetworkRequestProtocol.Tcp) { - if (null == stream) - { - url = url.Replace("tcp://", ""); - var split = url.Split(":"); - await tcpClient.ConnectAsync(split[0], int.Parse(split[1])); - stream = tcpClient.GetStream(); - } - stream.Write(Utils.VecU8ToByte(data)); var readBuf = new byte[8096]; var readlen = await stream.ReadAsync(readBuf, 0, readBuf.Length); @@ -89,29 +166,13 @@ public static class Connection } else { - throw new Exception($"Unimplemented protocol: {protocol}"); - } - } - else if (state.IsCompleted()) - { - try - { - var clientState = state.GetClientStateIfCompleted(); - return clientState; - } - catch (IronRdpException ex) - { - System.Diagnostics.Debug.WriteLine($"[ResolveGenerator] Error getting client state: {ex.Message}"); - System.Diagnostics.Debug.WriteLine($"[ResolveGenerator] Error kind: {ex.Inner?.Kind}"); - System.Diagnostics.Debug.WriteLine($"[ResolveGenerator] Stack trace: {ex.StackTrace}"); - throw; + throw new Exception("Unimplemented protocol"); } } else { - var errorMsg = $"[ResolveGenerator] Generator state is neither suspended nor completed. IsSuspended={state.IsSuspended()}, IsCompleted={state.IsCompleted()}"; - System.Diagnostics.Debug.WriteLine(errorMsg); - throw new InvalidOperationException(errorMsg); + var clientState = state.GetClientStateIfCompleted(); + return clientState; } } } diff --git a/ffi/dotnet/Devolutions.IronRdp/src/ConnectionHelpers.cs b/ffi/dotnet/Devolutions.IronRdp/src/ConnectionHelpers.cs deleted file mode 100644 index d57aaaca..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/src/ConnectionHelpers.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System.Net.Sockets; - -namespace Devolutions.IronRdp; - -/// -/// Internal helper class providing shared connection logic for both direct and RDCleanPath connections. -/// -internal static class ConnectionHelpers -{ - /// - /// Sets up common connector configuration including dynamic channels and clipboard. - /// - internal static void SetupConnector(ClientConnector connector, Config config, CliprdrBackendFactory? factory) - { - connector.WithDynamicChannelDisplayControl(); - - var dvcPipeProxy = config.DvcPipeProxy; - if (dvcPipeProxy != null) - { - connector.WithDynamicChannelPipeProxy(dvcPipeProxy); - } - - if (factory != null) - { - var cliprdr = factory.BuildCliprdr(); - connector.AttachStaticCliprdr(cliprdr); - } - } - - /// - /// Performs CredSSP authentication steps over any stream type. - /// - internal static async Task PerformCredsspSteps( - ClientConnector connector, - string serverName, - WriteBuf writeBuf, - Framed framed, - byte[] serverpubkey) where T : Stream - { - // Extract hostname from "hostname:port" format if needed - // CredSSP needs just the hostname for the service principal name (TERMSRV/hostname) - var hostname = serverName; - var colonIndex = serverName.IndexOf(':'); - if (colonIndex > 0) - { - hostname = serverName.Substring(0, colonIndex); - } - - var credsspSequenceInitResult = CredsspSequence.Init(connector, hostname, serverpubkey, null); - var credsspSequence = credsspSequenceInitResult.GetCredsspSequence(); - var tsRequest = credsspSequenceInitResult.GetTsRequest(); - var tcpClient = new TcpClient(); - - while (true) - { - var generator = credsspSequence.ProcessTsRequest(tsRequest); - var clientState = await Connection.ResolveGenerator(generator, tcpClient); - writeBuf.Clear(); - var written = credsspSequence.HandleProcessResult(clientState, writeBuf); - - if (written.GetSize().IsSome()) - { - var actualSize = (int)written.GetSize().Get(); - var response = new byte[actualSize]; - writeBuf.ReadIntoBuf(response); - await framed.Write(response); - } - - var pduHint = credsspSequence.NextPduHint(); - if (pduHint == null) - { - break; - } - - var pdu = await framed.ReadByHint(pduHint); - var decoded = credsspSequence.DecodeServerMessage(pdu); - - // Don't remove, DecodeServerMessage is generated, and it can return null - if (null == decoded) - { - break; - } - - tsRequest = decoded; - } - } - - /// - /// Finalizes the RDP connection after security upgrade, performing CredSSP if needed - /// and completing the connection sequence. - /// - internal static async Task ConnectFinalize( - string serverName, - ClientConnector connector, - byte[] serverPubKey, - Framed framedSsl) where T : Stream - { - var writeBuf = WriteBuf.New(); - - if (connector.ShouldPerformCredssp()) - { - await PerformCredsspSteps(connector, serverName, writeBuf, framedSsl, serverPubKey); - } - - while (!connector.GetDynState().IsTerminal()) - { - await Connection.SingleSequenceStep(connector, writeBuf, framedSsl); - } - - ClientConnectorState state = connector.ConsumeAndCastToClientConnectorState(); - - if (state.GetEnumType() == ClientConnectorStateType.Connected) - { - return state.GetConnectedResult(); - } - else - { - throw new IronRdpLibException(IronRdpLibExceptionType.ConnectionFailed, "Connection failed"); - } - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp/src/Framed.cs b/ffi/dotnet/Devolutions.IronRdp/src/Framed.cs index 2e8772e7..f03530f3 100644 --- a/ffi/dotnet/Devolutions.IronRdp/src/Framed.cs +++ b/ffi/dotnet/Devolutions.IronRdp/src/Framed.cs @@ -134,45 +134,4 @@ public class Framed where TS : Stream } } } - - /// - /// Reads data from the buffer based on a custom PDU hint function. - /// - /// A custom hint object implementing IPduHint interface. - /// An asynchronous task that represents the operation. The task result contains the read data as a byte array. - public async Task ReadByHint(IPduHint customHint) - { - while (true) - { - var result = customHint.FindSize(this._buffer.ToArray()); - if (result.HasValue) - { - return await this.ReadExact((nuint)result.Value.Item2); - } - else - { - var len = await this.Read(); - if (len == 0) - { - throw new Exception("EOF"); - } - } - } - } -} - -/// -/// Interface for custom PDU hint implementations. -/// -public interface IPduHint -{ - /// - /// Finds the size of a PDU in the given byte array. - /// - /// The byte array to analyze. - /// - /// A tuple (detected, size) if PDU is detected, null if more bytes are needed. - /// Throws exception if invalid PDU is detected. - /// - (bool, int)? FindSize(byte[] bytes); } \ No newline at end of file diff --git a/ffi/dotnet/Devolutions.IronRdp/src/RDCleanPathConnection.cs b/ffi/dotnet/Devolutions.IronRdp/src/RDCleanPathConnection.cs deleted file mode 100644 index 725c0525..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/src/RDCleanPathConnection.cs +++ /dev/null @@ -1,200 +0,0 @@ -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; - -namespace Devolutions.IronRdp; - -/// -/// Provides methods for connecting to RDP servers through an RDCleanPath-compatible gateway -/// (such as Devolutions Gateway or Cloudflare) using WebSocket. -/// -public static class RDCleanPathConnection -{ - /// - /// Connects to an RDP server through an RDCleanPath-compatible gateway using WebSocket. - /// - /// The RDP connection configuration - /// The WebSocket URL to the RDCleanPath gateway (e.g., "ws://localhost:7171/jet/rdp") - /// The JWT authentication token for the RDCleanPath gateway - /// The destination RDP server address (e.g., "10.10.0.3:3389") - /// Optional preconnection blob for Hyper-V VM connections - /// Optional clipboard backend factory - /// A tuple containing the connection result and framed WebSocket stream - public static async Task<(ConnectionResult, Framed)> ConnectRDCleanPath( - Config config, - string gatewayUrl, - string authToken, - string destination, - string? pcb = null, - CliprdrBackendFactory? factory = null) - { - // Step 1: Connect WebSocket to gateway - System.Diagnostics.Debug.WriteLine($"Connecting to gateway at {gatewayUrl}..."); - var ws = await WebSocketStream.ConnectAsync(new Uri(gatewayUrl)); - var framed = new Framed(ws); - - // Step 2: Get client local address from the WebSocket connection - // This mimics Rust: let client_addr = socket.local_addr()?; - string clientAddr = ws.ClientAddr; - System.Diagnostics.Debug.WriteLine($"Client local address: {clientAddr}"); - - // Step 3: Setup ClientConnector - var connector = ClientConnector.New(config, clientAddr); - ConnectionHelpers.SetupConnector(connector, config, factory); - - // Step 4: Perform RDCleanPath handshake - System.Diagnostics.Debug.WriteLine("Performing RDCleanPath handshake..."); - var (serverPublicKey, framedAfterHandshake) = await ConnectRdCleanPath( - framed, connector, destination, authToken, pcb ?? ""); - - // Step 5: Mark security upgrade as done (WebSocket already has TLS) - connector.MarkSecurityUpgradeAsDone(); - - // Step 6: Finalize connection - System.Diagnostics.Debug.WriteLine("Finalizing RDP connection..."); - var result = await ConnectionHelpers.ConnectFinalize(destination, connector, serverPublicKey, framedAfterHandshake); - - System.Diagnostics.Debug.WriteLine("Gateway connection established successfully!"); - return (result, framedAfterHandshake); - } - - /// - /// Performs the RDCleanPath handshake with the RDCleanPath-compatible gateway. - /// - private static async Task<(byte[], Framed)> ConnectRdCleanPath( - Framed framed, - ClientConnector connector, - string destination, - string authToken, - string pcb) - { - var writeBuf = WriteBuf.New(); - - // Step 1: Generate X.224 Connection Request - System.Diagnostics.Debug.WriteLine("Generating X.224 Connection Request..."); - var written = connector.StepNoInput(writeBuf); - var x224PduSize = (int)written.GetSize().Get(); - var x224Pdu = new byte[x224PduSize]; - writeBuf.ReadIntoBuf(x224Pdu); - - // Step 2: Create and send RDCleanPath Request - System.Diagnostics.Debug.WriteLine($"Sending RDCleanPath request to {destination}..."); - var rdCleanPathReq = RDCleanPathPdu.NewRequest(x224Pdu, destination, authToken, pcb); - var reqBytes = rdCleanPathReq.ToDer(); - var reqBytesArray = new byte[reqBytes.GetSize()]; - reqBytes.Fill(reqBytesArray); - await framed.Write(reqBytesArray); - - // Step 3: Read RDCleanPath Response - System.Diagnostics.Debug.WriteLine("Waiting for RDCleanPath response..."); - var respBytes = await framed.ReadByHint(new RDCleanPathHint()); - var rdCleanPathResp = RDCleanPathPdu.FromDer(respBytes); - - // Step 4: Determine response type and handle accordingly - var resultType = rdCleanPathResp.GetType(); - - if (resultType == RDCleanPathResultType.Response) - { - System.Diagnostics.Debug.WriteLine("RDCleanPath handshake successful!"); - - // Extract X.224 response - var x224Response = rdCleanPathResp.GetX224Response(); - var x224ResponseBytes = new byte[x224Response.GetSize()]; - x224Response.Fill(x224ResponseBytes); - - // Process X.224 response with connector - writeBuf.Clear(); - connector.Step(x224ResponseBytes, writeBuf); - - // Extract server public key from certificate chain - var certChain = rdCleanPathResp.GetServerCertChain(); - if (certChain.IsEmpty()) - { - throw new IronRdpLibException( - IronRdpLibExceptionType.ConnectionFailed, - "Server certificate chain is empty"); - } - - var firstCert = certChain.Next(); - if (firstCert == null) - { - throw new IronRdpLibException( - IronRdpLibExceptionType.ConnectionFailed, - "Failed to get first certificate from chain"); - } - - var certBytes = new byte[firstCert.GetSize()]; - firstCert.Fill(certBytes); - - var serverPublicKey = ExtractPublicKeyFromX509(certBytes); - - System.Diagnostics.Debug.WriteLine($"Extracted server public key (length: {serverPublicKey.Length})"); - - return (serverPublicKey, framed); - } - else if (resultType == RDCleanPathResultType.GeneralError) - { - var errorCode = rdCleanPathResp.GetErrorCode(); - var errorMessage = rdCleanPathResp.GetErrorMessage(); - throw new IronRdpLibException( - IronRdpLibExceptionType.ConnectionFailed, - $"RDCleanPath error (code {errorCode}): {errorMessage}"); - } - else if (resultType == RDCleanPathResultType.NegotiationError) - { - throw new IronRdpLibException( - IronRdpLibExceptionType.ConnectionFailed, - "RDCleanPath negotiation error: Server rejected connection parameters"); - } - else - { - throw new IronRdpLibException( - IronRdpLibExceptionType.ConnectionFailed, - $"Unexpected RDCleanPath response type: {resultType}"); - } - } - - /// - /// Extracts the public key from an X.509 certificate in DER format. - /// - private static byte[] ExtractPublicKeyFromX509(byte[] certDer) - { - try - { - var cert = new X509Certificate2(certDer); - return cert.GetPublicKey(); - } - catch (Exception ex) - { - throw new IronRdpLibException( - IronRdpLibExceptionType.ConnectionFailed, - $"Failed to extract public key from certificate: {ex.Message}"); - } - } -} - -/// -/// PDU hint for detecting RDCleanPath PDUs in the stream. -/// -public class RDCleanPathHint : IPduHint -{ - public (bool, int)? FindSize(byte[] bytes) - { - var detection = RDCleanPathPdu.Detect(bytes); - - if (detection.IsDetected()) - { - var totalLength = (int)detection.GetTotalLength(); - return (true, totalLength); - } - - if (detection.IsNotEnoughBytes()) - { - return null; // Need more bytes - } - - // Detection failed - throw new IronRdpLibException( - IronRdpLibExceptionType.ConnectionFailed, - "Invalid RDCleanPath PDU detected"); - } -} diff --git a/ffi/dotnet/Devolutions.IronRdp/src/WebsocketStream.cs b/ffi/dotnet/Devolutions.IronRdp/src/WebsocketStream.cs deleted file mode 100644 index 5f528101..00000000 --- a/ffi/dotnet/Devolutions.IronRdp/src/WebsocketStream.cs +++ /dev/null @@ -1,212 +0,0 @@ -using System; -using System.Buffers; -using System.IO; -using System.Net; -using System.Net.Http; -using System.Net.Sockets; -using System.Net.WebSockets; -using System.Threading; -using System.Threading.Tasks; - -public sealed class WebSocketStream : Stream -{ - private readonly ClientWebSocket _ws; - private readonly byte[] _recvBuf; - private int _recvPos; - private int _recvLen; - private bool _remoteClosed; - private bool _disposed; - private readonly string _clientAddr; - - private const int DefaultRecvBufferSize = 64 * 1024; - private const int MaxSendFrame = 16 * 1024; // send in chunks - - private WebSocketStream(ClientWebSocket ws, int receiveBufferSize, string clientAddr) - { - _ws = ws ?? throw new ArgumentNullException(nameof(ws)); - _recvBuf = ArrayPool.Shared.Rent(Math.Max(1024, receiveBufferSize)); - _clientAddr = clientAddr; - } - - public static async Task ConnectAsync( - Uri uri, - ClientWebSocket? ws = null, - int receiveBufferSize = DefaultRecvBufferSize, - CancellationToken ct = default) - { - // Capture the local endpoint from the socket using SocketsHttpHandler.ConnectCallback - // This follows the Rust approach: socket.local_addr() - IPEndPoint? localEndPoint = null; - - var handler = new SocketsHttpHandler - { - ConnectCallback = async (context, cancellationToken) => - { - var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); - - // Set TCP_NODELAY (matching Rust: socket.set_nodelay(true)) - socket.NoDelay = true; - - // Connect to the endpoint - await socket.ConnectAsync(context.DnsEndPoint, cancellationToken).ConfigureAwait(false); - - // Capture the local endpoint after connection - localEndPoint = socket.LocalEndPoint as IPEndPoint; - - return new NetworkStream(socket, ownsSocket: true); - } - }; - - var invoker = new HttpMessageInvoker(handler); - - ws ??= new ClientWebSocket(); - await ws.ConnectAsync(uri, invoker, ct).ConfigureAwait(false); - - string clientAddr = localEndPoint?.ToString() ?? "127.0.0.1:0"; - - return new WebSocketStream(ws, receiveBufferSize, clientAddr); - } - - public ClientWebSocket Socket => _ws; - - /// - /// Gets the local client address in "IP:port" format. - /// This is the address that was determined when establishing the TCP connection. - /// - public string ClientAddr => _clientAddr; - - public override bool CanRead => true; - public override bool CanSeek => false; - public override bool CanWrite => true; - public override long Length => throw new NotSupportedException(); - public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } - - public override void Flush() { /* no-op */ } - public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask; - - public override int Read(byte[] buffer, int offset, int count) => - ReadAsync(buffer.AsMemory(offset, count)).AsTask().GetAwaiter().GetResult(); - - public override void Write(byte[] buffer, int offset, int count) => - WriteAsync(buffer.AsMemory(offset, count)).GetAwaiter().GetResult(); - - public override async ValueTask ReadAsync( - Memory destination, CancellationToken cancellationToken = default) - { - if (_disposed) throw new ObjectDisposedException(nameof(WebSocketStream)); - if (_remoteClosed) return 0; - if (destination.Length == 0) return 0; - - // Fill local buffer if empty - if (_recvLen == 0) - { - var mem = _recvBuf.AsMemory(); - while (true) - { - var result = await _ws.ReceiveAsync(mem, cancellationToken).ConfigureAwait(false); - - // Close frame → signal EOF - if (result.MessageType == WebSocketMessageType.Close) - { - _remoteClosed = true; - try { await _ws.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "OK", cancellationToken).ConfigureAwait(false); } - catch { /* ignore */ } - return 0; - } - - if (result.MessageType == WebSocketMessageType.Text) - throw new InvalidOperationException("Received TEXT frame; this stream expects BINARY."); - - // Some data arrived - if (result.Count > 0) - { - _recvPos = 0; - _recvLen = result.Count; - break; - } - - // Keep looping if Count == 0 (can happen with pings/keepers) - } - } - - var toCopy = Math.Min(destination.Length, _recvLen); - new ReadOnlySpan(_recvBuf, _recvPos, toCopy).CopyTo(destination.Span); - _recvPos += toCopy; - _recvLen -= toCopy; - - // If we've drained local buffer, try to prefetch next chunk (non-blocking behavior not guaranteed) - if (_recvLen == 0 && _ws.State == WebSocketState.Open) - { - // optional prefetch: not strictly necessary—kept simple - } - - return toCopy; - } - - public override async Task WriteAsync( - byte[] buffer, int offset, int count, CancellationToken cancellationToken) - => await WriteAsync(buffer.AsMemory(offset, count), cancellationToken); - - public override async ValueTask WriteAsync( - ReadOnlyMemory source, CancellationToken cancellationToken = default) - { - if (_disposed) throw new ObjectDisposedException(nameof(WebSocketStream)); - if (_ws.State != WebSocketState.Open) throw new IOException("WebSocket is not open."); - - // Treat each Write* as one complete WebSocket message (Binary). - // Chunk large payloads as continuation frames and set EndOfMessage on the last chunk. - int sent = 0; - while (sent < source.Length) - { - var chunkLen = Math.Min(MaxSendFrame, source.Length - sent); - var chunk = source.Slice(sent, chunkLen); - sent += chunkLen; - - bool end = (sent == source.Length); - await _ws.SendAsync(chunk, WebSocketMessageType.Binary, end, cancellationToken).ConfigureAwait(false); - } - } - - public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - public override void SetLength(long value) => throw new NotSupportedException(); - - protected override void Dispose(bool disposing) - { - if (_disposed) return; - if (disposing) - { - try - { - if (_ws.State == WebSocketState.Open) - { - _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Disposing", CancellationToken.None) - .GetAwaiter().GetResult(); - } - } - catch { /* ignore on dispose */ } - _ws.Dispose(); - ArrayPool.Shared.Return(_recvBuf); - } - _disposed = true; - base.Dispose(disposing); - } - -#if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER - public override async ValueTask DisposeAsync() - { - if (!_disposed) - { - try - { - if (_ws.State == WebSocketState.Open) - await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Disposing", CancellationToken.None).ConfigureAwait(false); - } - catch { /* ignore */ } - _ws.Dispose(); - ArrayPool.Shared.Return(_recvBuf); - _disposed = true; - } - await base.DisposeAsync().ConfigureAwait(false); - } -#endif -} diff --git a/ffi/src/clipboard/mod.rs b/ffi/src/clipboard/mod.rs index 386e7b85..e50aa1fe 100644 --- a/ffi/src/clipboard/mod.rs +++ b/ffi/src/clipboard/mod.rs @@ -34,8 +34,8 @@ pub struct FfiClipbarodMessageProxy { impl ironrdp::cliprdr::backend::ClipboardMessageProxy for FfiClipbarodMessageProxy { fn send_clipboard_message(&self, message: ironrdp::cliprdr::backend::ClipboardMessage) { - if let Err(error) = self.sender.send(message) { - error!(?error, "Failed to send clipboard message"); + if let Err(err) = self.sender.send(message) { + error!("Failed to send clipboard message: {:?}", err); } } } diff --git a/ffi/src/connector/activation.rs b/ffi/src/connector/activation.rs index d48bede6..076315c6 100644 --- a/ffi/src/connector/activation.rs +++ b/ffi/src/connector/activation.rs @@ -16,7 +16,7 @@ pub mod ffi { impl ConnectionActivationSequence { pub fn get_state(&self) -> Box { - Box::new(ConnectionActivationState(self.0.connection_activation_state())) + Box::new(ConnectionActivationState(self.0.state.clone())) } pub fn next_pdu_hint<'a>(&'a self) -> Result>>, Box> { @@ -83,17 +83,17 @@ pub mod ffi { pub fn get_connection_finalization( &self, ) -> Result, Box> { - match self.0 { + match &self.0 { ironrdp::connector::connection_activation::ConnectionActivationState::ConnectionFinalization { io_channel_id, user_channel_id, desktop_size, connection_finalization, } => Ok(Box::new(ConnectionActivationStateConnectionFinalization { - io_channel_id, - user_channel_id, - desktop_size, - connection_finalization, + io_channel_id: *io_channel_id, + user_channel_id: *user_channel_id, + desktop_size: *desktop_size, + connection_finalization: connection_finalization.clone(), })), _ => Err(IncorrectEnumTypeError::on_variant("ConnectionFinalization") .of_enum("ConnectionActivationState") diff --git a/ffi/src/connector/mod.rs b/ffi/src/connector/mod.rs index 332177af..e9226467 100644 --- a/ffi/src/connector/mod.rs +++ b/ffi/src/connector/mod.rs @@ -97,7 +97,7 @@ pub mod ffi { pub fn with_dynamic_channel_display_control(&mut self) -> Result<(), Box> { self.with_dvc(DisplayControlClient::new(|c| { - info!(display_control_capabilities = ?c, "DisplayControl capabilities received"); + info!(DisplayCountrolCapabilities = ?c, "DisplayControl capabilities received"); Ok(Vec::new()) })) } @@ -185,7 +185,7 @@ pub mod ffi { let Some(connector) = self.0.as_ref() else { return Err(ValueConsumedError::for_item("connector").into()); }; - tracing::trace!(pdu_hint=?connector.next_pdu_hint(), "Reading next PDU hint"); + tracing::trace!(pduhint=?connector.next_pdu_hint(), "Reading next PDU hint"); Ok(connector.next_pdu_hint().map(PduHint).map(Box::new)) } diff --git a/ffi/src/dvc/dvc_pipe_proxy_message_queue.rs b/ffi/src/dvc/dvc_pipe_proxy_message_queue.rs index 3b32c393..a57935b9 100644 --- a/ffi/src/dvc/dvc_pipe_proxy_message_queue.rs +++ b/ffi/src/dvc/dvc_pipe_proxy_message_queue.rs @@ -27,7 +27,6 @@ pub mod ffi { impl DvcPipeProxyMessageQueue { pub fn new(queue_size: u32) -> Box { - #[expect(clippy::missing_panics_doc, reason = "unreachable panic (integer upcast)")] let queue_size = usize::try_from(queue_size).expect("invalid dvc pipe proxy message queue size"); Box::new(DvcPipeProxyMessageQueue(DvcPipeProxyMessageQueueInner::new(queue_size))) diff --git a/ffi/src/error.rs b/ffi/src/error.rs index 11ae4e2b..9312ba45 100644 --- a/ffi/src/error.rs +++ b/ffi/src/error.rs @@ -6,15 +6,101 @@ use ironrdp::connector::ConnectorError; use ironrdp::session::SessionError; #[cfg(target_os = "windows")] use ironrdp_cliprdr_native::WinCliprdrError; -use ironrdp_rdcleanpath::der; use self::ffi::IronRdpErrorKind; -pub struct GenericError(pub anyhow::Error); +impl From for IronRdpErrorKind { + fn from(val: ConnectorError) -> Self { + match val.kind { + ironrdp::connector::ConnectorErrorKind::Encode(_) => IronRdpErrorKind::EncodeError, + ironrdp::connector::ConnectorErrorKind::Decode(_) => IronRdpErrorKind::DecodeError, + ironrdp::connector::ConnectorErrorKind::Credssp(_) => IronRdpErrorKind::CredsspError, + ironrdp::connector::ConnectorErrorKind::AccessDenied => IronRdpErrorKind::AccessDenied, + _ => IronRdpErrorKind::Generic, + } + } +} -impl Display for GenericError { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:#}", self.0) +impl From<&str> for IronRdpErrorKind { + fn from(_val: &str) -> Self { + IronRdpErrorKind::Generic + } +} + +impl From for IronRdpErrorKind { + fn from(_val: sspi::Error) -> Self { + IronRdpErrorKind::CredsspError + } +} + +impl From for IronRdpErrorKind { + fn from(_val: ironrdp::pdu::PduError) -> Self { + IronRdpErrorKind::PduError + } +} + +impl From for IronRdpErrorKind { + fn from(_val: ironrdp::core::EncodeError) -> Self { + IronRdpErrorKind::EncodeError + } +} + +impl From for IronRdpErrorKind { + fn from(_val: ironrdp::core::DecodeError) -> Self { + IronRdpErrorKind::DecodeError + } +} + +impl From for IronRdpErrorKind { + fn from(_: std::io::Error) -> Self { + IronRdpErrorKind::IO + } +} + +impl From for IronRdpErrorKind { + fn from(_val: core::fmt::Error) -> Self { + IronRdpErrorKind::Generic + } +} + +impl From for IronRdpErrorKind { + fn from(value: SessionError) -> Self { + match value.kind() { + ironrdp::session::SessionErrorKind::Pdu(_) => IronRdpErrorKind::PduError, + ironrdp::session::SessionErrorKind::Encode(_) => IronRdpErrorKind::EncodeError, + ironrdp::session::SessionErrorKind::Decode(_) => IronRdpErrorKind::DecodeError, + _ => IronRdpErrorKind::Generic, + } + } +} + +impl From<&dyn ClipboardError> for IronRdpErrorKind { + fn from(_val: &dyn ClipboardError) -> Self { + IronRdpErrorKind::Clipboard + } +} + +#[cfg(target_os = "windows")] +impl From for IronRdpErrorKind { + fn from(_val: WinCliprdrError) -> Self { + IronRdpErrorKind::Clipboard + } +} + +impl From for IronRdpErrorKind { + fn from(_val: WrongOSError) -> Self { + IronRdpErrorKind::WrongOS + } +} + +impl From for Box +where + T: Into + ToString, +{ + fn from(value: T) -> Self { + let repr = value.to_string(); + let kind = value.into(); + Box::new(ffi::IronRdpError(IronRdpErrorInner { repr, kind })) } } @@ -23,163 +109,6 @@ struct IronRdpErrorInner { kind: IronRdpErrorKind, } -// Helper function to create an IronRdpError -fn make_ffi_error(repr: String, kind: IronRdpErrorKind) -> Box { - Box::new(ffi::IronRdpError(IronRdpErrorInner { repr, kind })) -} - -// Direct conversion from IronRdpErrorKind (for cases with no underlying error) -impl From for Box { - fn from(kind: IronRdpErrorKind) -> Self { - make_ffi_error(kind.to_string(), kind) - } -} - -// IronRDP errors - use .report() to include full error chain with sources -impl From for Box { - fn from(value: ConnectorError) -> Self { - let kind = match value.kind() { - ironrdp::connector::ConnectorErrorKind::Encode(_) => IronRdpErrorKind::EncodeError, - ironrdp::connector::ConnectorErrorKind::Decode(_) => IronRdpErrorKind::DecodeError, - ironrdp::connector::ConnectorErrorKind::Credssp(_) => IronRdpErrorKind::CredsspError, - ironrdp::connector::ConnectorErrorKind::AccessDenied => IronRdpErrorKind::AccessDenied, - _ => IronRdpErrorKind::Generic, - }; - let repr = value.report().to_string(); - make_ffi_error(repr, kind) - } -} - -impl From for Box { - fn from(value: SessionError) -> Self { - let kind = match value.kind() { - ironrdp::session::SessionErrorKind::Pdu(_) => IronRdpErrorKind::PduError, - ironrdp::session::SessionErrorKind::Encode(_) => IronRdpErrorKind::EncodeError, - ironrdp::session::SessionErrorKind::Decode(_) => IronRdpErrorKind::DecodeError, - _ => IronRdpErrorKind::Generic, - }; - let repr = value.report().to_string(); - make_ffi_error(repr, kind) - } -} - -impl From for Box { - fn from(value: ironrdp::pdu::PduError) -> Self { - let repr = value.report().to_string(); - make_ffi_error(repr, IronRdpErrorKind::PduError) - } -} - -impl From for Box { - fn from(value: ironrdp::core::EncodeError) -> Self { - let repr = value.report().to_string(); - make_ffi_error(repr, IronRdpErrorKind::EncodeError) - } -} - -impl From for Box { - fn from(value: ironrdp::core::DecodeError) -> Self { - let repr = value.report().to_string(); - make_ffi_error(repr, IronRdpErrorKind::DecodeError) - } -} - -// std::io::Error - convert to anyhow::Error for proper source chain formatting -impl From for Box { - fn from(value: std::io::Error) -> Self { - let repr = format!("{:#}", anyhow::Error::new(value)); - make_ffi_error(repr, IronRdpErrorKind::IO) - } -} - -// sspi::Error - convert to anyhow::Error for proper source chain formatting -impl From for Box { - fn from(value: sspi::Error) -> Self { - let repr = format!("{:#}", anyhow::Error::new(value)); - make_ffi_error(repr, IronRdpErrorKind::CredsspError) - } -} - -// Simple string error -impl From<&str> for Box { - fn from(value: &str) -> Self { - make_ffi_error(value.to_owned(), IronRdpErrorKind::Generic) - } -} - -// core::fmt::Error - convert to anyhow::Error for consistency -impl From for Box { - fn from(value: core::fmt::Error) -> Self { - let repr = format!("{:#}", anyhow::Error::new(value)); - make_ffi_error(repr, IronRdpErrorKind::Generic) - } -} - -// Clipboard errors - manually format with full source chain -impl From<&dyn ClipboardError> for Box { - fn from(value: &dyn ClipboardError) -> Self { - use core::fmt::Write as _; - - // Manually build error chain since we have a trait object reference - let mut repr = value.to_string(); - let mut source = value.source(); - while let Some(e) = source { - let _ = write!(&mut repr, ", caused by: {e}"); - source = e.source(); - } - make_ffi_error(repr, IronRdpErrorKind::Clipboard) - } -} - -#[cfg(target_os = "windows")] -impl From for Box { - fn from(value: WinCliprdrError) -> Self { - let repr = format!("{:#}", anyhow::Error::new(value)); - make_ffi_error(repr, IronRdpErrorKind::Clipboard) - } -} - -// DER errors - convert to anyhow::Error for proper source chain formatting -impl From for Box { - fn from(value: der::Error) -> Self { - let repr = format!("{:#}", anyhow::Error::new(value)); - make_ffi_error(repr, IronRdpErrorKind::DecodeError) - } -} - -impl From for Box { - fn from(value: ironrdp_rdcleanpath::MissingRDCleanPathField) -> Self { - let repr = format!("{:#}", anyhow::Error::new(value)); - make_ffi_error(repr, IronRdpErrorKind::Generic) - } -} - -// GenericError already has proper Display impl with {:#} -impl From for Box { - fn from(value: GenericError) -> Self { - make_ffi_error(value.to_string(), IronRdpErrorKind::Generic) - } -} - -// FFI-specific errors -impl From for Box { - fn from(value: ValueConsumedError) -> Self { - make_ffi_error(value.to_string(), IronRdpErrorKind::Consumed) - } -} - -impl From for Box { - fn from(value: IncorrectEnumTypeError) -> Self { - make_ffi_error(value.to_string(), IronRdpErrorKind::IncorrectEnumType) - } -} - -impl From for Box { - fn from(value: WrongOSError) -> Self { - make_ffi_error(value.to_string(), IronRdpErrorKind::WrongOS) - } -} - #[diplomat::bridge] pub mod ffi { use core::fmt::Write as _; @@ -292,7 +221,11 @@ impl IncorrectEnumTypeErrorBuilder { impl Display for IncorrectEnumTypeError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "expected enum variable {} of enum {}", self.expected, self.enum_name) + write!( + f, + "expected enum variable {}, of enum {}", + self.expected, self.enum_name + ) } } diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs index 44009cd5..407847ce 100644 --- a/ffi/src/lib.rs +++ b/ffi/src/lib.rs @@ -11,7 +11,6 @@ pub mod graphics; pub mod input; pub mod log; pub mod pdu; -pub mod rdcleanpath; pub mod session; pub mod svc; pub mod utils; diff --git a/ffi/src/log.rs b/ffi/src/log.rs index f050b150..c1c453df 100644 --- a/ffi/src/log.rs +++ b/ffi/src/log.rs @@ -14,16 +14,11 @@ pub mod ffi { pub struct Log; impl Log { - /// # Panics - /// - /// - Panics if log directory creation fails. - /// - Panics if tracing initialization fails. - // FIXME: We should return an error instead, because panicking at the FFI boundary is unsafe. pub fn init_with_env() { INIT_LOG.call_once(|| { let log_file = std::env::var(IRONRDP_LOG_PATH).ok(); let log_file = log_file.as_deref(); - setup_logging(log_file).expect("failed to setup logging"); + setup_logging(log_file).expect("Failed to setup logging"); }); } } diff --git a/ffi/src/rdcleanpath.rs b/ffi/src/rdcleanpath.rs deleted file mode 100644 index a842c747..00000000 --- a/ffi/src/rdcleanpath.rs +++ /dev/null @@ -1,268 +0,0 @@ -#[diplomat::bridge] -pub mod ffi { - use core::fmt::Write as _; - - use anyhow::Context as _; - use diplomat_runtime::DiplomatWriteable; - - use crate::error::ffi::IronRdpError; - use crate::error::GenericError; - use crate::utils::ffi::VecU8; - - #[diplomat::opaque] - pub struct RDCleanPathPdu(pub ironrdp_rdcleanpath::RDCleanPathPdu); - - impl RDCleanPathPdu { - /// Creates a new RDCleanPath request PDU - /// - /// # Arguments - /// * `x224_pdu` - The X.224 Connection Request PDU bytes - /// * `destination` - The destination RDP server address (e.g., "10.10.0.3:3389") - /// * `proxy_auth` - The JWT authentication token - /// * `pcb` - Optional preconnection blob (for Hyper-V VM connections, empty string if not needed) - pub fn new_request( - x224_pdu: &[u8], - destination: &str, - proxy_auth: &str, - pcb: &str, - ) -> Result, Box> { - let pcb_opt = if pcb.is_empty() { None } else { Some(pcb.to_owned()) }; - - let pdu = ironrdp_rdcleanpath::RDCleanPathPdu::new_request( - x224_pdu.to_vec(), - destination.to_owned(), - proxy_auth.to_owned(), - pcb_opt, - ) - .context("failed to create RDCleanPath request") - .map_err(GenericError)?; - - Ok(Box::new(RDCleanPathPdu(pdu))) - } - - /// Decodes a RDCleanPath PDU from DER-encoded bytes - pub fn from_der(bytes: &[u8]) -> Result, Box> { - let pdu = ironrdp_rdcleanpath::RDCleanPathPdu::from_der(bytes) - .context("failed to decode RDCleanPath PDU") - .map_err(GenericError)?; - - Ok(Box::new(RDCleanPathPdu(pdu))) - } - - /// Encodes the RDCleanPath PDU to DER-encoded bytes - pub fn to_der(&self) -> Result, Box> { - let bytes = self - .0 - .to_der() - .context("failed to encode RDCleanPath PDU") - .map_err(GenericError)?; - - Ok(Box::new(VecU8(bytes))) - } - - /// Detects if the bytes contain a valid RDCleanPath PDU and returns detection result - pub fn detect(bytes: &[u8]) -> Box { - let result = ironrdp_rdcleanpath::RDCleanPathPdu::detect(bytes); - Box::new(RDCleanPathDetectionResult(result)) - } - - /// Gets the type of this RDCleanPath PDU - pub fn get_type(&self) -> Result> { - if self.0.destination.is_some() { - if self.0.proxy_auth.is_none() { - return Err(Self::missing_field("proxy_auth")); - } - - if self.0.x224_connection_pdu.is_none() { - return Err(Self::missing_field("x224_connection_pdu")); - } - - Ok(RDCleanPathResultType::Request) - } else if self.0.server_addr.is_some() { - if self.0.x224_connection_pdu.is_none() { - return Err(Self::missing_field("x224_connection_pdu")); - } - - if self.0.server_cert_chain.is_none() { - return Err(Self::missing_field("server_cert_chain")); - } - - Ok(RDCleanPathResultType::Response) - } else if let Some(error) = &self.0.error { - if error.error_code == ironrdp_rdcleanpath::NEGOTIATION_ERROR_CODE { - if self.0.x224_connection_pdu.is_none() { - return Err(Self::missing_field("x224_connection_pdu")); - } - - Ok(RDCleanPathResultType::NegotiationError) - } else { - Ok(RDCleanPathResultType::GeneralError) - } - } else { - Err(Self::missing_field("error")) - } - } - - /// Gets the X.224 connection response bytes (for Response or NegotiationError variants) - pub fn get_x224_response(&self) -> Result, Box> { - if self.0.server_addr.is_some() { - let x224 = self - .0 - .x224_connection_pdu - .as_ref() - .ok_or_else(|| Self::missing_field("x224_connection_pdu"))?; - self.0 - .server_cert_chain - .as_ref() - .ok_or_else(|| Self::missing_field("server_cert_chain"))?; - - Ok(Box::new(VecU8(x224.as_bytes().to_vec()))) - } else if let Some(error) = &self.0.error { - if error.error_code == ironrdp_rdcleanpath::NEGOTIATION_ERROR_CODE { - let x224 = self - .0 - .x224_connection_pdu - .as_ref() - .ok_or_else(|| Self::missing_field("x224_connection_pdu"))?; - - Ok(Box::new(VecU8(x224.as_bytes().to_vec()))) - } else { - Err(GenericError(anyhow::anyhow!("RDCleanPath variant does not contain X.224 response")).into()) - } - } else { - Err(GenericError(anyhow::anyhow!("RDCleanPath variant does not contain X.224 response")).into()) - } - } - - /// Gets the server certificate chain (for Response variant) - /// Returns a vector iterator of certificate bytes - pub fn get_server_cert_chain(&self) -> Result, Box> { - if self.0.server_addr.is_some() { - self.0 - .x224_connection_pdu - .as_ref() - .ok_or_else(|| Self::missing_field("x224_connection_pdu"))?; - let certs = self - .0 - .server_cert_chain - .as_ref() - .ok_or_else(|| Self::missing_field("server_cert_chain"))?; - - let certs: Vec> = certs.iter().map(|cert| cert.as_bytes().to_vec()).collect(); - Ok(Box::new(CertificateChainIterator { certs, index: 0 })) - } else { - Err(GenericError(anyhow::anyhow!( - "RDCleanPath variant does not contain certificate chain" - )) - .into()) - } - } - - /// Gets the server address string (for Response variant) - pub fn get_server_addr<'a>(&'a self, writeable: &'a mut DiplomatWriteable) { - if self.0.server_addr.is_some() - && self.0.server_cert_chain.is_some() - && self.0.x224_connection_pdu.is_some() - { - if let Some(server_addr) = &self.0.server_addr { - let _ = write!(writeable, "{server_addr}"); - } - } - } - - /// Gets error message (for GeneralError variant) - pub fn get_error_message<'a>(&'a self, writeable: &'a mut DiplomatWriteable) { - if let Ok(err) = self.general_error() { - let _ = write!(writeable, "{err}"); - } - } - - /// Gets the error code (for GeneralError variant) - pub fn get_error_code(&self) -> Result> { - let err = self.general_error()?; - Ok(err.error_code) - } - - /// Gets the HTTP status code if present (for GeneralError variant) - /// Returns error if not present or not a GeneralError variant - pub fn get_http_status_code(&self) -> Result> { - let err = self.general_error()?; - - err.http_status_code - .ok_or_else(|| GenericError(anyhow::anyhow!("HTTP status code not present")).into()) - } - - fn missing_field(field: &'static str) -> Box { - GenericError(anyhow::anyhow!("RDCleanPath is missing {field} field")).into() - } - - fn general_error(&self) -> Result<&ironrdp_rdcleanpath::RDCleanPathErr, Box> { - let error = self.0.error.as_ref().ok_or_else(|| Self::missing_field("error"))?; - - if error.error_code == ironrdp_rdcleanpath::NEGOTIATION_ERROR_CODE { - Err(GenericError(anyhow::anyhow!("not a GeneralError variant")).into()) - } else { - Ok(error) - } - } - } - - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub enum RDCleanPathResultType { - Request, - Response, - GeneralError, - NegotiationError, - } - - #[diplomat::opaque] - pub struct RDCleanPathDetectionResult(pub ironrdp_rdcleanpath::DetectionResult); - - impl RDCleanPathDetectionResult { - pub fn is_detected(&self) -> bool { - matches!(self.0, ironrdp_rdcleanpath::DetectionResult::Detected { .. }) - } - - pub fn is_not_enough_bytes(&self) -> bool { - matches!(self.0, ironrdp_rdcleanpath::DetectionResult::NotEnoughBytes) - } - - pub fn is_failed(&self) -> bool { - matches!(self.0, ironrdp_rdcleanpath::DetectionResult::Failed) - } - - pub fn get_total_length(&self) -> Result> { - if let ironrdp_rdcleanpath::DetectionResult::Detected { total_length, .. } = self.0 { - Ok(total_length) - } else { - Err(GenericError(anyhow::anyhow!("detection result is not Detected variant")).into()) - } - } - } - - #[diplomat::opaque] - pub struct CertificateChainIterator { - certs: Vec>, - index: usize, - } - - impl CertificateChainIterator { - pub fn next(&mut self) -> Option> { - if self.index < self.certs.len() { - let cert = self.certs[self.index].clone(); - self.index += 1; - Some(Box::new(VecU8(cert))) - } else { - None - } - } - - pub fn len(&self) -> usize { - self.certs.len() - } - - pub fn is_empty(&self) -> bool { - self.certs.is_empty() - } - } -} diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 5d8e890a..f1fe432d 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -63,9 +63,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base64ct" -version = "1.8.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bit_field" @@ -75,9 +75,9 @@ checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bitvec" @@ -108,9 +108,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.2.49" +version = "1.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" dependencies = [ "find-msvc-tools", "jobserver", @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "const-oid" @@ -150,9 +150,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", @@ -237,9 +237,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" [[package]] name = "flagset" @@ -249,9 +249,9 @@ checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -275,19 +275,19 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", "r-efi", - "wasip2", + "wasi", ] [[package]] name = "ironrdp-cliprdr" -version = "0.5.0" +version = "0.4.0" dependencies = [ "bitflags", "ironrdp-core", @@ -363,7 +363,7 @@ dependencies = [ [[package]] name = "ironrdp-graphics" -version = "0.7.0" +version = "0.6.0" dependencies = [ "bit_field", "bitflags", @@ -371,6 +371,7 @@ dependencies = [ "byteorder", "ironrdp-core", "ironrdp-pdu", + "lazy_static", "num-derive", "num-traits", "yuv", @@ -400,7 +401,7 @@ dependencies = [ [[package]] name = "ironrdp-rdpdr" -version = "0.5.0" +version = "0.4.1" dependencies = [ "bitflags", "ironrdp-core", @@ -441,10 +442,16 @@ dependencies = [ ] [[package]] -name = "libc" -version = "0.2.178" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libfuzzer-sys" @@ -458,9 +465,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "md-5" @@ -474,9 +481,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "minimal-lexical" @@ -580,18 +587,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -636,9 +643,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "slab" @@ -658,9 +665,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.111" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -686,18 +693,18 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", @@ -727,9 +734,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.43" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -739,9 +746,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.31" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", @@ -750,24 +757,24 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.35" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", ] [[package]] name = "typenum" -version = "1.19.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "version_check" @@ -775,6 +782,15 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -813,18 +829,18 @@ dependencies = [ [[package]] name = "yuv" -version = "0.8.9" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28f1bad143caadcfcaec93039dc9c40a30fc86f23d9e7cc03764a39fe51d9d43" +checksum = "c3bb136c6b36d2856e62f3121892ae59f32caf5b0a9ff184600f0f5f4d5ff075" dependencies = [ "num-traits", ] [[package]] name = "zeroize" -version = "1.8.2" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] diff --git a/release-plz.toml b/release-plz.toml index 8a33bf6f..79409f23 100644 --- a/release-plz.toml +++ b/release-plz.toml @@ -11,7 +11,6 @@ release_commits = "^(feat|docs|fix|build|perf)" [[package]] name = "ironrdp-client" git_release_enable = true -publish = false # TODO: enable publishing when ready. # ironrdp-tls does not compile if no backend is specified. # rustls is the most common backend, so we let cargo publish check with it. diff --git a/web-client/iron-remote-desktop-rdp/public/package.json b/web-client/iron-remote-desktop-rdp/public/package.json index 8fb1a386..fc788cfc 100644 --- a/web-client/iron-remote-desktop-rdp/public/package.json +++ b/web-client/iron-remote-desktop-rdp/public/package.json @@ -6,7 +6,7 @@ "Benoit Cortier" ], "description": "RDP backend for iron-remote-desktop", - "version": "0.6.1", + "version": "0.6.0", "main": "iron-remote-desktop-rdp.js", "types": "index.d.ts", "files": [ diff --git a/web-client/iron-remote-desktop/public/package.json b/web-client/iron-remote-desktop/public/package.json index d7e941ec..e35db50c 100644 --- a/web-client/iron-remote-desktop/public/package.json +++ b/web-client/iron-remote-desktop/public/package.json @@ -10,7 +10,7 @@ "Alexandr Yusuk" ], "description": "Backend-agnostic Web Component for remote desktop protocols", - "version": "0.10.1", + "version": "0.10.0", "main": "iron-remote-desktop.js", "types": "index.d.ts", "files": [ diff --git a/web-client/iron-remote-desktop/src/services/clipboard.service.ts b/web-client/iron-remote-desktop/src/services/clipboard.service.ts index 5bae0927..98c8e7cc 100644 --- a/web-client/iron-remote-desktop/src/services/clipboard.service.ts +++ b/web-client/iron-remote-desktop/src/services/clipboard.service.ts @@ -149,6 +149,7 @@ export class ClipboardService { if (!clipboardData.isEmpty()) { this.lastSentClipboardData = clipboardData; + // TODO(Fix): onClipboardChanged takes an ownership over clipboardData, so lastSentClipboardData will be nullptr. await this.remoteDesktopService.onClipboardChanged(clipboardData); } } @@ -191,6 +192,7 @@ export class ClipboardService { // This callback is required to send initial clipboard state if available. private onForceClipboardUpdate() { + // TODO(Fix): lastSentClipboardData is nullptr. try { if (this.lastSentClipboardData) { this.remoteDesktopService.onClipboardChanged(this.lastSentClipboardData); @@ -311,6 +313,7 @@ export class ClipboardService { if (!clipboardData.isEmpty()) { this.lastSentClipboardData = clipboardData; + // TODO(Fix): onClipboardChanged takes an ownership over clipboardData, so lastSentClipboardData will be nullptr. await this.remoteDesktopService.onClipboardChanged(clipboardData); } } @@ -403,6 +406,7 @@ export class ClipboardService { if (!clipboardData.isEmpty()) { this.lastSentClipboardData = clipboardData; + // TODO(Fix): onClipboardChanged takes an ownership over clipboardData, so lastSentClipboardData will be nullptr. await this.remoteDesktopService.onClipboardChanged(clipboardData); } } diff --git a/xtask/src/cov.rs b/xtask/src/cov.rs index 50e073ab..f522db52 100644 --- a/xtask/src/cov.rs +++ b/xtask/src/cov.rs @@ -328,11 +328,8 @@ fn get_json_float(value: &tinyjson::JsonValue, key: &str) -> anyhow::Result } fn get_json_int(value: &tinyjson::JsonValue, key: &str) -> anyhow::Result { - #[expect( - clippy::as_conversions, - clippy::cast_sign_loss, - clippy::cast_possible_truncation, - reason = "tinyjson does not expose any integers at all, so we need the f64 to u64 as casting" - )] + // tinyjson does not expose any integers at all, so we need the f64 to u64 as casting + #[expect(clippy::cast_sign_loss)] + #[expect(clippy::cast_possible_truncation)] get_json_float(value, key).map(|value| value as u64) }