diff --git a/.gitlab-ci-templates.yml b/.gitlab-ci-templates.yml index a146a6db2..9fddc67e9 100644 --- a/.gitlab-ci-templates.yml +++ b/.gitlab-ci-templates.yml @@ -1,14 +1,22 @@ .test_execution_script: stage: ui-test - dependencies: - - build-installer + needs: + - job: build-installer-debug-x64 + optional: true + - job: build-installer-release-x64 + optional: true + hooks: + pre_get_sources_script: + - Get-Process | Where-Object { $_.Name -like "proton*" } | Stop-Process -Force tags: - e2e-tests - script: + before_script: - ci\test-scripts\uninstall-app.ps1 + script: - ci\test-scripts\install-the-app.ps1 - dotnet build src/Tests/ProtonVPN.UI.Tests/ProtonVPN.UI.Tests.csproj --arch x64 -o src/bin - VSTest.Console.exe src\bin\ProtonVPN.UI.Tests.dll /Settings:ci/test-scripts/TestRun/test-run-settings.xml /TestCaseFilter:"Category=${CATEGORY}" + after_script: - ci\test-scripts\uninstall-app.ps1 artifacts: when: always @@ -24,21 +32,21 @@ script: - echo "Building native dependencies..." - nuget restore ProtonVPN.InstallActions.sln - - cmd.exe /c BuildDependencies.bat $DEPENDENCIES + - cmd.exe /c BuildDependencies.bat ${DEPENDENCIES} - python ci\build-scripts\main.py add-commit-hash $env:CI_COMMIT_SHORT_SHA - python ci\build-scripts\main.py defaultConfig - dotnet build src\Builds\ProtonVPN.Builds.ConsoleJob\ProtonVPN.Builds.ConsoleJob.csproj - echo "Injecting CI variables" - src\bin\ProtonVPN.Builds.ConsoleJob.exe - echo "Publishing ${TYPE}..." - - dotnet publish src/ProtonVPN.App/ProtonVPN.App.csproj -c ${TYPE} -r win-x64 --self-contained -o $BUILD_PATH - - dotnet publish src/ProtonVPN.Service/ProtonVPN.Service.csproj -c ${TYPE} -r win-x64 --self-contained -o $BUILD_PATH - - dotnet publish src/ProtonVPN.WireguardService/ProtonVPN.WireguardService.csproj -c ${TYPE} -r win-x64 --self-contained -o $BUILD_PATH - - dotnet publish src/ProtonVPN.TlsVerify/ProtonVPN.TlsVerify.csproj -c ${TYPE} -r win-x64 --self-contained -o $BUILD_PATH - - dotnet publish src/ProtonVPN.Launcher/ProtonVPN.Launcher.csproj -c ${TYPE} -r win-x64 --self-contained -o $BUILD_PATH - - dotnet publish src/ProtonVPN.RestoreInternet/ProtonVPN.RestoreInternet.csproj -c ${TYPE} -r win-x64 --self-contained -o $BUILD_PATH - - dotnet publish src/ProtonDrive.Downloader/ProtonDrive.Downloader.csproj -c ${TYPE} -r win-x64 --self-contained -o $BUILD_PATH - - msbuild src\ProtonVPN.NativeHost\NativeHost.vcxproj /p:Configuration=Release /p:Platform=x64 + - dotnet publish src/ProtonVPN.App/ProtonVPN.App.csproj -c ${TYPE} -r win-${PLATFORM} --self-contained -o $BUILD_PATH + - dotnet publish src/ProtonVPN.Service/ProtonVPN.Service.csproj -c ${TYPE} -r win-${PLATFORM} --self-contained -o $BUILD_PATH + - dotnet publish src/ProtonVPN.WireguardService/ProtonVPN.WireguardService.csproj -c ${TYPE} -r win-${PLATFORM} --self-contained -o $BUILD_PATH + - dotnet publish src/ProtonVPN.TlsVerify/ProtonVPN.TlsVerify.csproj -c ${TYPE} -r win-${PLATFORM} --self-contained -o $BUILD_PATH + - dotnet publish src/ProtonVPN.Launcher/ProtonVPN.Launcher.csproj -c ${TYPE} -r win-${PLATFORM} --self-contained -o $BUILD_PATH + - dotnet publish src/ProtonVPN.RestoreInternet/ProtonVPN.RestoreInternet.csproj -c ${TYPE} -r win-${PLATFORM} --self-contained -o $BUILD_PATH + - dotnet publish src/ProtonInstaller/ProtonInstaller.csproj -c ${TYPE} -r win-${PLATFORM} --self-contained -o $BUILD_PATH + - msbuild src\ProtonVPN.NativeHost\NativeHost.vcxproj /p:Configuration=Release /p:Platform=${PLATFORM} artifacts: expire_in: 1 day paths: @@ -53,7 +61,7 @@ - windows-vpn-signer script: - python ci\build-scripts\main.py update-gh-list - - python ci\build-scripts\main.py app-installer $env:CI_COMMIT_SHORT_SHA + - python ci\build-scripts\main.py app-installer $env:CI_COMMIT_SHORT_SHA ${PLATFORM} artifacts: paths: - Setup/Installers/ @@ -64,3 +72,24 @@ ARTIFACT_COMPRESSION_LEVEL: "fastest" CACHE_COMPRESSION_LEVEL: "fastest" FASTZIP_ARCHIVER_BUFFER_SIZE: 128 + +.tests: + stage: test + script: + - cmd.exe /c BuildDependencies.bat bin + - dotnet build src\Builds\ProtonVPN.Builds.ConsoleJob\ProtonVPN.Builds.ConsoleJob.csproj + - echo "Injecting CI variables" + - src\bin\ProtonVPN.Builds.ConsoleJob.exe + - dotnet restore ProtonVpn.sln + - dotnet build ProtonVpn.sln + - coverlet src\bin --target "dotnet" --targetargs "test ProtonVpn.sln -l ""console;verbosity=normal"" --filter ""TestCategory!=UI&TestCategory!=Connection&TestCategory!=Performance&TestCategory!=BTI"" --no-restore --no-build" --format cobertura --output .\coverage-reports --exclude "[*.Tests*]*" --exclude "[ProtonVPN.MarkupValidator]*" --exclude "[TestTools*]*" --exclude "[*.Installers]*" + - powershell -Command "(gc coverage-reports.cobertura.xml) -replace '\\', '/' | Out-File -encoding UTF8 cobertura.xml" + - ReportGenerator.exe "-reports:cobertura.xml" "-targetdir:.\code-coverage-report-html" + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: cobertura.xml + coverage: '/Total.*?([0-9]{1,3}.[0-9]{1,3})%/' + variables: + GOSRPONLY: "true" \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 744e916a4..10a648150 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,8 +24,8 @@ include: product: vpn platform: windows artifact_list: "" - artifact_metadata_path: /windows - artifact_metadata_list: ../windows-releases.json + artifact_metadata_path: "" + artifact_metadata_list: "" variables: PUBLIC_REPO_URL: git@github.com:ProtonVPN/win-app.git @@ -55,7 +55,7 @@ stages: - test-cleanup - mirror -build-release: +build-release-x64: extends: .build-script only: - master @@ -63,9 +63,23 @@ build-release: variables: TYPE: Release DEPENDENCIES: publish + PLATFORM: x64 BUILD_PATH: src/bin/win-x64/publish -build-bti: +build-release-arm64: + extends: .build-script + only: + - master + - /^release.*$/ + tags: + - windows-arm64 + variables: + TYPE: Release + DEPENDENCIES: publish + PLATFORM: arm64 + BUILD_PATH: src/bin/win-arm64/publish + +build-bti-x64: rules: - if: '$CI_COMMIT_BRANCH == "master"' when: never @@ -82,10 +96,11 @@ build-bti: when: manual variables: TYPE: Debug + PLATFORM: x64 DEPENDENCIES: publish-BTI BUILD_PATH: src/bin/win-x64/BTI/publish - -build-debug: + +build-debug-x64: extends: .build-script except: - master @@ -93,9 +108,42 @@ build-debug: - schedules variables: TYPE: Debug + PLATFORM: x64 DEPENDENCIES: publish BUILD_PATH: src/bin/win-x64/publish +build-debug-arm64: + extends: .build-script + when: manual + except: + - master + - /^release.*$/ + - schedules + tags: + - windows-arm64 + variables: + TYPE: Debug + PLATFORM: arm64 + DEPENDENCIES: publish + BUILD_PATH: src/bin/win-arm64/publish + +full-ui-tests-arm: + tags: + - windows-arm64-ui + extends: .test_execution_script + needs: + - job: build-installer-debug-arm64 + optional: true + - job: build-installer-release-arm64 + optional: true + except: + - /^debug.*$/ + - release/9.9.9 + - master + - schedules + variables: + CATEGORY: "ARM" + ui-test: extends: .test_execution_script except: @@ -105,7 +153,7 @@ ui-test: - schedules variables: CATEGORY: "UI" - + connection-test: extends: .test_execution_script except: @@ -115,11 +163,11 @@ connection-test: - schedules variables: CATEGORY: "Connection" - + bti-test: extends: .test_execution_script needs: - - build-BTI-installer + - build-BTI-installer-x64 rules: - if: '$CI_COMMIT_BRANCH == "master"' when: never @@ -133,64 +181,119 @@ bti-test: tags: - BTI dependencies: - - build-BTI-installer + - build-BTI-installer-x64 variables: CATEGORY: "BTI" after_script: - ci\test-scripts\alert-failure.ps1 - -win-11-test: - extends: .test_execution_script - when: manual + +tests-x64-debug: + tags: + - windows-dot-net + extends: + - .tests except: - - /^debug.*$/ - - release/9.9.9 - master + - /^release.*$/ - schedules - tags: - - win11 + needs: + - build-debug-x64 variables: - CATEGORY: "Smoke" + PLATFORM: x64 -tests: - stage: test +tests-x64-release: tags: - windows-dot-net - script: - - cmd.exe /c BuildDependencies.bat bin gosrponly - - dotnet build src\Builds\ProtonVPN.Builds.ConsoleJob\ProtonVPN.Builds.ConsoleJob.csproj - - echo "Injecting CI variables" - - src\bin\ProtonVPN.Builds.ConsoleJob.exe - - dotnet restore ProtonVpn.sln - - dotnet build ProtonVpn.sln - - coverlet src\bin --target "dotnet" --targetargs "test ProtonVpn.sln -l ""console;verbosity=normal"" --filter ""TestCategory!=UI&TestCategory!=Connection&TestCategory!=Performance&TestCategory!=BTI"" --no-restore --no-build" --format cobertura --output .\coverage-reports --exclude "[*.Tests*]*" --exclude "[ProtonVPN.MarkupValidator]*" --exclude "[TestTools*]*" --exclude "[*.Installers]*" - - powershell -Command "(gc coverage-reports.cobertura.xml) -replace '\\', '/' | Out-File -encoding UTF8 cobertura.xml" - - ReportGenerator.exe "-reports:cobertura.xml" "-targetdir:.\code-coverage-report-html" + extends: + - .tests + only: + - master + - /^release.*$/ + needs: + - build-release-x64 + variables: + PLATFORM: x64 + +tests-arm64-debug: + tags: + - windows-arm64 + extends: + - .tests except: + - master + - /^release.*$/ - schedules - artifacts: - reports: - coverage_report: - coverage_format: cobertura - path: cobertura.xml - coverage: '/Total.*?([0-9]{1,3}.[0-9]{1,3})%/' + needs: + - build-debug-arm64 + variables: + PLATFORM: arm64 -build-installer: +tests-arm64-release: tags: - - windows-vpn-signer - dependencies: - - build-debug - - build-release + - windows-arm64 + extends: + - .tests + only: + - master + - /^release.*$/ + needs: + - build-release-arm64 + variables: + PLATFORM: arm64 + +build-installer-release-x64: + needs: + - build-release-x64 + extends: + - .build-installer + only: + - master + - /^release.*$/ + variables: + BUILD_PATH: src/bin/win-x64/publish + PLATFORM: x64 + +build-installer-debug-x64: + needs: + - build-debug-x64 extends: - .build-installer except: + - master + - /^release.*$/ - schedules variables: BUILD_PATH: src/bin/win-x64/publish + PLATFORM: x64 + +build-installer-debug-arm64: + needs: + - build-debug-arm64 + extends: + - .build-installer + except: + - master + - /^release.*$/ + - schedules + variables: + BUILD_PATH: src/bin/win-arm64/publish + PLATFORM: arm64 + +build-installer-release-arm64: + needs: + - build-release-arm64 + extends: + - .build-installer + only: + - master + - /^release.*$/ + variables: + BUILD_PATH: src/bin/win-arm64/publish + PLATFORM: arm64 -build-BTI-installer: +build-BTI-installer-x64: needs: - - build-bti + - build-bti-x64 except: - master - /^release.*$/ @@ -198,7 +301,8 @@ build-BTI-installer: - .build-installer variables: BUILD_PATH: src/bin/win-x64/BTI/publish - + PLATFORM: x64 + prepare-internal-beta-release: stage: internal-beta tags: @@ -209,7 +313,7 @@ prepare-internal-beta-release: - python ci\test-scripts\prepare-internal-beta.py only: - /^release.*$/ - + mirror: stage: mirror tags: @@ -278,12 +382,15 @@ send-slack-notification: generate-release-artifacts: stage: generate image: harbor.protontech.ch/docker.io/library/alpine:3.20 + needs: + - build-installer-release-x64 + - build-installer-release-arm64 tags: - shared-small script: - set -ex - export RELEASE_VERSION="${CI_COMMIT_BRANCH##release/}" && echo "RELEASE_VERSION=${RELEASE_VERSION}" | tee release.env - - echo "ARTIFACT_LIST=ProtonVPN_v${RELEASE_VERSION}.exe" | tee -a release.env + - echo "ARTIFACT_LIST=ProtonVPN_v${RELEASE_VERSION}_x64.exe ProtonVPN_v${RELEASE_VERSION}_arm64.exe" | tee -a release.env artifacts: reports: dotenv: release.env @@ -299,6 +406,12 @@ artifactlift-release-artifacts: - when: never release-binary-to-nexus: + needs: + - generate-release-artifacts + - job: build-installer-release-x64 + artifacts: true + - job: build-installer-release-arm64 + artifacts: true extends: artifactlift-release-candidate-artifacts rules: - if: '$CI_COMMIT_BRANCH == "release/9.9.9"' @@ -309,6 +422,10 @@ release-binary-to-nexus: release-binary-to-prod: extends: artifactlift-release-artifacts + needs: + - job: generate-release-artifacts + artifacts: true + - release-binary-to-nexus rules: - if: '$CI_COMMIT_BRANCH == "release/9.9.9"' when: never diff --git a/BuildDependencies.bat b/BuildDependencies.bat index 0810b5b2e..e96f0eeed 100644 --- a/BuildDependencies.bat +++ b/BuildDependencies.bat @@ -1,24 +1,51 @@ @echo off +if not defined PLATFORM ( + set PLATFORM=x64 +) + set currentDir=%~dp0 -set publishDir=%currentDir%src\bin\win-x64\publish\ -set publishDirBTI=%currentDir%src\bin\win-x64\BTI\publish\ +set publishDir=%currentDir%src\bin\win-%PLATFORM%\publish\ +set publishDirBTI=%currentDir%src\bin\win-%PLATFORM%\BTI\publish\ set binDir=%currentDir%src\bin\ -set resourcesDir=%binDir%Resources +set resourcesDir=%binDir%Resources\ if "%~1"=="publish" ( - set resourcesDir=%publishDir%Resources + set resourcesDir=%publishDir%Resources\ ) if "%~1"=="publish-BTI" ( - set resourcesDir=%publishDirBTI%Resources + set resourcesDir=%publishDirBTI%Resources\ +) + +if "%PLATFORM%"=="x64" ( + xcopy %currentDir%Setup\Native\x64\wireguard.dll %binDir% /y + xcopy %currentDir%Setup\Native\x64\tunnel.dll %binDir% /y + xcopy %currentDir%Setup\Native\x64\wireguard-tunnel-tcp.dll %binDir% /y + xcopy %currentDir%Setup\Native\x64\wintun.dll %binDir% /y + xcopy %currentDir%Setup\Native\x64\libcrypto-3-x64.dll %resourcesDir% /y + xcopy %currentDir%Setup\Native\x64\libpkcs11-helper-1.dll %resourcesDir% /y + xcopy %currentDir%Setup\Native\x64\libssl-3-x64.dll %resourcesDir% /y + xcopy %currentDir%Setup\Native\x64\openvpn.exe %resourcesDir% /y + xcopy %currentDir%Setup\Native\x64\vcruntime140.dll %resourcesDir% /y +) + +if "%PLATFORM%"=="arm64" ( + xcopy %currentDir%Setup\Native\arm64\wireguard.dll %binDir% /y + xcopy %currentDir%Setup\Native\arm64\tunnel.dll %binDir% /y + xcopy %currentDir%Setup\Native\arm64\wireguard-tunnel-tcp.dll %binDir% /y + xcopy %currentDir%Setup\Native\arm64\wintun.dll %binDir% /y + xcopy %currentDir%Setup\Native\arm64\libcrypto-3-arm64.dll %resourcesDir% /y + xcopy %currentDir%Setup\Native\arm64\libpkcs11-helper-1.dll %resourcesDir% /y + xcopy %currentDir%Setup\Native\arm64\libssl-3-arm64.dll %resourcesDir% /y + xcopy %currentDir%Setup\Native\arm64\openvpn.exe %resourcesDir% /y ) set buildParams=/p:PlatformToolset=v143 /p:Configuration=Release /p:OutDir=%resourcesDir% /clp:ErrorsOnly set x86buildParams=%buildParams% /p:Platform=Win32 -set x64buildParams=%buildParams% /p:Platform=x64 +set x64buildParams=%buildParams% /p:Platform=%PLATFORM% -if "%~2" NEQ "gosrponly" ( +if not defined GOSRPONLY ( echo compiling ProtonVPN.IPFilter.dll msbuild src\ProtonVPN.IpFilter\ProtonVPN.IpFilter.vcxproj %x64buildParams% || exit /b %ERRORLEVEL% @@ -32,20 +59,50 @@ if "%~2" NEQ "gosrponly" ( msbuild src\ProtonVPN.InstallActions\ProtonVPN.InstallActions.vcxproj %x64buildParams% || exit /b %ERRORLEVEL% echo compiling LocalAgent.dll - pushd %currentDir%src\ProtonVPN.LocalAgent\localAgentWin - set GO111MODULE=off - set CGO_CFLAGS=-O3 -Wall -Wno-unused-function -Wno-switch -std=gnu11 -DWINVER=0x0601 + + if "%PLATFORM%"=="x64" ( + pushd %currentDir%src\ProtonVPN.LocalAgent\localAgentWin + set GO111MODULE=off + set CGO_CFLAGS=-O3 -Wall -Wno-unused-function -Wno-switch -std=gnu11 -DWINVER=0x0601 - go build -buildmode c-shared -ldflags="-w -s" -trimpath -v -o %resourcesDir%\LocalAgent.dll - if %ERRORLEVEL% equ 0 ( - echo file saved %resourcesDir%\LocalAgent.dll + go build -buildmode c-shared -ldflags="-w -s" -trimpath -v -o %resourcesDir%LocalAgent.dll + if %ERRORLEVEL% equ 0 ( + echo file saved %resourcesDir%LocalAgent.dll + ) + ) + + if "%PLATFORM%"=="arm64" ( + docker run --rm ^ + -e GOARCH="arm64" ^ + -e GOOS="windows" ^ + -e GO111MODULE="off" ^ + -v %currentDir%\src\ProtonVPN.LocalAgent:/go/work ^ + -w /go/work/localAgentWin x1unix/go-mingw:1.23 ^ + go build -buildmode c-shared -ldflags="-w -s" -trimpath -v -o LocalAgent.dll . + + xcopy %currentDir%src\ProtonVPN.LocalAgent\localAgentWin\LocalAgent.dll %resourcesDir% /y ) ) echo compiling GoSrp.dll -pushd %currentDir%src\srp\windows\cshared -set GO111MODULE=on -go build -buildmode=c-shared -v -ldflags="-s -w" -o %resourcesDir%\GoSrp.dll main.go -if %ERRORLEVEL% equ 0 ( - echo file saved %resourcesDir%\GoSrp.dll + +if "%PLATFORM%"=="x64" ( + pushd %currentDir%src\srp\windows\cshared + set GO111MODULE=on + go build -buildmode=c-shared -v -ldflags="-s -w" -o %resourcesDir%GoSrp.dll main.go + if %ERRORLEVEL% equ 0 ( + echo file saved %resourcesDir%GoSrp.dll + ) +) + +if "%PLATFORM%"=="arm64" ( + docker run --rm ^ + -e GOARCH="arm64" ^ + -e GOOS="windows" ^ + -e GO111MODULE="on" ^ + -v %currentDir%\src\srp:/go/work ^ + -w /go/work/windows/cshared x1unix/go-mingw:1.23 ^ + go build -buildmode c-shared -ldflags="-w -s" -trimpath -v -o GoSrp.dll main.go + + xcopy %currentDir%src\srp\windows\cshared\GoSrp.dll %resourcesDir% /y ) \ No newline at end of file diff --git a/ProtonVpn.sln b/ProtonVpn.sln index f8c55ab61..4473f983a 100644 --- a/ProtonVpn.sln +++ b/ProtonVpn.sln @@ -109,26 +109,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.Announcements.Tes EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProcessCommunication", "ProcessCommunication", "{7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Contracts", "src\ProcessCommunication\ProtonVPN.ProcessCommunication.Contracts\ProtonVPN.ProcessCommunication.Contracts.csproj", "{8CEF18CA-9009-47F5-ADF4-63E73E6B663B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Common", "src\ProcessCommunication\ProtonVPN.ProcessCommunication.Common\ProtonVPN.ProcessCommunication.Common.csproj", "{E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Service", "Service", "{AF9F8787-E233-4DBF-B973-916EBCD88D96}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{A4955C19-C422-45E6-9F01-5AE2E9A76B2F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Service", "src\ProcessCommunication\Service\ProtonVPN.ProcessCommunication.Service\ProtonVPN.ProcessCommunication.Service.csproj", "{321C6410-B154-45BD-B44A-7CD451BBA9F0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Service.Installers", "src\ProcessCommunication\Service\ProtonVPN.ProcessCommunication.Service.Installers\ProtonVPN.ProcessCommunication.Service.Installers.csproj", "{076A3785-83CD-4AE3-BE45-1AE183587731}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Service.Tests", "src\ProcessCommunication\Service\ProtonVPN.ProcessCommunication.Service.Tests\ProtonVPN.ProcessCommunication.Service.Tests.csproj", "{0997005B-E6FF-4D3F-AACE-C29338C7977F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.App", "src\ProcessCommunication\App\ProtonVPN.ProcessCommunication.App\ProtonVPN.ProcessCommunication.App.csproj", "{15F67655-8025-4389-8FF7-3F3CA7F543DA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.App.Installers", "src\ProcessCommunication\App\ProtonVPN.ProcessCommunication.App.Installers\ProtonVPN.ProcessCommunication.App.Installers.csproj", "{1BCFC9AF-6570-4996-949D-3C45F3411712}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.App.Tests", "src\ProcessCommunication\App\ProtonVPN.ProcessCommunication.App.Tests\ProtonVPN.ProcessCommunication.App.Tests.csproj", "{219FADE8-5473-4099-8291-7C29AA6F4808}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EntityMapping", "EntityMapping", "{E85D3982-0792-430A-9E58-8B7C1A329F88}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.EntityMapping.Contracts", "src\EntityMapping\ProtonVPN.EntityMapping.Contracts\ProtonVPN.EntityMapping.Contracts.csproj", "{BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}" @@ -137,16 +117,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.EntityMapping", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.EntityMapping.Installers", "src\EntityMapping\ProtonVPN.EntityMapping.Installers\ProtonVPN.EntityMapping.Installers.csproj", "{D5596914-F824-45DD-9496-3D8A7FAD5796}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.EntityMapping", "src\ProcessCommunication\ProtonVPN.ProcessCommunication.EntityMapping\ProtonVPN.ProcessCommunication.EntityMapping.csproj", "{32817833-F567-4A92-BB57-8579A1D81DBA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Installers", "src\ProcessCommunication\ProtonVPN.ProcessCommunication.Installers\ProtonVPN.ProcessCommunication.Installers.csproj", "{354CB379-4F37-4C57-B71C-916257B7B328}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Common.Tests", "src\ProcessCommunication\ProtonVPN.ProcessCommunication.Common.Tests\ProtonVPN.ProcessCommunication.Common.Tests.csproj", "{E635ECAF-7338-4B82-A606-CAFEDCC11D6E}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.EntityMapping.Tests", "src\EntityMapping\ProtonVPN.EntityMapping.Tests\ProtonVPN.EntityMapping.Tests.csproj", "{9FAB310D-BB12-42A9-9E09-6762DF98DA0F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.EntityMapping.Tests", "src\ProcessCommunication\ProtonVPN.ProcessCommunication.EntityMapping.Tests\ProtonVPN.ProcessCommunication.EntityMapping.Tests.csproj", "{99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.Launcher", "src\ProtonVPN.Launcher\ProtonVPN.Launcher.csproj", "{1CE13B94-7AD5-49A5-802C-945D34903C23}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Update", "Update", "{7B4E6671-D28C-4159-BB16-40CEAC76EE73}" @@ -197,916 +169,1346 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.Logging.Events", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.RestoreInternet", "src\ProtonVPN.RestoreInternet\ProtonVPN.RestoreInternet.csproj", "{9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProtonInstaller", "ProtonInstaller", "{DBBD9699-0909-4E8C-98BA-1CE8C25381D3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonInstaller", "src\ProtonInstaller\ProtonInstaller.csproj", "{344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Installers", "src\ProcessCommunication\ProtonVPN.ProcessCommunication.Installers\ProtonVPN.ProcessCommunication.Installers.csproj", "{1C83BBB0-A89A-408D-9303-54C556BB5935}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.EntityMapping.Tests", "src\ProcessCommunication\ProtonVPN.ProcessCommunication.EntityMapping.Tests\ProtonVPN.ProcessCommunication.EntityMapping.Tests.csproj", "{55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.EntityMapping", "src\ProcessCommunication\ProtonVPN.ProcessCommunication.EntityMapping\ProtonVPN.ProcessCommunication.EntityMapping.csproj", "{9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Contracts", "src\ProcessCommunication\ProtonVPN.ProcessCommunication.Contracts\ProtonVPN.ProcessCommunication.Contracts.csproj", "{870F3B44-FDA4-460F-A102-17C15F4373E5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{92A18CCE-33CE-4986-80CD-B27131A77F77}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Common", "src\ProcessCommunication\Common\ProtonVPN.ProcessCommunication.Common\ProtonVPN.ProcessCommunication.Common.csproj", "{4C7525B9-1B55-429E-92AC-04248BC1247C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{1812EACD-7CF3-463A-BEAB-7C3650A5FF01}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Client", "src\ProcessCommunication\Client\ProtonVPN.ProcessCommunication.Client\ProtonVPN.ProcessCommunication.Client.csproj", "{CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Client.Installers", "src\ProcessCommunication\Client\ProtonVPN.ProcessCommunication.Client.Installers\ProtonVPN.ProcessCommunication.Client.Installers.csproj", "{55B42F87-2CA6-46BA-BCBE-513D4EF7F178}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{8398224D-0FB2-4E68-8095-5530531BA561}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Server", "src\ProcessCommunication\Server\ProtonVPN.ProcessCommunication.Server\ProtonVPN.ProcessCommunication.Server.csproj", "{230E0930-C155-4433-A64F-C9BF77A7086D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.ProcessCommunication.Server.Installers", "src\ProcessCommunication\Server\ProtonVPN.ProcessCommunication.Server.Installers\ProtonVPN.ProcessCommunication.Server.Installers.csproj", "{71D82911-0F26-46F8-9D14-7F564AEBF6DD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OperatingSystems", "OperatingSystems", "{21A233DF-8DB7-4299-BE46-2AD4AC2655DB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Registries", "Registries", "{8ADCEED2-41BD-47F8-BD49-5F1C3F3C748B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.OperatingSystems.Registries", "src\OperatingSystems\Registries\ProtonVPN.OperatingSystems.Registries\ProtonVPN.OperatingSystems.Registries.csproj", "{30469297-B321-41B8-B594-7D84BEE3DF45}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.OperatingSystems.Registries.Contracts", "src\OperatingSystems\Registries\ProtonVPN.OperatingSystems.Registries.Contracts\ProtonVPN.OperatingSystems.Registries.Contracts.csproj", "{7C258EBD-7ECA-4F4D-8618-40704DFCD16F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.OperatingSystems.Registries.Installers", "src\OperatingSystems\Registries\ProtonVPN.OperatingSystems.Registries.Installers\ProtonVPN.OperatingSystems.Registries.Installers.csproj", "{7AB9D305-664C-463D-91F9-3DBD1379F9F3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Processes", "Processes", "{3E7A8ABD-6F8D-4EA0-BE9F-C77FD5ECC1B3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.OperatingSystems.Processes", "src\OperatingSystems\Processes\ProtonVPN.OperatingSystems.Processes\ProtonVPN.OperatingSystems.Processes.csproj", "{3CEBC034-C137-484F-827A-B6B190497DCD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.OperatingSystems.Processes.Contracts", "src\OperatingSystems\Processes\ProtonVPN.OperatingSystems.Processes.Contracts\ProtonVPN.OperatingSystems.Processes.Contracts.csproj", "{F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.OperatingSystems.Processes.Installers", "src\OperatingSystems\Processes\ProtonVPN.OperatingSystems.Processes.Installers\ProtonVPN.OperatingSystems.Processes.Installers.csproj", "{1F1204ED-F445-4888-8171-4C06ED7CAABD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtonVPN.EntityMapping.Common.Installers", "src\EntityMapping\ProtonVPN.EntityMapping.Common.Installers\ProtonVPN.EntityMapping.Common.Installers.csproj", "{C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|ARM64 = Debug|ARM64 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|ARM64 = Release|ARM64 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Debug|ARM64.Build.0 = Debug|ARM64 {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Debug|x64.ActiveCfg = Debug|Any CPU {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Debug|x64.Build.0 = Debug|Any CPU {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Debug|x86.ActiveCfg = Debug|Any CPU {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Debug|x86.Build.0 = Debug|Any CPU {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Release|Any CPU.ActiveCfg = Release|Any CPU {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Release|Any CPU.Build.0 = Release|Any CPU + {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Release|ARM64.ActiveCfg = Release|ARM64 + {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Release|ARM64.Build.0 = Release|ARM64 {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Release|x64.ActiveCfg = Release|Any CPU {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Release|x64.Build.0 = Release|Any CPU {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Release|x86.ActiveCfg = Release|Any CPU {0CDCA012-BB2D-49B3-944E-CE80D75D651A}.Release|x86.Build.0 = Release|Any CPU {25781B52-5858-4387-80A5-C9C38C32B3CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {25781B52-5858-4387-80A5-C9C38C32B3CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25781B52-5858-4387-80A5-C9C38C32B3CC}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {25781B52-5858-4387-80A5-C9C38C32B3CC}.Debug|ARM64.Build.0 = Debug|ARM64 {25781B52-5858-4387-80A5-C9C38C32B3CC}.Debug|x64.ActiveCfg = Debug|Any CPU {25781B52-5858-4387-80A5-C9C38C32B3CC}.Debug|x64.Build.0 = Debug|Any CPU {25781B52-5858-4387-80A5-C9C38C32B3CC}.Debug|x86.ActiveCfg = Debug|Any CPU {25781B52-5858-4387-80A5-C9C38C32B3CC}.Debug|x86.Build.0 = Debug|Any CPU {25781B52-5858-4387-80A5-C9C38C32B3CC}.Release|Any CPU.ActiveCfg = Release|Any CPU {25781B52-5858-4387-80A5-C9C38C32B3CC}.Release|Any CPU.Build.0 = Release|Any CPU + {25781B52-5858-4387-80A5-C9C38C32B3CC}.Release|ARM64.ActiveCfg = Release|ARM64 + {25781B52-5858-4387-80A5-C9C38C32B3CC}.Release|ARM64.Build.0 = Release|ARM64 {25781B52-5858-4387-80A5-C9C38C32B3CC}.Release|x64.ActiveCfg = Release|Any CPU {25781B52-5858-4387-80A5-C9C38C32B3CC}.Release|x64.Build.0 = Release|Any CPU {25781B52-5858-4387-80A5-C9C38C32B3CC}.Release|x86.ActiveCfg = Release|Any CPU {25781B52-5858-4387-80A5-C9C38C32B3CC}.Release|x86.Build.0 = Release|Any CPU {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Debug|ARM64.Build.0 = Debug|ARM64 {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Debug|x64.ActiveCfg = Debug|Any CPU {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Debug|x64.Build.0 = Debug|Any CPU {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Debug|x86.ActiveCfg = Debug|Any CPU {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Debug|x86.Build.0 = Debug|Any CPU {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Release|Any CPU.ActiveCfg = Release|Any CPU {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Release|Any CPU.Build.0 = Release|Any CPU + {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Release|ARM64.ActiveCfg = Release|ARM64 + {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Release|ARM64.Build.0 = Release|ARM64 {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Release|x64.ActiveCfg = Release|Any CPU {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Release|x64.Build.0 = Release|Any CPU {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Release|x86.ActiveCfg = Release|Any CPU {CA44B51D-7645-413A-818F-2C5B57DB67DD}.Release|x86.Build.0 = Release|Any CPU {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Debug|ARM64.Build.0 = Debug|ARM64 {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Debug|x64.ActiveCfg = Debug|Any CPU {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Debug|x64.Build.0 = Debug|Any CPU {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Debug|x86.ActiveCfg = Debug|Any CPU {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Debug|x86.Build.0 = Debug|Any CPU {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Release|Any CPU.ActiveCfg = Release|Any CPU {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Release|Any CPU.Build.0 = Release|Any CPU + {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Release|ARM64.ActiveCfg = Release|ARM64 + {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Release|ARM64.Build.0 = Release|ARM64 {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Release|x64.ActiveCfg = Release|Any CPU {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Release|x64.Build.0 = Release|Any CPU {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Release|x86.ActiveCfg = Release|Any CPU {FA0D86B4-2B86-4DFE-B7E6-7C809DB74A13}.Release|x86.Build.0 = Release|Any CPU {7F48FD5C-A4C6-496A-B68E-265237C22330}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7F48FD5C-A4C6-496A-B68E-265237C22330}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F48FD5C-A4C6-496A-B68E-265237C22330}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7F48FD5C-A4C6-496A-B68E-265237C22330}.Debug|ARM64.Build.0 = Debug|ARM64 {7F48FD5C-A4C6-496A-B68E-265237C22330}.Debug|x64.ActiveCfg = Debug|Any CPU {7F48FD5C-A4C6-496A-B68E-265237C22330}.Debug|x64.Build.0 = Debug|Any CPU {7F48FD5C-A4C6-496A-B68E-265237C22330}.Debug|x86.ActiveCfg = Debug|Any CPU {7F48FD5C-A4C6-496A-B68E-265237C22330}.Debug|x86.Build.0 = Debug|Any CPU {7F48FD5C-A4C6-496A-B68E-265237C22330}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F48FD5C-A4C6-496A-B68E-265237C22330}.Release|Any CPU.Build.0 = Release|Any CPU + {7F48FD5C-A4C6-496A-B68E-265237C22330}.Release|ARM64.ActiveCfg = Release|ARM64 + {7F48FD5C-A4C6-496A-B68E-265237C22330}.Release|ARM64.Build.0 = Release|ARM64 {7F48FD5C-A4C6-496A-B68E-265237C22330}.Release|x64.ActiveCfg = Release|Any CPU {7F48FD5C-A4C6-496A-B68E-265237C22330}.Release|x64.Build.0 = Release|Any CPU {7F48FD5C-A4C6-496A-B68E-265237C22330}.Release|x86.ActiveCfg = Release|Any CPU {7F48FD5C-A4C6-496A-B68E-265237C22330}.Release|x86.Build.0 = Release|Any CPU {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Debug|ARM64.Build.0 = Debug|ARM64 {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Debug|x64.ActiveCfg = Debug|Any CPU {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Debug|x64.Build.0 = Debug|Any CPU {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Debug|x86.ActiveCfg = Debug|Any CPU {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Debug|x86.Build.0 = Debug|Any CPU {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Release|Any CPU.ActiveCfg = Release|Any CPU {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Release|Any CPU.Build.0 = Release|Any CPU + {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Release|ARM64.ActiveCfg = Release|ARM64 + {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Release|ARM64.Build.0 = Release|ARM64 {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Release|x64.ActiveCfg = Release|Any CPU {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Release|x64.Build.0 = Release|Any CPU {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Release|x86.ActiveCfg = Release|Any CPU {4AA7CE6F-7154-49C1-B598-46055D590CAD}.Release|x86.Build.0 = Release|Any CPU {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Debug|ARM64.Build.0 = Debug|ARM64 {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Debug|x64.ActiveCfg = Debug|Any CPU {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Debug|x64.Build.0 = Debug|Any CPU {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Debug|x86.ActiveCfg = Debug|Any CPU {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Debug|x86.Build.0 = Debug|Any CPU {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Release|Any CPU.ActiveCfg = Release|Any CPU {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Release|Any CPU.Build.0 = Release|Any CPU + {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Release|ARM64.ActiveCfg = Release|ARM64 + {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Release|ARM64.Build.0 = Release|ARM64 {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Release|x64.ActiveCfg = Release|Any CPU {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Release|x64.Build.0 = Release|Any CPU {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Release|x86.ActiveCfg = Release|Any CPU {90FDF2B3-25C9-428D-B264-5A5FAEB2D988}.Release|x86.Build.0 = Release|Any CPU {7D658974-C38C-421F-8186-B735F06CFC58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7D658974-C38C-421F-8186-B735F06CFC58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D658974-C38C-421F-8186-B735F06CFC58}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7D658974-C38C-421F-8186-B735F06CFC58}.Debug|ARM64.Build.0 = Debug|ARM64 {7D658974-C38C-421F-8186-B735F06CFC58}.Debug|x64.ActiveCfg = Debug|Any CPU {7D658974-C38C-421F-8186-B735F06CFC58}.Debug|x64.Build.0 = Debug|Any CPU {7D658974-C38C-421F-8186-B735F06CFC58}.Debug|x86.ActiveCfg = Debug|Any CPU {7D658974-C38C-421F-8186-B735F06CFC58}.Debug|x86.Build.0 = Debug|Any CPU {7D658974-C38C-421F-8186-B735F06CFC58}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D658974-C38C-421F-8186-B735F06CFC58}.Release|Any CPU.Build.0 = Release|Any CPU + {7D658974-C38C-421F-8186-B735F06CFC58}.Release|ARM64.ActiveCfg = Release|ARM64 + {7D658974-C38C-421F-8186-B735F06CFC58}.Release|ARM64.Build.0 = Release|ARM64 {7D658974-C38C-421F-8186-B735F06CFC58}.Release|x64.ActiveCfg = Release|Any CPU {7D658974-C38C-421F-8186-B735F06CFC58}.Release|x64.Build.0 = Release|Any CPU {7D658974-C38C-421F-8186-B735F06CFC58}.Release|x86.ActiveCfg = Release|Any CPU {7D658974-C38C-421F-8186-B735F06CFC58}.Release|x86.Build.0 = Release|Any CPU {03B8E43C-5680-4803-A745-0A104FE6620C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {03B8E43C-5680-4803-A745-0A104FE6620C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03B8E43C-5680-4803-A745-0A104FE6620C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {03B8E43C-5680-4803-A745-0A104FE6620C}.Debug|ARM64.Build.0 = Debug|ARM64 {03B8E43C-5680-4803-A745-0A104FE6620C}.Debug|x64.ActiveCfg = Debug|Any CPU {03B8E43C-5680-4803-A745-0A104FE6620C}.Debug|x64.Build.0 = Debug|Any CPU {03B8E43C-5680-4803-A745-0A104FE6620C}.Debug|x86.ActiveCfg = Debug|Any CPU {03B8E43C-5680-4803-A745-0A104FE6620C}.Debug|x86.Build.0 = Debug|Any CPU {03B8E43C-5680-4803-A745-0A104FE6620C}.Release|Any CPU.ActiveCfg = Release|Any CPU {03B8E43C-5680-4803-A745-0A104FE6620C}.Release|Any CPU.Build.0 = Release|Any CPU + {03B8E43C-5680-4803-A745-0A104FE6620C}.Release|ARM64.ActiveCfg = Release|ARM64 + {03B8E43C-5680-4803-A745-0A104FE6620C}.Release|ARM64.Build.0 = Release|ARM64 {03B8E43C-5680-4803-A745-0A104FE6620C}.Release|x64.ActiveCfg = Release|Any CPU {03B8E43C-5680-4803-A745-0A104FE6620C}.Release|x64.Build.0 = Release|Any CPU {03B8E43C-5680-4803-A745-0A104FE6620C}.Release|x86.ActiveCfg = Release|Any CPU {03B8E43C-5680-4803-A745-0A104FE6620C}.Release|x86.Build.0 = Release|Any CPU {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Debug|ARM64.Build.0 = Debug|ARM64 {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Debug|x64.ActiveCfg = Debug|Any CPU {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Debug|x64.Build.0 = Debug|Any CPU {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Debug|x86.ActiveCfg = Debug|Any CPU {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Debug|x86.Build.0 = Debug|Any CPU {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Release|Any CPU.ActiveCfg = Release|Any CPU {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Release|Any CPU.Build.0 = Release|Any CPU + {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Release|ARM64.ActiveCfg = Release|ARM64 + {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Release|ARM64.Build.0 = Release|ARM64 {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Release|x64.ActiveCfg = Release|Any CPU {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Release|x64.Build.0 = Release|Any CPU {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Release|x86.ActiveCfg = Release|Any CPU {45A0EA81-D37E-4D7F-8CE1-CE6B6A95A9ED}.Release|x86.Build.0 = Release|Any CPU {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Debug|ARM64.Build.0 = Debug|ARM64 {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Debug|x64.ActiveCfg = Debug|Any CPU {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Debug|x64.Build.0 = Debug|Any CPU {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Debug|x86.ActiveCfg = Debug|Any CPU {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Debug|x86.Build.0 = Debug|Any CPU {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Release|Any CPU.ActiveCfg = Release|Any CPU {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Release|Any CPU.Build.0 = Release|Any CPU + {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Release|ARM64.ActiveCfg = Release|ARM64 + {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Release|ARM64.Build.0 = Release|ARM64 {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Release|x64.ActiveCfg = Release|Any CPU {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Release|x64.Build.0 = Release|Any CPU {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Release|x86.ActiveCfg = Release|Any CPU {5F2931B6-9A77-4F94-80CD-BC9B9A0C64BF}.Release|x86.Build.0 = Release|Any CPU {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Debug|Any CPU.Build.0 = Debug|Any CPU + {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Debug|ARM64.Build.0 = Debug|ARM64 {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Debug|x64.ActiveCfg = Debug|Any CPU {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Debug|x64.Build.0 = Debug|Any CPU {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Debug|x86.ActiveCfg = Debug|Any CPU {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Debug|x86.Build.0 = Debug|Any CPU {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Release|Any CPU.ActiveCfg = Release|Any CPU {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Release|Any CPU.Build.0 = Release|Any CPU + {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Release|ARM64.ActiveCfg = Release|ARM64 + {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Release|ARM64.Build.0 = Release|ARM64 {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Release|x64.ActiveCfg = Release|Any CPU {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Release|x64.Build.0 = Release|Any CPU {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Release|x86.ActiveCfg = Release|Any CPU {24E940FF-C9F3-4D5C-8FCF-CA527F055318}.Release|x86.Build.0 = Release|Any CPU {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Debug|ARM64.Build.0 = Debug|ARM64 {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Debug|x64.ActiveCfg = Debug|Any CPU {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Debug|x64.Build.0 = Debug|Any CPU {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Debug|x86.ActiveCfg = Debug|Any CPU {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Debug|x86.Build.0 = Debug|Any CPU {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Release|Any CPU.ActiveCfg = Release|Any CPU {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Release|Any CPU.Build.0 = Release|Any CPU + {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Release|ARM64.ActiveCfg = Release|ARM64 + {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Release|ARM64.Build.0 = Release|ARM64 {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Release|x64.ActiveCfg = Release|Any CPU {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Release|x64.Build.0 = Release|Any CPU {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Release|x86.ActiveCfg = Release|Any CPU {4290C007-2142-4AD1-8EB6-F80EF2F45AA4}.Release|x86.Build.0 = Release|Any CPU {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Debug|ARM64.Build.0 = Debug|ARM64 {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Debug|x64.ActiveCfg = Debug|Any CPU {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Debug|x64.Build.0 = Debug|Any CPU {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Debug|x86.ActiveCfg = Debug|Any CPU {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Debug|x86.Build.0 = Debug|Any CPU {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Release|Any CPU.ActiveCfg = Release|Any CPU {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Release|Any CPU.Build.0 = Release|Any CPU + {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Release|ARM64.ActiveCfg = Release|ARM64 + {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Release|ARM64.Build.0 = Release|ARM64 {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Release|x64.ActiveCfg = Release|Any CPU {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Release|x64.Build.0 = Release|Any CPU {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Release|x86.ActiveCfg = Release|Any CPU {A16637C2-2D91-4953-AE04-D91EC188DD7B}.Release|x86.Build.0 = Release|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Debug|ARM64.Build.0 = Debug|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Debug|x64.ActiveCfg = Debug|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Debug|x64.Build.0 = Debug|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Debug|x86.ActiveCfg = Debug|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Debug|x86.Build.0 = Debug|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Release|Any CPU.ActiveCfg = Release|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Release|Any CPU.Build.0 = Release|Any CPU + {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Release|ARM64.ActiveCfg = Release|Any CPU + {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Release|ARM64.Build.0 = Release|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Release|x64.ActiveCfg = Release|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Release|x64.Build.0 = Release|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Release|x86.ActiveCfg = Release|Any CPU {A0DA4200-6643-4F2C-8450-65B8CE8A5576}.Release|x86.Build.0 = Release|Any CPU {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Debug|ARM64.Build.0 = Debug|ARM64 {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Debug|x64.ActiveCfg = Debug|Any CPU {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Debug|x64.Build.0 = Debug|Any CPU {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Debug|x86.ActiveCfg = Debug|Any CPU {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Debug|x86.Build.0 = Debug|Any CPU {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Release|Any CPU.Build.0 = Release|Any CPU + {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Release|ARM64.ActiveCfg = Release|ARM64 + {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Release|ARM64.Build.0 = Release|ARM64 {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Release|x64.ActiveCfg = Release|Any CPU {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Release|x64.Build.0 = Release|Any CPU {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Release|x86.ActiveCfg = Release|Any CPU {CB301B4C-D518-41F5-873B-9B1F145DB4AF}.Release|x86.Build.0 = Release|Any CPU {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Debug|ARM64.Build.0 = Debug|ARM64 {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Debug|x64.ActiveCfg = Debug|Any CPU {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Debug|x64.Build.0 = Debug|Any CPU {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Debug|x86.ActiveCfg = Debug|Any CPU {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Debug|x86.Build.0 = Debug|Any CPU {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Release|Any CPU.ActiveCfg = Release|Any CPU {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Release|Any CPU.Build.0 = Release|Any CPU + {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Release|ARM64.ActiveCfg = Release|ARM64 + {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Release|ARM64.Build.0 = Release|ARM64 {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Release|x64.ActiveCfg = Release|Any CPU {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Release|x64.Build.0 = Release|Any CPU {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Release|x86.ActiveCfg = Release|Any CPU {1CF1B8BF-57EB-4E49-B644-0A8F2DFEEB58}.Release|x86.Build.0 = Release|Any CPU {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Debug|ARM64.Build.0 = Debug|ARM64 {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Debug|x64.ActiveCfg = Debug|Any CPU {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Debug|x64.Build.0 = Debug|Any CPU {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Debug|x86.ActiveCfg = Debug|Any CPU {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Debug|x86.Build.0 = Debug|Any CPU {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Release|Any CPU.ActiveCfg = Release|Any CPU {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Release|Any CPU.Build.0 = Release|Any CPU + {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Release|ARM64.ActiveCfg = Release|ARM64 + {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Release|ARM64.Build.0 = Release|ARM64 {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Release|x64.ActiveCfg = Release|Any CPU {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Release|x64.Build.0 = Release|Any CPU {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Release|x86.ActiveCfg = Release|Any CPU {643CA26B-B80E-4E6A-AAE4-BCEC021D2AA0}.Release|x86.Build.0 = Release|Any CPU {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Debug|ARM64.Build.0 = Debug|ARM64 {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Debug|x64.ActiveCfg = Debug|Any CPU {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Debug|x64.Build.0 = Debug|Any CPU {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Debug|x86.ActiveCfg = Debug|Any CPU {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Debug|x86.Build.0 = Debug|Any CPU {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Release|Any CPU.Build.0 = Release|Any CPU + {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Release|ARM64.ActiveCfg = Release|ARM64 + {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Release|ARM64.Build.0 = Release|ARM64 {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Release|x64.ActiveCfg = Release|Any CPU {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Release|x64.Build.0 = Release|Any CPU {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Release|x86.ActiveCfg = Release|Any CPU {2A00C747-8BC0-4EF1-A53E-37A7E156D910}.Release|x86.Build.0 = Release|Any CPU {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Debug|ARM64.Build.0 = Debug|ARM64 {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Debug|x64.ActiveCfg = Debug|Any CPU {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Debug|x64.Build.0 = Debug|Any CPU {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Debug|x86.ActiveCfg = Debug|Any CPU {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Debug|x86.Build.0 = Debug|Any CPU {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Release|Any CPU.ActiveCfg = Release|Any CPU {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Release|Any CPU.Build.0 = Release|Any CPU + {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Release|ARM64.ActiveCfg = Release|ARM64 + {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Release|ARM64.Build.0 = Release|ARM64 {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Release|x64.ActiveCfg = Release|Any CPU {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Release|x64.Build.0 = Release|Any CPU {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Release|x86.ActiveCfg = Release|Any CPU {BA2D505E-CED3-4FCB-A463-DAF6B77C18DE}.Release|x86.Build.0 = Release|Any CPU {7D608265-3330-4747-B5B4-9673A119FE6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7D608265-3330-4747-B5B4-9673A119FE6C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D608265-3330-4747-B5B4-9673A119FE6C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7D608265-3330-4747-B5B4-9673A119FE6C}.Debug|ARM64.Build.0 = Debug|ARM64 {7D608265-3330-4747-B5B4-9673A119FE6C}.Debug|x64.ActiveCfg = Debug|Any CPU {7D608265-3330-4747-B5B4-9673A119FE6C}.Debug|x64.Build.0 = Debug|Any CPU {7D608265-3330-4747-B5B4-9673A119FE6C}.Debug|x86.ActiveCfg = Debug|Any CPU {7D608265-3330-4747-B5B4-9673A119FE6C}.Debug|x86.Build.0 = Debug|Any CPU {7D608265-3330-4747-B5B4-9673A119FE6C}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D608265-3330-4747-B5B4-9673A119FE6C}.Release|Any CPU.Build.0 = Release|Any CPU + {7D608265-3330-4747-B5B4-9673A119FE6C}.Release|ARM64.ActiveCfg = Release|ARM64 + {7D608265-3330-4747-B5B4-9673A119FE6C}.Release|ARM64.Build.0 = Release|ARM64 {7D608265-3330-4747-B5B4-9673A119FE6C}.Release|x64.ActiveCfg = Release|Any CPU {7D608265-3330-4747-B5B4-9673A119FE6C}.Release|x64.Build.0 = Release|Any CPU {7D608265-3330-4747-B5B4-9673A119FE6C}.Release|x86.ActiveCfg = Release|Any CPU {7D608265-3330-4747-B5B4-9673A119FE6C}.Release|x86.Build.0 = Release|Any CPU {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Debug|ARM64.Build.0 = Debug|ARM64 {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Debug|x64.ActiveCfg = Debug|Any CPU {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Debug|x64.Build.0 = Debug|Any CPU {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Debug|x86.ActiveCfg = Debug|Any CPU {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Debug|x86.Build.0 = Debug|Any CPU {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Release|Any CPU.ActiveCfg = Release|Any CPU {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Release|Any CPU.Build.0 = Release|Any CPU + {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Release|ARM64.ActiveCfg = Release|ARM64 + {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Release|ARM64.Build.0 = Release|ARM64 {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Release|x64.ActiveCfg = Release|Any CPU {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Release|x64.Build.0 = Release|Any CPU {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Release|x86.ActiveCfg = Release|Any CPU {A0A9C7B9-4A33-492E-BA54-8E8E600D3D66}.Release|x86.Build.0 = Release|Any CPU {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Debug|ARM64.Build.0 = Debug|ARM64 {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Debug|x64.ActiveCfg = Debug|Any CPU {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Debug|x64.Build.0 = Debug|Any CPU {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Debug|x86.ActiveCfg = Debug|Any CPU {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Debug|x86.Build.0 = Debug|Any CPU {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Release|Any CPU.ActiveCfg = Release|Any CPU {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Release|Any CPU.Build.0 = Release|Any CPU + {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Release|ARM64.ActiveCfg = Release|ARM64 + {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Release|ARM64.Build.0 = Release|ARM64 {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Release|x64.ActiveCfg = Release|Any CPU {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Release|x64.Build.0 = Release|Any CPU {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Release|x86.ActiveCfg = Release|Any CPU {7882140D-32E1-4AB5-853D-F8DED5256DC2}.Release|x86.Build.0 = Release|Any CPU {3E905528-D87C-4552-A32D-66BF90D14DB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3E905528-D87C-4552-A32D-66BF90D14DB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E905528-D87C-4552-A32D-66BF90D14DB0}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {3E905528-D87C-4552-A32D-66BF90D14DB0}.Debug|ARM64.Build.0 = Debug|ARM64 {3E905528-D87C-4552-A32D-66BF90D14DB0}.Debug|x64.ActiveCfg = Debug|Any CPU {3E905528-D87C-4552-A32D-66BF90D14DB0}.Debug|x64.Build.0 = Debug|Any CPU {3E905528-D87C-4552-A32D-66BF90D14DB0}.Debug|x86.ActiveCfg = Debug|Any CPU {3E905528-D87C-4552-A32D-66BF90D14DB0}.Debug|x86.Build.0 = Debug|Any CPU {3E905528-D87C-4552-A32D-66BF90D14DB0}.Release|Any CPU.ActiveCfg = Release|Any CPU {3E905528-D87C-4552-A32D-66BF90D14DB0}.Release|Any CPU.Build.0 = Release|Any CPU + {3E905528-D87C-4552-A32D-66BF90D14DB0}.Release|ARM64.ActiveCfg = Release|ARM64 + {3E905528-D87C-4552-A32D-66BF90D14DB0}.Release|ARM64.Build.0 = Release|ARM64 {3E905528-D87C-4552-A32D-66BF90D14DB0}.Release|x64.ActiveCfg = Release|Any CPU {3E905528-D87C-4552-A32D-66BF90D14DB0}.Release|x64.Build.0 = Release|Any CPU {3E905528-D87C-4552-A32D-66BF90D14DB0}.Release|x86.ActiveCfg = Release|Any CPU {3E905528-D87C-4552-A32D-66BF90D14DB0}.Release|x86.Build.0 = Release|Any CPU {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Debug|ARM64.Build.0 = Debug|ARM64 {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Debug|x64.ActiveCfg = Debug|Any CPU {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Debug|x64.Build.0 = Debug|Any CPU {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Debug|x86.ActiveCfg = Debug|Any CPU {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Debug|x86.Build.0 = Debug|Any CPU {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Release|Any CPU.ActiveCfg = Release|Any CPU {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Release|Any CPU.Build.0 = Release|Any CPU + {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Release|ARM64.ActiveCfg = Release|ARM64 + {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Release|ARM64.Build.0 = Release|ARM64 {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Release|x64.ActiveCfg = Release|Any CPU {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Release|x64.Build.0 = Release|Any CPU {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Release|x86.ActiveCfg = Release|Any CPU {9E4D6072-C8DE-475A-B9A7-4B6BF6EEEAEB}.Release|x86.Build.0 = Release|Any CPU {686E902E-0C23-4396-8887-6D9219EF8D27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {686E902E-0C23-4396-8887-6D9219EF8D27}.Debug|Any CPU.Build.0 = Debug|Any CPU + {686E902E-0C23-4396-8887-6D9219EF8D27}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {686E902E-0C23-4396-8887-6D9219EF8D27}.Debug|ARM64.Build.0 = Debug|ARM64 {686E902E-0C23-4396-8887-6D9219EF8D27}.Debug|x64.ActiveCfg = Debug|Any CPU {686E902E-0C23-4396-8887-6D9219EF8D27}.Debug|x64.Build.0 = Debug|Any CPU {686E902E-0C23-4396-8887-6D9219EF8D27}.Debug|x86.ActiveCfg = Debug|Any CPU {686E902E-0C23-4396-8887-6D9219EF8D27}.Debug|x86.Build.0 = Debug|Any CPU {686E902E-0C23-4396-8887-6D9219EF8D27}.Release|Any CPU.ActiveCfg = Release|Any CPU {686E902E-0C23-4396-8887-6D9219EF8D27}.Release|Any CPU.Build.0 = Release|Any CPU + {686E902E-0C23-4396-8887-6D9219EF8D27}.Release|ARM64.ActiveCfg = Release|ARM64 + {686E902E-0C23-4396-8887-6D9219EF8D27}.Release|ARM64.Build.0 = Release|ARM64 {686E902E-0C23-4396-8887-6D9219EF8D27}.Release|x64.ActiveCfg = Release|Any CPU {686E902E-0C23-4396-8887-6D9219EF8D27}.Release|x64.Build.0 = Release|Any CPU {686E902E-0C23-4396-8887-6D9219EF8D27}.Release|x86.ActiveCfg = Release|Any CPU {686E902E-0C23-4396-8887-6D9219EF8D27}.Release|x86.Build.0 = Release|Any CPU {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Debug|ARM64.Build.0 = Debug|ARM64 {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Debug|x64.ActiveCfg = Debug|Any CPU {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Debug|x64.Build.0 = Debug|Any CPU {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Debug|x86.ActiveCfg = Debug|Any CPU {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Debug|x86.Build.0 = Debug|Any CPU {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Release|Any CPU.ActiveCfg = Release|Any CPU {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Release|Any CPU.Build.0 = Release|Any CPU + {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Release|ARM64.ActiveCfg = Release|ARM64 + {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Release|ARM64.Build.0 = Release|ARM64 {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Release|x64.ActiveCfg = Release|Any CPU {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Release|x64.Build.0 = Release|Any CPU {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Release|x86.ActiveCfg = Release|Any CPU {8EE4A9C6-AA93-4A84-8EAB-4EC955DD6851}.Release|x86.Build.0 = Release|Any CPU {80A71107-9C8E-47B2-B743-58D5976B38FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {80A71107-9C8E-47B2-B743-58D5976B38FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80A71107-9C8E-47B2-B743-58D5976B38FB}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {80A71107-9C8E-47B2-B743-58D5976B38FB}.Debug|ARM64.Build.0 = Debug|ARM64 {80A71107-9C8E-47B2-B743-58D5976B38FB}.Debug|x64.ActiveCfg = Debug|Any CPU {80A71107-9C8E-47B2-B743-58D5976B38FB}.Debug|x64.Build.0 = Debug|Any CPU {80A71107-9C8E-47B2-B743-58D5976B38FB}.Debug|x86.ActiveCfg = Debug|Any CPU {80A71107-9C8E-47B2-B743-58D5976B38FB}.Debug|x86.Build.0 = Debug|Any CPU {80A71107-9C8E-47B2-B743-58D5976B38FB}.Release|Any CPU.ActiveCfg = Release|Any CPU {80A71107-9C8E-47B2-B743-58D5976B38FB}.Release|Any CPU.Build.0 = Release|Any CPU + {80A71107-9C8E-47B2-B743-58D5976B38FB}.Release|ARM64.ActiveCfg = Release|ARM64 + {80A71107-9C8E-47B2-B743-58D5976B38FB}.Release|ARM64.Build.0 = Release|ARM64 {80A71107-9C8E-47B2-B743-58D5976B38FB}.Release|x64.ActiveCfg = Release|Any CPU {80A71107-9C8E-47B2-B743-58D5976B38FB}.Release|x64.Build.0 = Release|Any CPU {80A71107-9C8E-47B2-B743-58D5976B38FB}.Release|x86.ActiveCfg = Release|Any CPU {80A71107-9C8E-47B2-B743-58D5976B38FB}.Release|x86.Build.0 = Release|Any CPU {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Debug|ARM64.Build.0 = Debug|ARM64 {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Debug|x64.ActiveCfg = Debug|Any CPU {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Debug|x64.Build.0 = Debug|Any CPU {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Debug|x86.ActiveCfg = Debug|Any CPU {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Debug|x86.Build.0 = Debug|Any CPU {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Release|Any CPU.ActiveCfg = Release|Any CPU {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Release|Any CPU.Build.0 = Release|Any CPU + {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Release|ARM64.ActiveCfg = Release|ARM64 + {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Release|ARM64.Build.0 = Release|ARM64 {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Release|x64.ActiveCfg = Release|Any CPU {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Release|x64.Build.0 = Release|Any CPU {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Release|x86.ActiveCfg = Release|Any CPU {C0D6E7EC-29AF-4FC2-B8E0-1E5D083B55DD}.Release|x86.Build.0 = Release|Any CPU {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Debug|ARM64.Build.0 = Debug|ARM64 {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Debug|x64.ActiveCfg = Debug|Any CPU {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Debug|x64.Build.0 = Debug|Any CPU {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Debug|x86.ActiveCfg = Debug|Any CPU {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Debug|x86.Build.0 = Debug|Any CPU {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Release|Any CPU.ActiveCfg = Release|Any CPU {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Release|Any CPU.Build.0 = Release|Any CPU + {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Release|ARM64.ActiveCfg = Release|ARM64 + {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Release|ARM64.Build.0 = Release|ARM64 {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Release|x64.ActiveCfg = Release|Any CPU {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Release|x64.Build.0 = Release|Any CPU {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Release|x86.ActiveCfg = Release|Any CPU {168C5EC3-FF08-402F-8D70-F216CB04DE81}.Release|x86.Build.0 = Release|Any CPU {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Debug|ARM64.Build.0 = Debug|ARM64 {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Debug|x64.ActiveCfg = Debug|Any CPU {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Debug|x64.Build.0 = Debug|Any CPU {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Debug|x86.ActiveCfg = Debug|Any CPU {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Debug|x86.Build.0 = Debug|Any CPU {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Release|Any CPU.ActiveCfg = Release|Any CPU {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Release|Any CPU.Build.0 = Release|Any CPU + {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Release|ARM64.ActiveCfg = Release|ARM64 + {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Release|ARM64.Build.0 = Release|ARM64 {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Release|x64.ActiveCfg = Release|Any CPU {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Release|x64.Build.0 = Release|Any CPU {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Release|x86.ActiveCfg = Release|Any CPU {7318548D-B8F2-4ED3-8B3E-F61DD8B552D1}.Release|x86.Build.0 = Release|Any CPU {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Debug|ARM64.Build.0 = Debug|ARM64 {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Debug|x64.ActiveCfg = Debug|Any CPU {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Debug|x64.Build.0 = Debug|Any CPU {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Debug|x86.ActiveCfg = Debug|Any CPU {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Debug|x86.Build.0 = Debug|Any CPU {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Release|Any CPU.ActiveCfg = Release|Any CPU {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Release|Any CPU.Build.0 = Release|Any CPU + {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Release|ARM64.ActiveCfg = Release|ARM64 + {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Release|ARM64.Build.0 = Release|ARM64 {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Release|x64.ActiveCfg = Release|Any CPU {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Release|x64.Build.0 = Release|Any CPU {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Release|x86.ActiveCfg = Release|Any CPU {A2B4BEC3-7430-489E-BE6B-F1E8205A7C62}.Release|x86.Build.0 = Release|Any CPU {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Debug|ARM64.Build.0 = Debug|ARM64 {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Debug|x64.ActiveCfg = Debug|Any CPU {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Debug|x64.Build.0 = Debug|Any CPU {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Debug|x86.ActiveCfg = Debug|Any CPU {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Debug|x86.Build.0 = Debug|Any CPU {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Release|Any CPU.ActiveCfg = Release|Any CPU {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Release|Any CPU.Build.0 = Release|Any CPU + {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Release|ARM64.ActiveCfg = Release|ARM64 + {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Release|ARM64.Build.0 = Release|ARM64 {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Release|x64.ActiveCfg = Release|Any CPU {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Release|x64.Build.0 = Release|Any CPU {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Release|x86.ActiveCfg = Release|Any CPU {8C4C72C3-DCC4-43B1-A2B3-DF77B435FA75}.Release|x86.Build.0 = Release|Any CPU {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Debug|Any CPU.Build.0 = Debug|Any CPU + {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Debug|ARM64.Build.0 = Debug|ARM64 {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Debug|x64.ActiveCfg = Debug|Any CPU {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Debug|x64.Build.0 = Debug|Any CPU {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Debug|x86.ActiveCfg = Debug|Any CPU {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Debug|x86.Build.0 = Debug|Any CPU {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Release|Any CPU.ActiveCfg = Release|Any CPU {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Release|Any CPU.Build.0 = Release|Any CPU + {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Release|ARM64.ActiveCfg = Release|ARM64 + {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Release|ARM64.Build.0 = Release|ARM64 {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Release|x64.ActiveCfg = Release|Any CPU {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Release|x64.Build.0 = Release|Any CPU {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Release|x86.ActiveCfg = Release|Any CPU {455DA1FB-5097-47D2-8603-B0E1F9D90294}.Release|x86.Build.0 = Release|Any CPU {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Debug|ARM64.Build.0 = Debug|ARM64 {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Debug|x64.ActiveCfg = Debug|Any CPU {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Debug|x64.Build.0 = Debug|Any CPU {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Debug|x86.ActiveCfg = Debug|Any CPU {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Debug|x86.Build.0 = Debug|Any CPU {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Release|Any CPU.ActiveCfg = Release|Any CPU {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Release|Any CPU.Build.0 = Release|Any CPU + {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Release|ARM64.ActiveCfg = Release|ARM64 + {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Release|ARM64.Build.0 = Release|ARM64 {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Release|x64.ActiveCfg = Release|Any CPU {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Release|x64.Build.0 = Release|Any CPU {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Release|x86.ActiveCfg = Release|Any CPU {E52E34FD-40AE-425B-9C1A-2CAB3EE2704F}.Release|x86.Build.0 = Release|Any CPU {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Debug|ARM64.Build.0 = Debug|ARM64 {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Debug|x64.ActiveCfg = Debug|Any CPU {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Debug|x64.Build.0 = Debug|Any CPU {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Debug|x86.ActiveCfg = Debug|Any CPU {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Debug|x86.Build.0 = Debug|Any CPU {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Release|Any CPU.Build.0 = Release|Any CPU + {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Release|ARM64.ActiveCfg = Release|ARM64 + {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Release|ARM64.Build.0 = Release|ARM64 {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Release|x64.ActiveCfg = Release|Any CPU {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Release|x64.Build.0 = Release|Any CPU {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Release|x86.ActiveCfg = Release|Any CPU {F6B47679-3362-4A0C-BB4D-BD3C9B0550AF}.Release|x86.Build.0 = Release|Any CPU {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Debug|ARM64.Build.0 = Debug|ARM64 {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Debug|x64.ActiveCfg = Debug|Any CPU {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Debug|x64.Build.0 = Debug|Any CPU {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Debug|x86.ActiveCfg = Debug|Any CPU {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Debug|x86.Build.0 = Debug|Any CPU {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Release|Any CPU.ActiveCfg = Release|Any CPU {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Release|Any CPU.Build.0 = Release|Any CPU + {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Release|ARM64.ActiveCfg = Release|ARM64 + {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Release|ARM64.Build.0 = Release|ARM64 {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Release|x64.ActiveCfg = Release|Any CPU {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Release|x64.Build.0 = Release|Any CPU {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Release|x86.ActiveCfg = Release|Any CPU {45927301-6CF5-4770-888C-7B0B51ECEBEE}.Release|x86.Build.0 = Release|Any CPU {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Debug|Any CPU.Build.0 = Debug|Any CPU + {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Debug|ARM64.Build.0 = Debug|ARM64 {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Debug|x64.ActiveCfg = Debug|Any CPU {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Debug|x64.Build.0 = Debug|Any CPU {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Debug|x86.ActiveCfg = Debug|Any CPU {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Debug|x86.Build.0 = Debug|Any CPU {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Release|Any CPU.ActiveCfg = Release|Any CPU {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Release|Any CPU.Build.0 = Release|Any CPU + {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Release|ARM64.ActiveCfg = Release|ARM64 + {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Release|ARM64.Build.0 = Release|ARM64 {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Release|x64.ActiveCfg = Release|Any CPU {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Release|x64.Build.0 = Release|Any CPU {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Release|x86.ActiveCfg = Release|Any CPU {153BD6AB-6B34-4E97-A96D-4ED5826DC037}.Release|x86.Build.0 = Release|Any CPU {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Debug|ARM64.Build.0 = Debug|ARM64 {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Debug|x64.ActiveCfg = Debug|Any CPU {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Debug|x64.Build.0 = Debug|Any CPU {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Debug|x86.ActiveCfg = Debug|Any CPU {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Debug|x86.Build.0 = Debug|Any CPU {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Release|Any CPU.ActiveCfg = Release|Any CPU {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Release|Any CPU.Build.0 = Release|Any CPU + {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Release|ARM64.ActiveCfg = Release|ARM64 + {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Release|ARM64.Build.0 = Release|ARM64 {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Release|x64.ActiveCfg = Release|Any CPU {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Release|x64.Build.0 = Release|Any CPU {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Release|x86.ActiveCfg = Release|Any CPU {2088B3AF-F9AF-45B8-B824-16749D5DAF9E}.Release|x86.Build.0 = Release|Any CPU {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Debug|ARM64.Build.0 = Debug|ARM64 {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Debug|x64.ActiveCfg = Debug|Any CPU {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Debug|x64.Build.0 = Debug|Any CPU {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Debug|x86.ActiveCfg = Debug|Any CPU {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Debug|x86.Build.0 = Debug|Any CPU {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Release|Any CPU.ActiveCfg = Release|Any CPU {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Release|Any CPU.Build.0 = Release|Any CPU + {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Release|ARM64.ActiveCfg = Release|ARM64 + {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Release|ARM64.Build.0 = Release|ARM64 {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Release|x64.ActiveCfg = Release|Any CPU {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Release|x64.Build.0 = Release|Any CPU {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Release|x86.ActiveCfg = Release|Any CPU {89E58A49-12C4-4C22-B646-348B6BFCCB4D}.Release|x86.Build.0 = Release|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Debug|x64.ActiveCfg = Debug|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Debug|x64.Build.0 = Debug|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Debug|x86.ActiveCfg = Debug|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Debug|x86.Build.0 = Debug|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Release|Any CPU.Build.0 = Release|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Release|x64.ActiveCfg = Release|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Release|x64.Build.0 = Release|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Release|x86.ActiveCfg = Release|Any CPU - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B}.Release|x86.Build.0 = Release|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Debug|x64.ActiveCfg = Debug|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Debug|x64.Build.0 = Debug|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Debug|x86.ActiveCfg = Debug|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Debug|x86.Build.0 = Debug|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Release|Any CPU.Build.0 = Release|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Release|x64.ActiveCfg = Release|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Release|x64.Build.0 = Release|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Release|x86.ActiveCfg = Release|Any CPU - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62}.Release|x86.Build.0 = Release|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Debug|x64.ActiveCfg = Debug|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Debug|x64.Build.0 = Debug|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Debug|x86.ActiveCfg = Debug|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Debug|x86.Build.0 = Debug|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Release|Any CPU.Build.0 = Release|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Release|x64.ActiveCfg = Release|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Release|x64.Build.0 = Release|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Release|x86.ActiveCfg = Release|Any CPU - {321C6410-B154-45BD-B44A-7CD451BBA9F0}.Release|x86.Build.0 = Release|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Debug|Any CPU.Build.0 = Debug|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Debug|x64.ActiveCfg = Debug|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Debug|x64.Build.0 = Debug|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Debug|x86.ActiveCfg = Debug|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Debug|x86.Build.0 = Debug|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Release|Any CPU.ActiveCfg = Release|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Release|Any CPU.Build.0 = Release|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Release|x64.ActiveCfg = Release|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Release|x64.Build.0 = Release|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Release|x86.ActiveCfg = Release|Any CPU - {076A3785-83CD-4AE3-BE45-1AE183587731}.Release|x86.Build.0 = Release|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Debug|x64.ActiveCfg = Debug|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Debug|x64.Build.0 = Debug|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Debug|x86.ActiveCfg = Debug|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Debug|x86.Build.0 = Debug|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Release|Any CPU.Build.0 = Release|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Release|x64.ActiveCfg = Release|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Release|x64.Build.0 = Release|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Release|x86.ActiveCfg = Release|Any CPU - {0997005B-E6FF-4D3F-AACE-C29338C7977F}.Release|x86.Build.0 = Release|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Debug|x64.ActiveCfg = Debug|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Debug|x64.Build.0 = Debug|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Debug|x86.ActiveCfg = Debug|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Debug|x86.Build.0 = Debug|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Release|Any CPU.Build.0 = Release|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Release|x64.ActiveCfg = Release|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Release|x64.Build.0 = Release|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Release|x86.ActiveCfg = Release|Any CPU - {15F67655-8025-4389-8FF7-3F3CA7F543DA}.Release|x86.Build.0 = Release|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Debug|x64.ActiveCfg = Debug|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Debug|x64.Build.0 = Debug|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Debug|x86.ActiveCfg = Debug|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Debug|x86.Build.0 = Debug|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Release|Any CPU.Build.0 = Release|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Release|x64.ActiveCfg = Release|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Release|x64.Build.0 = Release|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Release|x86.ActiveCfg = Release|Any CPU - {1BCFC9AF-6570-4996-949D-3C45F3411712}.Release|x86.Build.0 = Release|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Debug|Any CPU.Build.0 = Debug|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Debug|x64.ActiveCfg = Debug|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Debug|x64.Build.0 = Debug|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Debug|x86.ActiveCfg = Debug|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Debug|x86.Build.0 = Debug|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Release|Any CPU.ActiveCfg = Release|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Release|Any CPU.Build.0 = Release|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Release|x64.ActiveCfg = Release|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Release|x64.Build.0 = Release|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Release|x86.ActiveCfg = Release|Any CPU - {219FADE8-5473-4099-8291-7C29AA6F4808}.Release|x86.Build.0 = Release|Any CPU {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Debug|ARM64.Build.0 = Debug|ARM64 {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Debug|x64.ActiveCfg = Debug|Any CPU {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Debug|x64.Build.0 = Debug|Any CPU {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Debug|x86.ActiveCfg = Debug|Any CPU {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Debug|x86.Build.0 = Debug|Any CPU {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Release|Any CPU.ActiveCfg = Release|Any CPU {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Release|Any CPU.Build.0 = Release|Any CPU + {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Release|ARM64.ActiveCfg = Release|ARM64 + {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Release|ARM64.Build.0 = Release|ARM64 {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Release|x64.ActiveCfg = Release|Any CPU {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Release|x64.Build.0 = Release|Any CPU {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Release|x86.ActiveCfg = Release|Any CPU {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2}.Release|x86.Build.0 = Release|Any CPU {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Debug|ARM64.Build.0 = Debug|ARM64 {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Debug|x64.ActiveCfg = Debug|Any CPU {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Debug|x64.Build.0 = Debug|Any CPU {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Debug|x86.ActiveCfg = Debug|Any CPU {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Debug|x86.Build.0 = Debug|Any CPU {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Release|Any CPU.ActiveCfg = Release|Any CPU {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Release|Any CPU.Build.0 = Release|Any CPU + {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Release|ARM64.ActiveCfg = Release|ARM64 + {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Release|ARM64.Build.0 = Release|ARM64 {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Release|x64.ActiveCfg = Release|Any CPU {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Release|x64.Build.0 = Release|Any CPU {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Release|x86.ActiveCfg = Release|Any CPU {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F}.Release|x86.Build.0 = Release|Any CPU {D5596914-F824-45DD-9496-3D8A7FAD5796}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D5596914-F824-45DD-9496-3D8A7FAD5796}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5596914-F824-45DD-9496-3D8A7FAD5796}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {D5596914-F824-45DD-9496-3D8A7FAD5796}.Debug|ARM64.Build.0 = Debug|ARM64 {D5596914-F824-45DD-9496-3D8A7FAD5796}.Debug|x64.ActiveCfg = Debug|Any CPU {D5596914-F824-45DD-9496-3D8A7FAD5796}.Debug|x64.Build.0 = Debug|Any CPU {D5596914-F824-45DD-9496-3D8A7FAD5796}.Debug|x86.ActiveCfg = Debug|Any CPU {D5596914-F824-45DD-9496-3D8A7FAD5796}.Debug|x86.Build.0 = Debug|Any CPU {D5596914-F824-45DD-9496-3D8A7FAD5796}.Release|Any CPU.ActiveCfg = Release|Any CPU {D5596914-F824-45DD-9496-3D8A7FAD5796}.Release|Any CPU.Build.0 = Release|Any CPU + {D5596914-F824-45DD-9496-3D8A7FAD5796}.Release|ARM64.ActiveCfg = Release|ARM64 + {D5596914-F824-45DD-9496-3D8A7FAD5796}.Release|ARM64.Build.0 = Release|ARM64 {D5596914-F824-45DD-9496-3D8A7FAD5796}.Release|x64.ActiveCfg = Release|Any CPU {D5596914-F824-45DD-9496-3D8A7FAD5796}.Release|x64.Build.0 = Release|Any CPU {D5596914-F824-45DD-9496-3D8A7FAD5796}.Release|x86.ActiveCfg = Release|Any CPU {D5596914-F824-45DD-9496-3D8A7FAD5796}.Release|x86.Build.0 = Release|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Debug|x64.ActiveCfg = Debug|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Debug|x64.Build.0 = Debug|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Debug|x86.ActiveCfg = Debug|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Debug|x86.Build.0 = Debug|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Release|Any CPU.Build.0 = Release|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Release|x64.ActiveCfg = Release|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Release|x64.Build.0 = Release|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Release|x86.ActiveCfg = Release|Any CPU - {32817833-F567-4A92-BB57-8579A1D81DBA}.Release|x86.Build.0 = Release|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Debug|Any CPU.Build.0 = Debug|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Debug|x64.ActiveCfg = Debug|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Debug|x64.Build.0 = Debug|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Debug|x86.ActiveCfg = Debug|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Debug|x86.Build.0 = Debug|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Release|Any CPU.ActiveCfg = Release|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Release|Any CPU.Build.0 = Release|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Release|x64.ActiveCfg = Release|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Release|x64.Build.0 = Release|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Release|x86.ActiveCfg = Release|Any CPU - {354CB379-4F37-4C57-B71C-916257B7B328}.Release|x86.Build.0 = Release|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Debug|x64.ActiveCfg = Debug|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Debug|x64.Build.0 = Debug|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Debug|x86.ActiveCfg = Debug|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Debug|x86.Build.0 = Debug|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Release|Any CPU.Build.0 = Release|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Release|x64.ActiveCfg = Release|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Release|x64.Build.0 = Release|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Release|x86.ActiveCfg = Release|Any CPU - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E}.Release|x86.Build.0 = Release|Any CPU {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Debug|ARM64.Build.0 = Debug|ARM64 {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Debug|x64.ActiveCfg = Debug|Any CPU {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Debug|x64.Build.0 = Debug|Any CPU {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Debug|x86.ActiveCfg = Debug|Any CPU {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Debug|x86.Build.0 = Debug|Any CPU {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Release|Any CPU.ActiveCfg = Release|Any CPU {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Release|Any CPU.Build.0 = Release|Any CPU + {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Release|ARM64.ActiveCfg = Release|ARM64 + {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Release|ARM64.Build.0 = Release|ARM64 {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Release|x64.ActiveCfg = Release|Any CPU {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Release|x64.Build.0 = Release|Any CPU {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Release|x86.ActiveCfg = Release|Any CPU {9FAB310D-BB12-42A9-9E09-6762DF98DA0F}.Release|x86.Build.0 = Release|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Debug|Any CPU.Build.0 = Debug|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Debug|x64.ActiveCfg = Debug|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Debug|x64.Build.0 = Debug|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Debug|x86.ActiveCfg = Debug|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Debug|x86.Build.0 = Debug|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Release|Any CPU.ActiveCfg = Release|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Release|Any CPU.Build.0 = Release|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Release|x64.ActiveCfg = Release|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Release|x64.Build.0 = Release|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Release|x86.ActiveCfg = Release|Any CPU - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026}.Release|x86.Build.0 = Release|Any CPU {1CE13B94-7AD5-49A5-802C-945D34903C23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1CE13B94-7AD5-49A5-802C-945D34903C23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1CE13B94-7AD5-49A5-802C-945D34903C23}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {1CE13B94-7AD5-49A5-802C-945D34903C23}.Debug|ARM64.Build.0 = Debug|ARM64 {1CE13B94-7AD5-49A5-802C-945D34903C23}.Debug|x64.ActiveCfg = Debug|Any CPU {1CE13B94-7AD5-49A5-802C-945D34903C23}.Debug|x64.Build.0 = Debug|Any CPU {1CE13B94-7AD5-49A5-802C-945D34903C23}.Debug|x86.ActiveCfg = Debug|Any CPU {1CE13B94-7AD5-49A5-802C-945D34903C23}.Debug|x86.Build.0 = Debug|Any CPU {1CE13B94-7AD5-49A5-802C-945D34903C23}.Release|Any CPU.ActiveCfg = Release|Any CPU {1CE13B94-7AD5-49A5-802C-945D34903C23}.Release|Any CPU.Build.0 = Release|Any CPU + {1CE13B94-7AD5-49A5-802C-945D34903C23}.Release|ARM64.ActiveCfg = Release|ARM64 + {1CE13B94-7AD5-49A5-802C-945D34903C23}.Release|ARM64.Build.0 = Release|ARM64 {1CE13B94-7AD5-49A5-802C-945D34903C23}.Release|x64.ActiveCfg = Release|Any CPU {1CE13B94-7AD5-49A5-802C-945D34903C23}.Release|x64.Build.0 = Release|Any CPU {1CE13B94-7AD5-49A5-802C-945D34903C23}.Release|x86.ActiveCfg = Release|Any CPU {1CE13B94-7AD5-49A5-802C-945D34903C23}.Release|x86.Build.0 = Release|Any CPU {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Debug|ARM64.Build.0 = Debug|ARM64 {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Debug|x64.ActiveCfg = Debug|Any CPU {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Debug|x64.Build.0 = Debug|Any CPU {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Debug|x86.ActiveCfg = Debug|Any CPU {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Debug|x86.Build.0 = Debug|Any CPU {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Release|Any CPU.Build.0 = Release|Any CPU + {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Release|ARM64.ActiveCfg = Release|ARM64 + {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Release|ARM64.Build.0 = Release|ARM64 {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Release|x64.ActiveCfg = Release|Any CPU {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Release|x64.Build.0 = Release|Any CPU {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Release|x86.ActiveCfg = Release|Any CPU {688CEDDE-8105-49ED-937C-567B0F28B7AF}.Release|x86.Build.0 = Release|Any CPU {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Debug|ARM64.Build.0 = Debug|ARM64 {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Debug|x64.ActiveCfg = Debug|Any CPU {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Debug|x64.Build.0 = Debug|Any CPU {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Debug|x86.ActiveCfg = Debug|Any CPU {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Debug|x86.Build.0 = Debug|Any CPU {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Release|Any CPU.ActiveCfg = Release|Any CPU {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Release|Any CPU.Build.0 = Release|Any CPU + {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Release|ARM64.ActiveCfg = Release|ARM64 + {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Release|ARM64.Build.0 = Release|ARM64 {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Release|x64.ActiveCfg = Release|Any CPU {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Release|x64.Build.0 = Release|Any CPU {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Release|x86.ActiveCfg = Release|Any CPU {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0}.Release|x86.Build.0 = Release|Any CPU {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Debug|ARM64.Build.0 = Debug|ARM64 {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Debug|x64.ActiveCfg = Debug|Any CPU {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Debug|x64.Build.0 = Debug|Any CPU {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Debug|x86.ActiveCfg = Debug|Any CPU {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Debug|x86.Build.0 = Debug|Any CPU {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Release|Any CPU.ActiveCfg = Release|Any CPU {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Release|Any CPU.Build.0 = Release|Any CPU + {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Release|ARM64.ActiveCfg = Release|ARM64 + {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Release|ARM64.Build.0 = Release|ARM64 {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Release|x64.ActiveCfg = Release|Any CPU {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Release|x64.Build.0 = Release|Any CPU {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Release|x86.ActiveCfg = Release|Any CPU {6DF66A16-6F21-4A72-A366-C5E70E4C34EF}.Release|x86.Build.0 = Release|Any CPU {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Debug|ARM64.Build.0 = Debug|ARM64 {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Debug|x64.ActiveCfg = Debug|Any CPU {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Debug|x64.Build.0 = Debug|Any CPU {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Debug|x86.ActiveCfg = Debug|Any CPU {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Debug|x86.Build.0 = Debug|Any CPU {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Release|Any CPU.ActiveCfg = Release|Any CPU {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Release|Any CPU.Build.0 = Release|Any CPU + {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Release|ARM64.ActiveCfg = Release|ARM64 + {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Release|ARM64.Build.0 = Release|ARM64 {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Release|x64.ActiveCfg = Release|Any CPU {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Release|x64.Build.0 = Release|Any CPU {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Release|x86.ActiveCfg = Release|Any CPU {77BE3256-5CA0-490C-BB30-B187285E0EE6}.Release|x86.Build.0 = Release|Any CPU {753A3B06-C763-4869-8ECF-74274049624D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {753A3B06-C763-4869-8ECF-74274049624D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {753A3B06-C763-4869-8ECF-74274049624D}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {753A3B06-C763-4869-8ECF-74274049624D}.Debug|ARM64.Build.0 = Debug|ARM64 {753A3B06-C763-4869-8ECF-74274049624D}.Debug|x64.ActiveCfg = Debug|Any CPU {753A3B06-C763-4869-8ECF-74274049624D}.Debug|x64.Build.0 = Debug|Any CPU {753A3B06-C763-4869-8ECF-74274049624D}.Debug|x86.ActiveCfg = Debug|Any CPU {753A3B06-C763-4869-8ECF-74274049624D}.Debug|x86.Build.0 = Debug|Any CPU {753A3B06-C763-4869-8ECF-74274049624D}.Release|Any CPU.ActiveCfg = Release|Any CPU {753A3B06-C763-4869-8ECF-74274049624D}.Release|Any CPU.Build.0 = Release|Any CPU + {753A3B06-C763-4869-8ECF-74274049624D}.Release|ARM64.ActiveCfg = Release|ARM64 + {753A3B06-C763-4869-8ECF-74274049624D}.Release|ARM64.Build.0 = Release|ARM64 {753A3B06-C763-4869-8ECF-74274049624D}.Release|x64.ActiveCfg = Release|Any CPU {753A3B06-C763-4869-8ECF-74274049624D}.Release|x64.Build.0 = Release|Any CPU {753A3B06-C763-4869-8ECF-74274049624D}.Release|x86.ActiveCfg = Release|Any CPU {753A3B06-C763-4869-8ECF-74274049624D}.Release|x86.Build.0 = Release|Any CPU {C8931979-88CB-4C80-93CF-740680A5206E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C8931979-88CB-4C80-93CF-740680A5206E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8931979-88CB-4C80-93CF-740680A5206E}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C8931979-88CB-4C80-93CF-740680A5206E}.Debug|ARM64.Build.0 = Debug|ARM64 {C8931979-88CB-4C80-93CF-740680A5206E}.Debug|x64.ActiveCfg = Debug|Any CPU {C8931979-88CB-4C80-93CF-740680A5206E}.Debug|x64.Build.0 = Debug|Any CPU {C8931979-88CB-4C80-93CF-740680A5206E}.Debug|x86.ActiveCfg = Debug|Any CPU {C8931979-88CB-4C80-93CF-740680A5206E}.Debug|x86.Build.0 = Debug|Any CPU {C8931979-88CB-4C80-93CF-740680A5206E}.Release|Any CPU.ActiveCfg = Release|Any CPU {C8931979-88CB-4C80-93CF-740680A5206E}.Release|Any CPU.Build.0 = Release|Any CPU + {C8931979-88CB-4C80-93CF-740680A5206E}.Release|ARM64.ActiveCfg = Release|ARM64 + {C8931979-88CB-4C80-93CF-740680A5206E}.Release|ARM64.Build.0 = Release|ARM64 {C8931979-88CB-4C80-93CF-740680A5206E}.Release|x64.ActiveCfg = Release|Any CPU {C8931979-88CB-4C80-93CF-740680A5206E}.Release|x64.Build.0 = Release|Any CPU {C8931979-88CB-4C80-93CF-740680A5206E}.Release|x86.ActiveCfg = Release|Any CPU {C8931979-88CB-4C80-93CF-740680A5206E}.Release|x86.Build.0 = Release|Any CPU {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Debug|ARM64.Build.0 = Debug|ARM64 {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Debug|x64.ActiveCfg = Debug|Any CPU {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Debug|x64.Build.0 = Debug|Any CPU {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Debug|x86.ActiveCfg = Debug|Any CPU {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Debug|x86.Build.0 = Debug|Any CPU {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Release|Any CPU.ActiveCfg = Release|Any CPU {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Release|Any CPU.Build.0 = Release|Any CPU + {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Release|ARM64.ActiveCfg = Release|ARM64 + {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Release|ARM64.Build.0 = Release|ARM64 {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Release|x64.ActiveCfg = Release|Any CPU {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Release|x64.Build.0 = Release|Any CPU {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Release|x86.ActiveCfg = Release|Any CPU {E6ACC4BC-2A7D-4AB5-87BD-A28C7CD6A388}.Release|x86.Build.0 = Release|Any CPU {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Debug|ARM64.Build.0 = Debug|ARM64 {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Debug|x64.ActiveCfg = Debug|Any CPU {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Debug|x64.Build.0 = Debug|Any CPU {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Debug|x86.ActiveCfg = Debug|Any CPU {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Debug|x86.Build.0 = Debug|Any CPU {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Release|Any CPU.ActiveCfg = Release|Any CPU {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Release|Any CPU.Build.0 = Release|Any CPU + {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Release|ARM64.ActiveCfg = Release|ARM64 + {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Release|ARM64.Build.0 = Release|ARM64 {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Release|x64.ActiveCfg = Release|Any CPU {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Release|x64.Build.0 = Release|Any CPU {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Release|x86.ActiveCfg = Release|Any CPU {313EBBB8-C029-4A12-B898-EB6E18D025EA}.Release|x86.Build.0 = Release|Any CPU {3522105D-D4CD-4707-8613-271998B582DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3522105D-D4CD-4707-8613-271998B582DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3522105D-D4CD-4707-8613-271998B582DA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {3522105D-D4CD-4707-8613-271998B582DA}.Debug|ARM64.Build.0 = Debug|ARM64 {3522105D-D4CD-4707-8613-271998B582DA}.Debug|x64.ActiveCfg = Debug|Any CPU {3522105D-D4CD-4707-8613-271998B582DA}.Debug|x64.Build.0 = Debug|Any CPU {3522105D-D4CD-4707-8613-271998B582DA}.Debug|x86.ActiveCfg = Debug|Any CPU {3522105D-D4CD-4707-8613-271998B582DA}.Debug|x86.Build.0 = Debug|Any CPU {3522105D-D4CD-4707-8613-271998B582DA}.Release|Any CPU.ActiveCfg = Release|Any CPU {3522105D-D4CD-4707-8613-271998B582DA}.Release|Any CPU.Build.0 = Release|Any CPU + {3522105D-D4CD-4707-8613-271998B582DA}.Release|ARM64.ActiveCfg = Release|ARM64 + {3522105D-D4CD-4707-8613-271998B582DA}.Release|ARM64.Build.0 = Release|ARM64 {3522105D-D4CD-4707-8613-271998B582DA}.Release|x64.ActiveCfg = Release|Any CPU {3522105D-D4CD-4707-8613-271998B582DA}.Release|x64.Build.0 = Release|Any CPU {3522105D-D4CD-4707-8613-271998B582DA}.Release|x86.ActiveCfg = Release|Any CPU {3522105D-D4CD-4707-8613-271998B582DA}.Release|x86.Build.0 = Release|Any CPU {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Debug|ARM64.Build.0 = Debug|ARM64 {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Debug|x64.ActiveCfg = Debug|Any CPU {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Debug|x64.Build.0 = Debug|Any CPU {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Debug|x86.ActiveCfg = Debug|Any CPU {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Debug|x86.Build.0 = Debug|Any CPU {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Release|Any CPU.ActiveCfg = Release|Any CPU {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Release|Any CPU.Build.0 = Release|Any CPU + {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Release|ARM64.ActiveCfg = Release|ARM64 + {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Release|ARM64.Build.0 = Release|ARM64 {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Release|x64.ActiveCfg = Release|Any CPU {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Release|x64.Build.0 = Release|Any CPU {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Release|x86.ActiveCfg = Release|Any CPU {433F53CA-E2E3-4CE1-A342-4A358D1999FC}.Release|x86.Build.0 = Release|Any CPU {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Debug|ARM64.Build.0 = Debug|ARM64 {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Debug|x64.ActiveCfg = Debug|Any CPU {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Debug|x64.Build.0 = Debug|Any CPU {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Debug|x86.ActiveCfg = Debug|Any CPU {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Debug|x86.Build.0 = Debug|Any CPU {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Release|Any CPU.ActiveCfg = Release|Any CPU {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Release|Any CPU.Build.0 = Release|Any CPU + {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Release|ARM64.ActiveCfg = Release|ARM64 + {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Release|ARM64.Build.0 = Release|ARM64 {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Release|x64.ActiveCfg = Release|Any CPU {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Release|x64.Build.0 = Release|Any CPU {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Release|x86.ActiveCfg = Release|Any CPU {F4908758-811B-4D99-AEE7-3D9F3BC2E3C5}.Release|x86.Build.0 = Release|Any CPU {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Debug|ARM64.Build.0 = Debug|ARM64 {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Debug|x64.ActiveCfg = Debug|Any CPU {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Debug|x64.Build.0 = Debug|Any CPU {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Debug|x86.ActiveCfg = Debug|Any CPU {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Debug|x86.Build.0 = Debug|Any CPU {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Release|Any CPU.ActiveCfg = Release|Any CPU {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Release|Any CPU.Build.0 = Release|Any CPU + {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Release|ARM64.ActiveCfg = Release|ARM64 + {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Release|ARM64.Build.0 = Release|ARM64 {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Release|x64.ActiveCfg = Release|Any CPU {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Release|x64.Build.0 = Release|Any CPU {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Release|x86.ActiveCfg = Release|Any CPU {C8B78B43-EFEE-41CF-8BE9-1EA84AA18BF9}.Release|x86.Build.0 = Release|Any CPU {669BF256-765D-4BF1-9278-68EF33F86FFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {669BF256-765D-4BF1-9278-68EF33F86FFB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {669BF256-765D-4BF1-9278-68EF33F86FFB}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {669BF256-765D-4BF1-9278-68EF33F86FFB}.Debug|ARM64.Build.0 = Debug|ARM64 {669BF256-765D-4BF1-9278-68EF33F86FFB}.Debug|x64.ActiveCfg = Debug|Any CPU {669BF256-765D-4BF1-9278-68EF33F86FFB}.Debug|x64.Build.0 = Debug|Any CPU {669BF256-765D-4BF1-9278-68EF33F86FFB}.Debug|x86.ActiveCfg = Debug|Any CPU {669BF256-765D-4BF1-9278-68EF33F86FFB}.Debug|x86.Build.0 = Debug|Any CPU {669BF256-765D-4BF1-9278-68EF33F86FFB}.Release|Any CPU.ActiveCfg = Release|Any CPU {669BF256-765D-4BF1-9278-68EF33F86FFB}.Release|Any CPU.Build.0 = Release|Any CPU + {669BF256-765D-4BF1-9278-68EF33F86FFB}.Release|ARM64.ActiveCfg = Release|ARM64 + {669BF256-765D-4BF1-9278-68EF33F86FFB}.Release|ARM64.Build.0 = Release|ARM64 {669BF256-765D-4BF1-9278-68EF33F86FFB}.Release|x64.ActiveCfg = Release|Any CPU {669BF256-765D-4BF1-9278-68EF33F86FFB}.Release|x64.Build.0 = Release|Any CPU {669BF256-765D-4BF1-9278-68EF33F86FFB}.Release|x86.ActiveCfg = Release|Any CPU {669BF256-765D-4BF1-9278-68EF33F86FFB}.Release|x86.Build.0 = Release|Any CPU {CEE9045E-0299-4488-80FF-0162D099C544}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CEE9045E-0299-4488-80FF-0162D099C544}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CEE9045E-0299-4488-80FF-0162D099C544}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {CEE9045E-0299-4488-80FF-0162D099C544}.Debug|ARM64.Build.0 = Debug|ARM64 {CEE9045E-0299-4488-80FF-0162D099C544}.Debug|x64.ActiveCfg = Debug|Any CPU {CEE9045E-0299-4488-80FF-0162D099C544}.Debug|x64.Build.0 = Debug|Any CPU {CEE9045E-0299-4488-80FF-0162D099C544}.Debug|x86.ActiveCfg = Debug|Any CPU {CEE9045E-0299-4488-80FF-0162D099C544}.Debug|x86.Build.0 = Debug|Any CPU {CEE9045E-0299-4488-80FF-0162D099C544}.Release|Any CPU.ActiveCfg = Release|Any CPU {CEE9045E-0299-4488-80FF-0162D099C544}.Release|Any CPU.Build.0 = Release|Any CPU + {CEE9045E-0299-4488-80FF-0162D099C544}.Release|ARM64.ActiveCfg = Release|ARM64 + {CEE9045E-0299-4488-80FF-0162D099C544}.Release|ARM64.Build.0 = Release|ARM64 {CEE9045E-0299-4488-80FF-0162D099C544}.Release|x64.ActiveCfg = Release|Any CPU {CEE9045E-0299-4488-80FF-0162D099C544}.Release|x64.Build.0 = Release|Any CPU {CEE9045E-0299-4488-80FF-0162D099C544}.Release|x86.ActiveCfg = Release|Any CPU {CEE9045E-0299-4488-80FF-0162D099C544}.Release|x86.Build.0 = Release|Any CPU {070A1A8B-241E-45B8-882C-B33D79086E34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {070A1A8B-241E-45B8-882C-B33D79086E34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {070A1A8B-241E-45B8-882C-B33D79086E34}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {070A1A8B-241E-45B8-882C-B33D79086E34}.Debug|ARM64.Build.0 = Debug|ARM64 {070A1A8B-241E-45B8-882C-B33D79086E34}.Debug|x64.ActiveCfg = Debug|Any CPU {070A1A8B-241E-45B8-882C-B33D79086E34}.Debug|x64.Build.0 = Debug|Any CPU {070A1A8B-241E-45B8-882C-B33D79086E34}.Debug|x86.ActiveCfg = Debug|Any CPU {070A1A8B-241E-45B8-882C-B33D79086E34}.Debug|x86.Build.0 = Debug|Any CPU {070A1A8B-241E-45B8-882C-B33D79086E34}.Release|Any CPU.ActiveCfg = Release|Any CPU {070A1A8B-241E-45B8-882C-B33D79086E34}.Release|Any CPU.Build.0 = Release|Any CPU + {070A1A8B-241E-45B8-882C-B33D79086E34}.Release|ARM64.ActiveCfg = Release|ARM64 + {070A1A8B-241E-45B8-882C-B33D79086E34}.Release|ARM64.Build.0 = Release|ARM64 {070A1A8B-241E-45B8-882C-B33D79086E34}.Release|x64.ActiveCfg = Release|Any CPU {070A1A8B-241E-45B8-882C-B33D79086E34}.Release|x64.Build.0 = Release|Any CPU {070A1A8B-241E-45B8-882C-B33D79086E34}.Release|x86.ActiveCfg = Release|Any CPU {070A1A8B-241E-45B8-882C-B33D79086E34}.Release|x86.Build.0 = Release|Any CPU {37355661-376A-4F1D-B4A8-2B74D088571A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {37355661-376A-4F1D-B4A8-2B74D088571A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37355661-376A-4F1D-B4A8-2B74D088571A}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {37355661-376A-4F1D-B4A8-2B74D088571A}.Debug|ARM64.Build.0 = Debug|ARM64 {37355661-376A-4F1D-B4A8-2B74D088571A}.Debug|x64.ActiveCfg = Debug|Any CPU {37355661-376A-4F1D-B4A8-2B74D088571A}.Debug|x64.Build.0 = Debug|Any CPU {37355661-376A-4F1D-B4A8-2B74D088571A}.Debug|x86.ActiveCfg = Debug|Any CPU {37355661-376A-4F1D-B4A8-2B74D088571A}.Debug|x86.Build.0 = Debug|Any CPU {37355661-376A-4F1D-B4A8-2B74D088571A}.Release|Any CPU.ActiveCfg = Release|Any CPU {37355661-376A-4F1D-B4A8-2B74D088571A}.Release|Any CPU.Build.0 = Release|Any CPU + {37355661-376A-4F1D-B4A8-2B74D088571A}.Release|ARM64.ActiveCfg = Release|ARM64 + {37355661-376A-4F1D-B4A8-2B74D088571A}.Release|ARM64.Build.0 = Release|ARM64 {37355661-376A-4F1D-B4A8-2B74D088571A}.Release|x64.ActiveCfg = Release|Any CPU {37355661-376A-4F1D-B4A8-2B74D088571A}.Release|x64.Build.0 = Release|Any CPU {37355661-376A-4F1D-B4A8-2B74D088571A}.Release|x86.ActiveCfg = Release|Any CPU {37355661-376A-4F1D-B4A8-2B74D088571A}.Release|x86.Build.0 = Release|Any CPU {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Debug|ARM64.Build.0 = Debug|ARM64 {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Debug|x64.ActiveCfg = Debug|Any CPU {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Debug|x64.Build.0 = Debug|Any CPU {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Debug|x86.ActiveCfg = Debug|Any CPU {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Debug|x86.Build.0 = Debug|Any CPU {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Release|Any CPU.ActiveCfg = Release|Any CPU {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Release|Any CPU.Build.0 = Release|Any CPU + {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Release|ARM64.ActiveCfg = Release|ARM64 + {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Release|ARM64.Build.0 = Release|ARM64 {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Release|x64.ActiveCfg = Release|Any CPU {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Release|x64.Build.0 = Release|Any CPU {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Release|x86.ActiveCfg = Release|Any CPU {E4DC870F-6844-4031-B74D-F2B29B02ADD6}.Release|x86.Build.0 = Release|Any CPU {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Debug|ARM64.Build.0 = Debug|ARM64 {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Debug|x64.ActiveCfg = Debug|Any CPU {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Debug|x64.Build.0 = Debug|Any CPU {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Debug|x86.ActiveCfg = Debug|Any CPU {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Debug|x86.Build.0 = Debug|Any CPU {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Release|Any CPU.ActiveCfg = Release|Any CPU {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Release|Any CPU.Build.0 = Release|Any CPU + {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Release|ARM64.ActiveCfg = Release|ARM64 + {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Release|ARM64.Build.0 = Release|ARM64 {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Release|x64.ActiveCfg = Release|Any CPU {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Release|x64.Build.0 = Release|Any CPU {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Release|x86.ActiveCfg = Release|Any CPU {9B405749-AD48-49CC-ADE5-5D3AAB5A9D66}.Release|x86.Build.0 = Release|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Debug|ARM64.Build.0 = Debug|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Debug|x64.ActiveCfg = Debug|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Debug|x64.Build.0 = Debug|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Debug|x86.ActiveCfg = Debug|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Debug|x86.Build.0 = Debug|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Release|Any CPU.Build.0 = Release|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Release|ARM64.ActiveCfg = Release|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Release|ARM64.Build.0 = Release|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Release|x64.ActiveCfg = Release|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Release|x64.Build.0 = Release|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Release|x86.ActiveCfg = Release|Any CPU + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0}.Release|x86.Build.0 = Release|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Debug|ARM64.Build.0 = Debug|ARM64 + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Debug|x64.ActiveCfg = Debug|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Debug|x64.Build.0 = Debug|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Debug|x86.ActiveCfg = Debug|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Debug|x86.Build.0 = Debug|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Release|Any CPU.Build.0 = Release|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Release|ARM64.ActiveCfg = Release|ARM64 + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Release|ARM64.Build.0 = Release|ARM64 + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Release|x64.ActiveCfg = Release|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Release|x64.Build.0 = Release|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Release|x86.ActiveCfg = Release|Any CPU + {1C83BBB0-A89A-408D-9303-54C556BB5935}.Release|x86.Build.0 = Release|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Debug|ARM64.Build.0 = Debug|ARM64 + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Debug|x64.ActiveCfg = Debug|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Debug|x64.Build.0 = Debug|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Debug|x86.ActiveCfg = Debug|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Debug|x86.Build.0 = Debug|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Release|Any CPU.Build.0 = Release|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Release|ARM64.ActiveCfg = Release|ARM64 + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Release|ARM64.Build.0 = Release|ARM64 + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Release|x64.ActiveCfg = Release|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Release|x64.Build.0 = Release|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Release|x86.ActiveCfg = Release|Any CPU + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D}.Release|x86.Build.0 = Release|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Debug|ARM64.Build.0 = Debug|ARM64 + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Debug|x64.ActiveCfg = Debug|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Debug|x64.Build.0 = Debug|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Debug|x86.ActiveCfg = Debug|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Debug|x86.Build.0 = Debug|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Release|Any CPU.Build.0 = Release|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Release|ARM64.ActiveCfg = Release|ARM64 + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Release|ARM64.Build.0 = Release|ARM64 + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Release|x64.ActiveCfg = Release|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Release|x64.Build.0 = Release|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Release|x86.ActiveCfg = Release|Any CPU + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91}.Release|x86.Build.0 = Release|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Debug|ARM64.Build.0 = Debug|ARM64 + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Debug|x64.ActiveCfg = Debug|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Debug|x64.Build.0 = Debug|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Debug|x86.ActiveCfg = Debug|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Debug|x86.Build.0 = Debug|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Release|Any CPU.Build.0 = Release|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Release|ARM64.ActiveCfg = Release|ARM64 + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Release|ARM64.Build.0 = Release|ARM64 + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Release|x64.ActiveCfg = Release|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Release|x64.Build.0 = Release|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Release|x86.ActiveCfg = Release|Any CPU + {870F3B44-FDA4-460F-A102-17C15F4373E5}.Release|x86.Build.0 = Release|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Debug|ARM64.Build.0 = Debug|ARM64 + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Debug|x64.ActiveCfg = Debug|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Debug|x64.Build.0 = Debug|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Debug|x86.ActiveCfg = Debug|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Debug|x86.Build.0 = Debug|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Release|Any CPU.Build.0 = Release|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Release|ARM64.ActiveCfg = Release|ARM64 + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Release|ARM64.Build.0 = Release|ARM64 + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Release|x64.ActiveCfg = Release|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Release|x64.Build.0 = Release|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Release|x86.ActiveCfg = Release|Any CPU + {4C7525B9-1B55-429E-92AC-04248BC1247C}.Release|x86.Build.0 = Release|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Debug|ARM64.Build.0 = Debug|ARM64 + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Debug|x64.ActiveCfg = Debug|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Debug|x64.Build.0 = Debug|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Debug|x86.ActiveCfg = Debug|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Debug|x86.Build.0 = Debug|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Release|Any CPU.Build.0 = Release|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Release|ARM64.ActiveCfg = Release|ARM64 + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Release|ARM64.Build.0 = Release|ARM64 + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Release|x64.ActiveCfg = Release|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Release|x64.Build.0 = Release|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Release|x86.ActiveCfg = Release|Any CPU + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8}.Release|x86.Build.0 = Release|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Debug|ARM64.Build.0 = Debug|ARM64 + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Debug|x64.ActiveCfg = Debug|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Debug|x64.Build.0 = Debug|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Debug|x86.ActiveCfg = Debug|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Debug|x86.Build.0 = Debug|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Release|Any CPU.Build.0 = Release|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Release|ARM64.ActiveCfg = Release|ARM64 + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Release|ARM64.Build.0 = Release|ARM64 + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Release|x64.ActiveCfg = Release|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Release|x64.Build.0 = Release|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Release|x86.ActiveCfg = Release|Any CPU + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178}.Release|x86.Build.0 = Release|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {230E0930-C155-4433-A64F-C9BF77A7086D}.Debug|ARM64.Build.0 = Debug|ARM64 + {230E0930-C155-4433-A64F-C9BF77A7086D}.Debug|x64.ActiveCfg = Debug|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Debug|x64.Build.0 = Debug|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Debug|x86.ActiveCfg = Debug|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Debug|x86.Build.0 = Debug|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Release|Any CPU.Build.0 = Release|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Release|ARM64.ActiveCfg = Release|ARM64 + {230E0930-C155-4433-A64F-C9BF77A7086D}.Release|ARM64.Build.0 = Release|ARM64 + {230E0930-C155-4433-A64F-C9BF77A7086D}.Release|x64.ActiveCfg = Release|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Release|x64.Build.0 = Release|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Release|x86.ActiveCfg = Release|Any CPU + {230E0930-C155-4433-A64F-C9BF77A7086D}.Release|x86.Build.0 = Release|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Debug|ARM64.Build.0 = Debug|ARM64 + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Debug|x64.ActiveCfg = Debug|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Debug|x64.Build.0 = Debug|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Debug|x86.ActiveCfg = Debug|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Debug|x86.Build.0 = Debug|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Release|Any CPU.Build.0 = Release|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Release|ARM64.ActiveCfg = Release|ARM64 + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Release|ARM64.Build.0 = Release|ARM64 + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Release|x64.ActiveCfg = Release|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Release|x64.Build.0 = Release|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Release|x86.ActiveCfg = Release|Any CPU + {71D82911-0F26-46F8-9D14-7F564AEBF6DD}.Release|x86.Build.0 = Release|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {30469297-B321-41B8-B594-7D84BEE3DF45}.Debug|ARM64.Build.0 = Debug|ARM64 + {30469297-B321-41B8-B594-7D84BEE3DF45}.Debug|x64.ActiveCfg = Debug|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Debug|x64.Build.0 = Debug|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Debug|x86.ActiveCfg = Debug|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Debug|x86.Build.0 = Debug|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Release|Any CPU.Build.0 = Release|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Release|ARM64.ActiveCfg = Release|ARM64 + {30469297-B321-41B8-B594-7D84BEE3DF45}.Release|ARM64.Build.0 = Release|ARM64 + {30469297-B321-41B8-B594-7D84BEE3DF45}.Release|x64.ActiveCfg = Release|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Release|x64.Build.0 = Release|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Release|x86.ActiveCfg = Release|Any CPU + {30469297-B321-41B8-B594-7D84BEE3DF45}.Release|x86.Build.0 = Release|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Debug|ARM64.Build.0 = Debug|ARM64 + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Debug|x64.ActiveCfg = Debug|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Debug|x64.Build.0 = Debug|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Debug|x86.ActiveCfg = Debug|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Debug|x86.Build.0 = Debug|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Release|Any CPU.Build.0 = Release|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Release|ARM64.ActiveCfg = Release|ARM64 + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Release|ARM64.Build.0 = Release|ARM64 + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Release|x64.ActiveCfg = Release|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Release|x64.Build.0 = Release|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Release|x86.ActiveCfg = Release|Any CPU + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F}.Release|x86.Build.0 = Release|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Debug|ARM64.Build.0 = Debug|ARM64 + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Debug|x64.ActiveCfg = Debug|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Debug|x64.Build.0 = Debug|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Debug|x86.ActiveCfg = Debug|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Debug|x86.Build.0 = Debug|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Release|Any CPU.Build.0 = Release|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Release|ARM64.ActiveCfg = Release|ARM64 + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Release|ARM64.Build.0 = Release|ARM64 + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Release|x64.ActiveCfg = Release|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Release|x64.Build.0 = Release|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Release|x86.ActiveCfg = Release|Any CPU + {7AB9D305-664C-463D-91F9-3DBD1379F9F3}.Release|x86.Build.0 = Release|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {3CEBC034-C137-484F-827A-B6B190497DCD}.Debug|ARM64.Build.0 = Debug|ARM64 + {3CEBC034-C137-484F-827A-B6B190497DCD}.Debug|x64.ActiveCfg = Debug|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Debug|x64.Build.0 = Debug|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Debug|x86.ActiveCfg = Debug|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Debug|x86.Build.0 = Debug|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Release|Any CPU.Build.0 = Release|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Release|ARM64.ActiveCfg = Release|ARM64 + {3CEBC034-C137-484F-827A-B6B190497DCD}.Release|ARM64.Build.0 = Release|ARM64 + {3CEBC034-C137-484F-827A-B6B190497DCD}.Release|x64.ActiveCfg = Release|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Release|x64.Build.0 = Release|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Release|x86.ActiveCfg = Release|Any CPU + {3CEBC034-C137-484F-827A-B6B190497DCD}.Release|x86.Build.0 = Release|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Debug|ARM64.Build.0 = Debug|ARM64 + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Debug|x64.ActiveCfg = Debug|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Debug|x64.Build.0 = Debug|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Debug|x86.ActiveCfg = Debug|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Debug|x86.Build.0 = Debug|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Release|Any CPU.Build.0 = Release|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Release|ARM64.ActiveCfg = Release|ARM64 + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Release|ARM64.Build.0 = Release|ARM64 + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Release|x64.ActiveCfg = Release|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Release|x64.Build.0 = Release|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Release|x86.ActiveCfg = Release|Any CPU + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9}.Release|x86.Build.0 = Release|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Debug|ARM64.Build.0 = Debug|ARM64 + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Debug|x64.ActiveCfg = Debug|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Debug|x64.Build.0 = Debug|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Debug|x86.ActiveCfg = Debug|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Debug|x86.Build.0 = Debug|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Release|Any CPU.Build.0 = Release|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Release|ARM64.ActiveCfg = Release|ARM64 + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Release|ARM64.Build.0 = Release|ARM64 + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Release|x64.ActiveCfg = Release|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Release|x64.Build.0 = Release|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Release|x86.ActiveCfg = Release|Any CPU + {1F1204ED-F445-4888-8171-4C06ED7CAABD}.Release|x86.Build.0 = Release|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Debug|ARM64.Build.0 = Debug|ARM64 + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Debug|x64.ActiveCfg = Debug|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Debug|x64.Build.0 = Debug|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Debug|x86.ActiveCfg = Debug|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Debug|x86.Build.0 = Debug|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Release|Any CPU.Build.0 = Release|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Release|ARM64.ActiveCfg = Release|ARM64 + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Release|ARM64.Build.0 = Release|ARM64 + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Release|x64.ActiveCfg = Release|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Release|x64.Build.0 = Release|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Release|x86.ActiveCfg = Release|Any CPU + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1139,24 +1541,10 @@ Global {153BD6AB-6B34-4E97-A96D-4ED5826DC037} = {56EA9268-0B36-46CB-B8F0-871DBEED5D4F} {2088B3AF-F9AF-45B8-B824-16749D5DAF9E} = {56EA9268-0B36-46CB-B8F0-871DBEED5D4F} {89E58A49-12C4-4C22-B646-348B6BFCCB4D} = {56EA9268-0B36-46CB-B8F0-871DBEED5D4F} - {8CEF18CA-9009-47F5-ADF4-63E73E6B663B} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} - {E2404BB9-0B08-4DDB-AA8A-D55DAD042E62} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} - {AF9F8787-E233-4DBF-B973-916EBCD88D96} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} - {A4955C19-C422-45E6-9F01-5AE2E9A76B2F} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} - {321C6410-B154-45BD-B44A-7CD451BBA9F0} = {AF9F8787-E233-4DBF-B973-916EBCD88D96} - {076A3785-83CD-4AE3-BE45-1AE183587731} = {AF9F8787-E233-4DBF-B973-916EBCD88D96} - {0997005B-E6FF-4D3F-AACE-C29338C7977F} = {AF9F8787-E233-4DBF-B973-916EBCD88D96} - {15F67655-8025-4389-8FF7-3F3CA7F543DA} = {A4955C19-C422-45E6-9F01-5AE2E9A76B2F} - {1BCFC9AF-6570-4996-949D-3C45F3411712} = {A4955C19-C422-45E6-9F01-5AE2E9A76B2F} - {219FADE8-5473-4099-8291-7C29AA6F4808} = {A4955C19-C422-45E6-9F01-5AE2E9A76B2F} {BCEADFB1-3446-4E82-91C1-E7A5D4E731C2} = {E85D3982-0792-430A-9E58-8B7C1A329F88} {A3EB6441-4729-4FC9-B0E8-E0A075D4DF4F} = {E85D3982-0792-430A-9E58-8B7C1A329F88} {D5596914-F824-45DD-9496-3D8A7FAD5796} = {E85D3982-0792-430A-9E58-8B7C1A329F88} - {32817833-F567-4A92-BB57-8579A1D81DBA} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} - {354CB379-4F37-4C57-B71C-916257B7B328} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} - {E635ECAF-7338-4B82-A606-CAFEDCC11D6E} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} {9FAB310D-BB12-42A9-9E09-6762DF98DA0F} = {E85D3982-0792-430A-9E58-8B7C1A329F88} - {99B7AEAE-EFC1-4343-ACAA-AA621E3E1026} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} {688CEDDE-8105-49ED-937C-567B0F28B7AF} = {7B4E6671-D28C-4159-BB16-40CEAC76EE73} {C5CF6D06-C762-4DBE-8771-CE64B9CC81E0} = {7B4E6671-D28C-4159-BB16-40CEAC76EE73} {6DF66A16-6F21-4A72-A366-C5E70E4C34EF} = {D2A5F6DB-29AA-47C2-9AF9-96E294328139} @@ -1173,6 +1561,28 @@ Global {070A1A8B-241E-45B8-882C-B33D79086E34} = {209CAB96-3CE8-4F93-A535-2B93C9A6AA32} {37355661-376A-4F1D-B4A8-2B74D088571A} = {209CAB96-3CE8-4F93-A535-2B93C9A6AA32} {E4DC870F-6844-4031-B74D-F2B29B02ADD6} = {2A968101-45CA-421C-A546-00D681BF3C76} + {344BB22E-AEEA-46C9-9F27-AF4D0057FEF0} = {DBBD9699-0909-4E8C-98BA-1CE8C25381D3} + {1C83BBB0-A89A-408D-9303-54C556BB5935} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} + {55EF4887-99D7-48BE-8D07-E7E34D6A1A9D} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} + {9AA73BAF-4FB4-4B14-9698-7F07B10DBB91} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} + {870F3B44-FDA4-460F-A102-17C15F4373E5} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} + {92A18CCE-33CE-4986-80CD-B27131A77F77} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} + {4C7525B9-1B55-429E-92AC-04248BC1247C} = {92A18CCE-33CE-4986-80CD-B27131A77F77} + {1812EACD-7CF3-463A-BEAB-7C3650A5FF01} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} + {CB08C2EB-3A3A-4756-B19A-329BEB1DF6E8} = {1812EACD-7CF3-463A-BEAB-7C3650A5FF01} + {55B42F87-2CA6-46BA-BCBE-513D4EF7F178} = {1812EACD-7CF3-463A-BEAB-7C3650A5FF01} + {8398224D-0FB2-4E68-8095-5530531BA561} = {7DB123DC-28AF-4C6E-B8F9-8A88399A5D3F} + {230E0930-C155-4433-A64F-C9BF77A7086D} = {8398224D-0FB2-4E68-8095-5530531BA561} + {71D82911-0F26-46F8-9D14-7F564AEBF6DD} = {8398224D-0FB2-4E68-8095-5530531BA561} + {8ADCEED2-41BD-47F8-BD49-5F1C3F3C748B} = {21A233DF-8DB7-4299-BE46-2AD4AC2655DB} + {30469297-B321-41B8-B594-7D84BEE3DF45} = {8ADCEED2-41BD-47F8-BD49-5F1C3F3C748B} + {7C258EBD-7ECA-4F4D-8618-40704DFCD16F} = {8ADCEED2-41BD-47F8-BD49-5F1C3F3C748B} + {7AB9D305-664C-463D-91F9-3DBD1379F9F3} = {8ADCEED2-41BD-47F8-BD49-5F1C3F3C748B} + {3E7A8ABD-6F8D-4EA0-BE9F-C77FD5ECC1B3} = {21A233DF-8DB7-4299-BE46-2AD4AC2655DB} + {3CEBC034-C137-484F-827A-B6B190497DCD} = {3E7A8ABD-6F8D-4EA0-BE9F-C77FD5ECC1B3} + {F2DDC33F-DF0B-4BE9-9265-046EC14BE2E9} = {3E7A8ABD-6F8D-4EA0-BE9F-C77FD5ECC1B3} + {1F1204ED-F445-4888-8171-4C06ED7CAABD} = {3E7A8ABD-6F8D-4EA0-BE9F-C77FD5ECC1B3} + {C4C6DBB4-870D-4AA2-8F10-98CC0B1292D8} = {E85D3982-0792-430A-9E58-8B7C1A329F88} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5CFD3EA5-ADCA-48F0-9E3F-BBC76CCBF1C2} diff --git a/Setup/Images/ProtonDrive.bmp b/Setup/Images/ProtonDrive.bmp new file mode 100644 index 000000000..a8a725157 Binary files /dev/null and b/Setup/Images/ProtonDrive.bmp differ diff --git a/Setup/Images/ProtonMail.bmp b/Setup/Images/ProtonMail.bmp new file mode 100644 index 000000000..8b80ede12 Binary files /dev/null and b/Setup/Images/ProtonMail.bmp differ diff --git a/Setup/Images/ProtonPass.bmp b/Setup/Images/ProtonPass.bmp new file mode 100644 index 000000000..6419365b9 Binary files /dev/null and b/Setup/Images/ProtonPass.bmp differ diff --git a/Setup/Native/arm64/ProtonVPN.CalloutDriver.inf b/Setup/Native/arm64/ProtonVPN.CalloutDriver.inf new file mode 100644 index 000000000..fcee7510b --- /dev/null +++ b/Setup/Native/arm64/ProtonVPN.CalloutDriver.inf @@ -0,0 +1,55 @@ +; +; ProtonVPN.CalloutDriver.inf +; + +[Version] +Signature = "$WINDOWS NT$" +Class = WFPCALLOUTS +ClassGuid = {57465043-616C-6C6F-7574-5F636C617373} +Provider = %ManufacturerName% +CatalogFile = ProtonVPN.CalloutDriver.cat +DriverVer = 08/19/2024,15.41.59.712 + +[SourceDisksNames] +1 = %DiskName%,,,"" + +[SourceDisksFiles] +ProtonVPN.CalloutDriver.sys = 1,, + +[DestinationDirs] +DefaultDestDir = 12 ; %WinDir%\System32\Drivers +ProtonVPN.CalloutDriver.Files = 12 ; %WinDir%\System32\Drivers + +[DefaultInstall.NTARM64] +OptionDesc = %ServiceDescription% +CopyFiles = ProtonVPN.CalloutDriver.Files + +[DefaultUninstall.NTARM64] +LegacyUninstall = 1 +DelFiles = ProtonVPN.CalloutDriver.Files + +[DefaultInstall.NTARM64.Services] +AddService = %ServiceName%,,ProtonVPN.CalloutDriver.Service + +[DefaultUninstall.NTARM64.Services] +DelService = %ServiceName%,0x200 ; SPSVCINST_STOPSERVICE + +[ProtonVPN.CalloutDriver.Files] +ProtonVPN.CalloutDriver.sys,,,0x00000040 ; COPYFLG_OVERWRITE_OLDER_ONLY + +[ProtonVPN.CalloutDriver.Service] +DisplayName = %ServiceDisplayName% +Description = %ServiceDescription% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\ProtonVPN.CalloutDriver.sys +LoadOrderGroup = NDIS +Dependencies = TCPIP ; Load after TCPIP.sys + +[Strings] +ManufacturerName = "Proton AG" +DiskName = "ProtonVPN Callout Driver Installation Disk" +ServiceName = "ProtonVPNCallout" +ServiceDisplayName = "ProtonVPN Callout" +ServiceDescription = "ProtonVPN Callout Driver" diff --git a/Setup/Native/arm64/ProtonVPN.CalloutDriver.sys b/Setup/Native/arm64/ProtonVPN.CalloutDriver.sys new file mode 100644 index 000000000..57b351d29 Binary files /dev/null and b/Setup/Native/arm64/ProtonVPN.CalloutDriver.sys differ diff --git a/Setup/Native/arm64/libcrypto-3-arm64.dll b/Setup/Native/arm64/libcrypto-3-arm64.dll new file mode 100644 index 000000000..3640cf039 Binary files /dev/null and b/Setup/Native/arm64/libcrypto-3-arm64.dll differ diff --git a/Setup/Native/arm64/libpkcs11-helper-1.dll b/Setup/Native/arm64/libpkcs11-helper-1.dll new file mode 100644 index 000000000..fe8d50ad6 Binary files /dev/null and b/Setup/Native/arm64/libpkcs11-helper-1.dll differ diff --git a/Setup/Native/arm64/libssl-3-arm64.dll b/Setup/Native/arm64/libssl-3-arm64.dll new file mode 100644 index 000000000..59320275e Binary files /dev/null and b/Setup/Native/arm64/libssl-3-arm64.dll differ diff --git a/Setup/Native/arm64/openvpn.exe b/Setup/Native/arm64/openvpn.exe new file mode 100644 index 000000000..dbccc1414 Binary files /dev/null and b/Setup/Native/arm64/openvpn.exe differ diff --git a/Setup/Native/arm64/protonvpn.calloutdriver.cat b/Setup/Native/arm64/protonvpn.calloutdriver.cat new file mode 100644 index 000000000..73c2a544d Binary files /dev/null and b/Setup/Native/arm64/protonvpn.calloutdriver.cat differ diff --git a/Setup/Native/arm64/tunnel.dll b/Setup/Native/arm64/tunnel.dll new file mode 100644 index 000000000..5110e2cef Binary files /dev/null and b/Setup/Native/arm64/tunnel.dll differ diff --git a/Setup/Native/arm64/wintun.dll b/Setup/Native/arm64/wintun.dll new file mode 100644 index 000000000..dc4e4aeeb Binary files /dev/null and b/Setup/Native/arm64/wintun.dll differ diff --git a/Setup/Native/arm64/wireguard-tunnel-tcp.dll b/Setup/Native/arm64/wireguard-tunnel-tcp.dll new file mode 100644 index 000000000..8762942e2 Binary files /dev/null and b/Setup/Native/arm64/wireguard-tunnel-tcp.dll differ diff --git a/Setup/Native/arm64/wireguard.dll b/Setup/Native/arm64/wireguard.dll new file mode 100644 index 000000000..d49df5c02 Binary files /dev/null and b/Setup/Native/arm64/wireguard.dll differ diff --git a/Setup/SplitTunnel/ProtonVPN.CalloutDriver.inf b/Setup/Native/x64/ProtonVPN.CalloutDriver.inf similarity index 100% rename from Setup/SplitTunnel/ProtonVPN.CalloutDriver.inf rename to Setup/Native/x64/ProtonVPN.CalloutDriver.inf diff --git a/Setup/SplitTunnel/ProtonVPN.CalloutDriver.sys b/Setup/Native/x64/ProtonVPN.CalloutDriver.sys similarity index 100% rename from Setup/SplitTunnel/ProtonVPN.CalloutDriver.sys rename to Setup/Native/x64/ProtonVPN.CalloutDriver.sys diff --git a/src/ProtonVPN.Vpn/Resources/libcrypto-3-x64.dll b/Setup/Native/x64/libcrypto-3-x64.dll similarity index 54% rename from src/ProtonVPN.Vpn/Resources/libcrypto-3-x64.dll rename to Setup/Native/x64/libcrypto-3-x64.dll index 9b11e29c5..9f8422730 100644 Binary files a/src/ProtonVPN.Vpn/Resources/libcrypto-3-x64.dll and b/Setup/Native/x64/libcrypto-3-x64.dll differ diff --git a/Setup/Native/x64/libpkcs11-helper-1.dll b/Setup/Native/x64/libpkcs11-helper-1.dll new file mode 100644 index 000000000..1ed67739e Binary files /dev/null and b/Setup/Native/x64/libpkcs11-helper-1.dll differ diff --git a/Setup/Native/x64/libssl-3-x64.dll b/Setup/Native/x64/libssl-3-x64.dll new file mode 100644 index 000000000..3ab91e4ee Binary files /dev/null and b/Setup/Native/x64/libssl-3-x64.dll differ diff --git a/Setup/Native/x64/openvpn.exe b/Setup/Native/x64/openvpn.exe new file mode 100644 index 000000000..be296070b Binary files /dev/null and b/Setup/Native/x64/openvpn.exe differ diff --git a/Setup/SplitTunnel/protonvpn.calloutdriver.cat b/Setup/Native/x64/protonvpn.calloutdriver.cat similarity index 100% rename from Setup/SplitTunnel/protonvpn.calloutdriver.cat rename to Setup/Native/x64/protonvpn.calloutdriver.cat diff --git a/src/ProtonVPN.Vpn/Resources/tunnel.dll b/Setup/Native/x64/tunnel.dll similarity index 100% rename from src/ProtonVPN.Vpn/Resources/tunnel.dll rename to Setup/Native/x64/tunnel.dll diff --git a/src/ProtonVPN.Vpn/Resources/vcruntime140.dll b/Setup/Native/x64/vcruntime140.dll similarity index 100% rename from src/ProtonVPN.Vpn/Resources/vcruntime140.dll rename to Setup/Native/x64/vcruntime140.dll diff --git a/Setup/WireGuard/wintun.dll b/Setup/Native/x64/wintun.dll similarity index 100% rename from Setup/WireGuard/wintun.dll rename to Setup/Native/x64/wintun.dll diff --git a/Setup/WireGuard/wireguard-tunnel-tcp.dll b/Setup/Native/x64/wireguard-tunnel-tcp.dll similarity index 100% rename from Setup/WireGuard/wireguard-tunnel-tcp.dll rename to Setup/Native/x64/wireguard-tunnel-tcp.dll diff --git a/src/ProtonVPN.Vpn/Resources/wireguard.dll b/Setup/Native/x64/wireguard.dll similarity index 100% rename from src/ProtonVPN.Vpn/Resources/wireguard.dll rename to Setup/Native/x64/wireguard.dll diff --git a/Setup/Setup.arm64.iss b/Setup/Setup.arm64.iss new file mode 100644 index 000000000..e1329a0e1 --- /dev/null +++ b/Setup/Setup.arm64.iss @@ -0,0 +1,33 @@ +[Setup] +ArchitecturesAllowed=arm64 + +#define Architecture "arm64" +#define SourcePath GetEnv("BUILD_PATH") +#define IsBTISource SourcePath == "src/bin/win-arm64/BTI/publish" +#if IsBTISource +#define OutputBaseSuffix "_BTI" +#else +#define OutputBaseSuffix "" +#endif + +#include "SetupBase.iss" + +[Files] +Source: "Native\arm64\tunnel.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; +Source: "Native\arm64\wintun.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; +Source: "Native\arm64\wireguard.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; +Source: "Native\arm64\wireguard-tunnel-tcp.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; + +Source: "Native\arm64\libcrypto-3-arm64.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; +Source: "Native\arm64\libpkcs11-helper-1.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; +Source: "Native\arm64\libssl-3-arm64.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; +Source: "Native\arm64\openvpn.exe"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; + +Source: "Native\arm64\ProtonVPN.CalloutDriver.sys"; DestDir: "{app}\{#VersionFolder}\Resources"; AfterInstall: InstallNetworkDriver; + +Source: "tap\arm64\tapinstall.exe"; DestDir: "{app}\{#VersionFolder}\Resources\tap"; +Source: "tap\arm64\OemVista.inf"; DestDir: "{app}\{#VersionFolder}\Resources\tap"; +Source: "tap\arm64\tapprotonvpn.cat"; DestDir: "{app}\{#VersionFolder}\Resources\tap"; +Source: "tap\arm64\tapprotonvpn.sys"; DestDir: "{app}\{#VersionFolder}\Resources\tap"; + +Source: "..\{#SourcePath}\runtimes\win-arm64\native\*"; DestDir: "{app}\{#VersionFolder}\runtimes\win-arm64\native"; \ No newline at end of file diff --git a/Setup/Setup.x64.iss b/Setup/Setup.x64.iss new file mode 100644 index 000000000..f0a0bafa4 --- /dev/null +++ b/Setup/Setup.x64.iss @@ -0,0 +1,34 @@ +[Setup] +ArchitecturesAllowed=x64os + +#define Architecture "x64" +#define SourcePath GetEnv("BUILD_PATH") +#define IsBTISource SourcePath == "src/bin/win-x64/BTI/publish" +#if IsBTISource +#define OutputBaseSuffix "_BTI" +#else +#define OutputBaseSuffix "" +#endif + +#include "SetupBase.iss" + +[Files] +Source: "Native\x64\tunnel.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; +Source: "Native\x64\wintun.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; +Source: "Native\x64\wireguard.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; +Source: "Native\x64\wireguard-tunnel-tcp.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; + +Source: "Native\x64\libcrypto-3-x64.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; +Source: "Native\x64\libpkcs11-helper-1.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; +Source: "Native\x64\libssl-3-x64.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; +Source: "Native\x64\openvpn.exe"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; +Source: "Native\x64\vcruntime140.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; + +Source: "Native\x64\ProtonVPN.CalloutDriver.sys"; DestDir: "{app}\{#VersionFolder}\Resources"; AfterInstall: InstallNetworkDriver; + +Source: "tap\x64\tapinstall.exe"; DestDir: "{app}\{#VersionFolder}\Resources\tap"; +Source: "tap\x64\OemVista.inf"; DestDir: "{app}\{#VersionFolder}\Resources\tap"; +Source: "tap\x64\tapprotonvpn.cat"; DestDir: "{app}\{#VersionFolder}\Resources\tap"; +Source: "tap\x64\tapprotonvpn.Sys"; DestDir: "{app}\{#VersionFolder}\Resources\tap"; + +Source: "..\{#SourcePath}\runtimes\win-x64\native\*"; DestDir: "{app}\{#VersionFolder}\runtimes\win-x64\native"; \ No newline at end of file diff --git a/Setup/setup.iss b/Setup/SetupBase.iss similarity index 61% rename from Setup/setup.iss rename to Setup/SetupBase.iss index 01131701e..714b71ea1 100644 --- a/Setup/setup.iss +++ b/Setup/SetupBase.iss @@ -15,21 +15,16 @@ #define NetworkDriverName "ProtonVPNCallout" #define NetworkDriverFileName "Resources\ProtonVPN.CalloutDriver.sys" -#define ProtonDriveDownloaderName "ProtonDrive.Downloader.exe" +#define ProtonInstallerName "ProtonInstaller.exe" #define Webview2InstallerName "MicrosoftEdgeWebview2Setup.exe" #define InstallLogPath "{app}\Install.log.txt" +#define ClearAppDataClientArg "-DoUninstallActions" + +#define ProtonDriveUpgradeCode "{F3B95BD2-1311-4B82-8B4A-B9EB7C0500ED}" #define Hash "" #define VersionFolder "v" + MyAppVersion -#define ClearAppDataClientArg "-DoUninstallActions" #define AppFolder "Proton\VPN" -#define SourcePath GetEnv("BUILD_PATH") -#define IsBTISource SourcePath == "src/bin/win-x64/BTI/publish" -#if IsBTISource -#define OutputBaseSuffix "_BTI" -#else -#define OutputBaseSuffix "" -#endif [Setup] AppName={#MyAppName} @@ -42,21 +37,23 @@ DisableProgramGroupPage=auto AppPublisher={#MyPublisher} UninstallDisplayIcon={app}\{#LauncherExeName} UninstallDisplayName={#MyAppName} -OutputBaseFilename=ProtonVPN_{#VersionFolder}{#OutputBaseSuffix} +OutputBaseFilename=ProtonVPN_{#VersionFolder}_{#Architecture}{#OutputBaseSuffix} +ArchitecturesInstallIn64BitMode=x64compatible WizardStyle=modern Compression=lzma2 SolidCompression=yes OutputDir=Installers -ArchitecturesInstallIn64BitMode=x64 SetupIconFile=Images\protonvpn.ico SetupLogging=yes DisableFinishedPage=yes DisableStartupPrompt=yes +DisableReadyPage=yes DirExistsWarning=no VersionInfoProductTextVersion={#MyAppVersion}-{#hash} VersionInfoVersion={#MyAppVersion} AppCopyright= 2022 {#MyPublisher} -SignTool=signtool sign /a /tr http://timestamp.globalsign.com/tsa/r6advanced1 /td SHA256 /fd SHA256 $f + +SignTool=signtool sign /a /tr http://timestamp.sectigo.com /td SHA256 /fd SHA256 $f [Messages] SetupWindowTitle={#MyAppName} @@ -84,8 +81,7 @@ Source: "..\{#SourcePath}\*.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: sign Source: "..\{#SourcePath}\*.exe"; Excludes: "ProtonVPN.exe,ProtonVPN.Launcher.exe,ProtonVPNService.exe,createdump.exe"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; Source: "..\{#SourcePath}\*.deps.json"; DestDir: "{app}\{#VersionFolder}"; Source: "..\{#SourcePath}\*.dll.config"; DestDir: "{app}\{#VersionFolder}"; - -Source: "..\{#SourcePath}\runtimes\win-x64\native\*"; DestDir: "{app}\{#VersionFolder}\runtimes\win-x64\native"; +Source: "..\{#SourcePath}\Resources\ProtonVPN.InstallActions.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; Source: "..\{#SourcePath}\en-US\ProtonVPN.Translations.resources.dll"; DestDir: "{app}\{#VersionFolder}\en-US"; Flags: signonce; Source: "..\{#SourcePath}\cs-CZ\ProtonVPN.Translations.resources.dll"; DestDir: "{app}\{#VersionFolder}\cs-CZ"; Flags: signonce; @@ -118,31 +114,23 @@ Source: "..\{#SourcePath}\nn-NO\ProtonVPN.Translations.resources.dll"; DestDir: Source: "..\{#SourcePath}\nb-NO\ProtonVPN.Translations.resources.dll"; DestDir: "{app}\{#VersionFolder}\nb-NO"; Flags: signonce; Source: "..\{#SourcePath}\sl-SI\ProtonVPN.Translations.resources.dll"; DestDir: "{app}\{#VersionFolder}\sl-SI"; Flags: signonce; -Source: "..\{#SourcePath}\Resources\*.dll"; Excludes: "ProtonVPN.InstallActions.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; -Source: "..\{#SourcePath}\Resources\*.exe"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; -Source: "..\{#SourcePath}\Resources\ProtonVPN.InstallActions.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; -Source: "..\src\ProtonVPN.Vpn\Resources\wireguard.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; -Source: "..\src\ProtonVPN.Vpn\Resources\tunnel.dll"; DestDir: "{app}\{#VersionFolder}"; Flags: signonce; - -Source: "tap\tapinstall.exe"; DestDir: "{app}\{#VersionFolder}\Resources\tap" -Source: "tap\OemVista.inf"; DestDir: "{app}\{#VersionFolder}\Resources\tap" -Source: "tap\tapprotonvpn.cat"; DestDir: "{app}\{#VersionFolder}\Resources\tap" -Source: "tap\tapprotonvpn.Sys"; DestDir: "{app}\{#VersionFolder}\Resources\tap"; +Source: "..\{#SourcePath}\Resources\ProtonVPN.InstallActions.x86.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; +Source: "..\{#SourcePath}\Resources\LocalAgent.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; +Source: "..\{#SourcePath}\Resources\ProtonVPN.IPFilter.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; +Source: "..\{#SourcePath}\Resources\ProtonVPN.NetworkUtil.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; +Source: "..\{#SourcePath}\Resources\GoSrp.dll"; DestDir: "{app}\{#VersionFolder}\Resources"; Flags: signonce; -Source: "SplitTunnel\ProtonVPN.CalloutDriver.sys"; DestDir: "{app}\{#VersionFolder}\Resources"; AfterInstall: InstallNetworkDriver; -Source: "WireGuard\wintun.dll"; DestDir: "{app}\{#VersionFolder}"; -Source: "WireGuard\wireguard-tunnel-tcp.dll"; DestDir: "{app}\{#VersionFolder}"; Source: "GuestHoleServers.json"; DestDir: "{app}\{#VersionFolder}\Resources"; Source: "Dependencies\{#Webview2InstallerName}"; Flags: dontcopy; +Source: "Images\Proton*.bmp"; Flags: dontcopy; + [Icons] Name: "{group}\Proton VPN"; Filename: "{app}\{#LauncherExeName}" Name: "{commondesktop}\Proton VPN"; Filename: "{app}\{#LauncherExeName}"; Tasks: desktopicon; AppUserModelID: "{#AppUserModelID}"; [Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; -Name: "installProtonDrive"; Description: "{cm:InstallProtonDriveTitle}"; Check: ShouldDisplayProtonDriveCheckbox; -Name: "installWebview2"; Description: "Install Microsoft Edge WebView2 runtime"; Check: ShouldDisplayWebview2Checkbox; +Name: "desktopicon"; Description: "{cm:CreateDesktopShortcuts}"; [Languages] Name: "en_US"; MessagesFile: "compiler:Default.isl,Strings\Default.isl" @@ -230,15 +218,250 @@ type TInt64Array = array of Int64; var - IsToReboot, IsSilent, IsVerySilent, IsToDisableAutoUpdate: Boolean; + IsToReboot, IsSilent, IsVerySilent, IsNotSilent, IsToDisableAutoUpdate: Boolean; InstallationProgressLabel: TNewStaticText; + ProductDriveCheckBox, ProductMailCheckBox, ProductPassCheckBox: TNewCheckBox; + +const + ProductLogoWidth = 140; + ProductLogoHeight = 36; + PanelWidth = 500; + PanelHeight = 50; + Padding = 10; + PanelSpacing = 10; + +procedure OnProductDriveClick(Sender: TObject); +begin + ProductDriveCheckBox.Checked := not ProductDriveCheckBox.Checked; +end; + +procedure OnProductMailClick(Sender: TObject); +begin + ProductMailCheckBox.Checked := not ProductMailCheckBox.Checked; +end; + +procedure OnProductPassClick(Sender: TObject); +begin + ProductPassCheckBox.Checked := not ProductPassCheckBox.Checked; +end; procedure InitializeWizard; +var + // Proton product vars + HeaderLabel, SubHeaderLabel: TLabel; + ProductDriveLabelA, ProductMailLabelA, ProductPassLabelA: TLabel; + ProductDriveLabelB, ProductMailLabelB, ProductPassLabelB: TLabel; + ProductDriveImage, ProductMailImage, ProductPassImage: TBitmapImage; + ProductDrivePanel, ProductMailPanel, ProductPassPanel: TPanel; + ProductDrivePanelOverlay, ProductMailPanelOverlay, ProductPassPanelOverlay: TLabel; + IsProductDriveInstalled, IsProductMailInstalled, IsProductPassInstalled, IsArm64: Boolean; + ProductPadding: Int64; begin + IsArm64 := ExpandConstant('{#Architecture}') = 'arm64'; InstallationProgressLabel := TNewStaticText.Create(WizardForm); InstallationProgressLabel.Parent := WizardForm.InstallingPage; InstallationProgressLabel.Top := ScaleY(100); InstallationProgressLabel.Left := 0; + + HeaderLabel := TLabel.Create(WizardForm.SelectTasksPage); + HeaderLabel.Parent := WizardForm.SelectTasksPage; + HeaderLabel.Caption := CustomMessage('InstallerTitle'); + HeaderLabel.AutoSize := True; + HeaderLabel.WordWrap := True; + HeaderLabel.Top := 0; + HeaderLabel.Width := ScaleX(PanelWidth); + HeaderLabel.Font.Size := 14; + + IsProductMailInstalled := RegValueExists(HKEY_CURRENT_USER, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\proton_mail', 'DisplayVersion'); + IsProductDriveInstalled := IsProductInstalled('{#ProtonDriveUpgradeCode}') <> 0; + IsProductPassInstalled := RegValueExists(HKEY_CURRENT_USER, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\ProtonPass', 'DisplayVersion'); + + SubHeaderLabel := TLabel.Create(WizardForm.SelectTasksPage); + SubHeaderLabel.Parent := WizardForm.SelectTasksPage; + SubHeaderLabel.Top := HeaderLabel.Top + HeaderLabel.Height + ScaleY(32); + SubHeaderLabel.Caption := CustomMessage('InstallOtherApps'); + SubHeaderLabel.WordWrap := True; + SubHeaderLabel.Width := ScaleX(PanelWidth); + SubHeaderLabel.Font.Size := 8; + SubHeaderLabel.Font.Style := [fsBold]; + + if not IsProductMailInstalled or not IsProductDriveInstalled or not IsProductPassInstalled then begin + ExtractTemporaryFile('ProtonMail.bmp'); + ExtractTemporaryFile('ProtonDrive.bmp'); + ExtractTemporaryFile('ProtonPass.bmp'); + + ProductPadding := ScaleY(PanelSpacing); + + // Proton Mail + ProductMailPanel := TPanel.Create(WizardForm.SelectTasksPage); + ProductMailPanel.Parent := WizardForm.SelectTasksPage; + ProductMailPanel.SetBounds(0, SubHeaderLabel.Top + SubHeaderLabel.Height + ProductPadding, ScaleX(PanelWidth), ScaleY(PanelHeight)); + ProductMailPanel.BevelOuter := bvNone; + + ProductMailCheckBox := TNewCheckBox.Create(ProductMailPanel); + ProductMailCheckBox.Parent := ProductMailPanel; + ProductMailCheckBox.Top := ScaleX(Padding); + ProductMailCheckBox.Left := ScaleX(Padding); + ProductMailCheckBox.Width := ScaleX(14); + ProductMailCheckBox.Height := ScaleY(14); + ProductMailCheckBox.Checked := not IsProductMailInstalled; + + ProductMailImage := TBitmapImage.Create(ProductMailPanel); + ProductMailImage.Parent := ProductMailPanel; + ProductMailImage.Bitmap.LoadFromFile(ExpandConstant('{tmp}\ProtonMail.bmp')); + ProductMailImage.Stretch := True; + ProductMailImage.SetBounds(ProductMailCheckBox.Left + ScaleX(21), ProductMailCheckBox.Top - ScaleY(2), ScaleX(82), ScaleY(22)); + + ProductMailLabelA := TLabel.Create(ProductMailPanel); + ProductMailLabelA.Parent := ProductMailPanel; + ProductMailLabelA.Caption := CustomMessage('FreeTrial') + ' - '; + ProductMailLabelA.AutoSize := True; + ProductMailLabelA.Top := ProductMailImage.Top + ProductMailImage.Height + ScaleY(5); + ProductMailLabelA.Left := ProductMailImage.Left; + ProductMailLabelA.Width := ScaleX(PanelWidth - Padding); + ProductMailLabelA.Font.Style := [fsBold]; + + ProductMailLabelB := TLabel.Create(ProductMailPanel); + ProductMailLabelB.Parent := ProductMailPanel; + ProductMailLabelB.Caption := CustomMessage('ProtonMailDescription'); + ProductMailLabelB.AutoSize := True; + ProductMailLabelB.Top := ProductMailLabelA.Top; + ProductMailLabelB.Left := ProductMailLabelA.Left + ProductMailLabelA.Width; + ProductMailLabelB.WordWrap := True; + + ProductMailPanelOverlay := TLabel.Create(ProductMailPanel); + ProductMailPanelOverlay.Parent := ProductMailPanel; + ProductMailPanelOverlay.Width := ScaleX(PanelWidth); + ProductMailPanelOverlay.Height := ScaleY(PanelHeight); + ProductMailPanelOverlay.Transparent := True; + ProductMailPanelOverlay.OnClick := @OnProductMailClick; + + if IsProductMailInstalled then begin + ProductMailPanel.Visible := False; + ProductMailPanel.Height := 0; + ProductPadding := 0; + end; + + // Proton Drive + ProductDrivePanel := TPanel.Create(WizardForm.SelectTasksPage); + ProductDrivePanel.Parent := WizardForm.SelectTasksPage; + ProductDrivePanel.SetBounds(0, ProductMailPanel.Top + ProductMailPanel.Height + ProductPadding, ScaleX(PanelWidth), ScaleY(PanelHeight)); + ProductDrivePanel.BevelOuter := bvNone; + + ProductDriveCheckBox := TNewCheckBox.Create(ProductDrivePanel); + ProductDriveCheckBox.Parent := ProductDrivePanel; + ProductDriveCheckBox.Top := ScaleX(Padding); + ProductDriveCheckBox.Left := ScaleX(Padding); + ProductDriveCheckBox.Width := ScaleX(14); + ProductDriveCheckBox.Height := ScaleY(14); + ProductDriveCheckBox.Checked := not IsProductDriveInstalled and not IsArm64; // Drive doesn't work on arm64 + + ProductDriveImage := TBitmapImage.Create(ProductDrivePanel); + ProductDriveImage.Parent := ProductDrivePanel; + ProductDriveImage.Bitmap.LoadFromFile(ExpandConstant('{tmp}\ProtonDrive.bmp')); + ProductDriveImage.Stretch := True; + ProductDriveImage.SetBounds(ProductDriveCheckBox.Left + ScaleX(21), ProductDriveCheckBox.Top - ScaleY(2), ScaleX(86), ScaleY(22)); + + ProductDriveLabelA := TLabel.Create(ProductDrivePanel); + ProductDriveLabelA.Parent := ProductDrivePanel; + ProductDriveLabelA.Caption := CustomMessage('Free') + ' - '; + ProductDriveLabelA.AutoSize := True; + ProductDriveLabelA.Top := ProductDriveImage.Top + ProductDriveImage.Height + ScaleY(5); + ProductDriveLabelA.Left := ProductDriveImage.Left; + ProductDriveLabelA.Width := ScaleX(PanelWidth - Padding); + ProductDriveLabelA.Font.Style := [fsBold]; + + ProductDriveLabelB := TLabel.Create(ProductDrivePanel); + ProductDriveLabelB.Parent := ProductDrivePanel; + ProductDriveLabelB.Caption := CustomMessage('ProtonDriveDescription'); + ProductDriveLabelB.AutoSize := True; + ProductDriveLabelB.Top := ProductDriveLabelA.Top; + ProductDriveLabelB.Left := ProductDriveLabelA.Left + ProductDriveLabelA.Width; + ProductDriveLabelB.WordWrap := True; + + ProductDrivePanelOverlay := TLabel.Create(ProductDrivePanel); + ProductDrivePanelOverlay.Parent := ProductDrivePanel; + ProductDrivePanelOverlay.Width := ScaleX(PanelWidth); + ProductDrivePanelOverlay.Height := ScaleY(PanelHeight); + ProductDrivePanelOverlay.Transparent := True; + ProductDrivePanelOverlay.OnClick := @OnProductDriveClick; + + // Drive doesn't work on arm64 + if IsProductDriveInstalled or IsArm64 then begin + ProductDrivePanel.Visible := False; + ProductDrivePanel.Height := 0; + ProductPadding := 0; + end else + ProductPadding := ScaleX(PanelSpacing); + + // Proton Pass + ProductPassPanel := TPanel.Create(WizardForm.SelectTasksPage); + ProductPassPanel.Parent := WizardForm.SelectTasksPage; + ProductPassPanel.SetBounds(0, ProductDrivePanel.Top + ProductDrivePanel.Height + ProductPadding, ScaleX(PanelWidth), ScaleY(PanelHeight)); + ProductPassPanel.BevelOuter := bvNone; + + ProductPassCheckBox := TNewCheckBox.Create(ProductPassPanel); + ProductPassCheckBox.Parent := ProductPassPanel; + ProductPassCheckBox.Top := ScaleX(Padding); + ProductPassCheckBox.Left := ScaleX(Padding); + ProductPassCheckBox.Width := ScaleX(14); + ProductPassCheckBox.Height := ScaleY(14); + ProductPassCheckBox.Checked := not IsProductPassInstalled; + + ProductPassImage := TBitmapImage.Create(ProductPassPanel); + ProductPassImage.Parent := ProductPassPanel; + ProductPassImage.Bitmap.LoadFromFile(ExpandConstant('{tmp}\ProtonPass.bmp')); + ProductPassImage.Stretch := True; + ProductPassImage.SetBounds(ProductPassCheckBox.Left + ScaleX(21), ProductPassCheckBox.Top - ScaleY(2), ScaleX(84), ScaleY(22)); + + ProductPassLabelA := TLabel.Create(ProductPassPanel); + ProductPassLabelA.Parent := ProductPassPanel; + ProductPassLabelA.Caption := CustomMessage('Free') + ' - '; + ProductPassLabelA.AutoSize := True; + ProductPassLabelA.Top := ProductPassImage.Top + ProductPassImage.Height + ScaleY(5); + ProductPassLabelA.Left := ProductPassImage.Left; + ProductPassLabelA.Width := ScaleX(PanelWidth - Padding); + ProductPassLabelA.Font.Style := [fsBold]; + + ProductPassLabelB := TLabel.Create(ProductPassPanel); + ProductPassLabelB.Parent := ProductPassPanel; + ProductPassLabelB.Caption := CustomMessage('ProtonPassDescription'); + ProductPassLabelB.AutoSize := True; + ProductPassLabelB.Top := ProductPassLabelA.Top; + ProductPassLabelB.Left := ProductPassLabelA.Left + ProductPassLabelA.Width; + ProductPassLabelB.WordWrap := True; + + ProductPassPanelOverlay := TLabel.Create(ProductPassPanel); + ProductPassPanelOverlay.Parent := ProductPassPanel; + ProductPassPanelOverlay.Width := ScaleX(PanelWidth); + ProductPassPanelOverlay.Height := ScaleY(PanelHeight); + ProductPassPanelOverlay.Transparent := True; + ProductPassPanelOverlay.OnClick := @OnProductPassClick; + + if IsProductPassInstalled then begin + ProductPassPanel.Visible := False; + ProductPassPanel.Height := 0; + end; + + WizardForm.TasksList.Top := ProductPassPanel.Top + ProductPassPanel.Height + ScaleY(16); + WizardForm.TasksList.Left := ProductPassCheckBox.Left - ScaleX(4); + end; + + // Hide top window section + WizardForm.SelectTasksLabel.Visible := False; +end; + +procedure CurPageChanged(CurPageID: Integer); +begin + if CurPageID = wpSelectTasks then begin + WizardForm.MainPanel.Visible := False; + WizardForm.InnerNotebook.Top := ScaleY(40); + WizardForm.NextButton.Caption := SetupMessage(msgButtonInstall); + end else begin + WizardForm.MainPanel.Visible := True; + WizardForm.InnerNotebook.Top := ScaleY(72); + WizardForm.NextButton.Caption := SetupMessage(msgButtonNext); + end; end; function NeedRestart(): Boolean; @@ -350,7 +573,8 @@ begin if CompareText(ParamStr(i), '/verysilent') = 0 then IsVerySilent := True else if CompareText(ParamStr(i), '/silent') = 0 then - IsSilent := True + IsSilent := True; + IsNotSilent := (IsVerySilent = false) and (IsSilent = false); end; procedure SetIsToDisableAutoUpdate(); @@ -446,9 +670,26 @@ end; procedure CurStepChanged(CurStep: TSetupStep); var - logfilepathname, logfilename, newfilepathname, langCode, launcherArgs: String; + logfilepathname, logfilename, newfilepathname, langCode, launcherArgs, productArguments: String; res: Integer; begin + productArguments := ''; + launcherArgs := ''; + if IsNotSilent then begin + if Assigned(ProductMailCheckBox) and ProductMailCheckBox.Checked then begin + productArguments := productArguments + ' /Mail'; + launcherArgs := launcherArgs + ' /MailInstalled'; + end; + if Assigned(ProductDriveCheckBox) and ProductDriveCheckBox.Checked then begin + productArguments := productArguments + ' /Drive'; + launcherArgs := launcherArgs + ' /DriveInstalled'; + end; + if Assigned(ProductPassCheckBox) and ProductPassCheckBox.Checked then begin + productArguments := productArguments + ' /Pass'; + launcherArgs := launcherArgs + ' /PassInstalled'; + end; + end; + if CurStep = ssDone then begin logfilepathname := ExpandConstant('{log}'); logfilename := ExtractFileName(logfilepathname); @@ -459,29 +700,33 @@ begin end; RestoreOldUserConfigFolder(ExpandConstant('{app}')); if (not IsToReboot or WizardForm.NoRadio.Checked = True) and IsVerySilent = false then begin - launcherArgs := ''; if WizardSilent() = false then begin langCode := ActiveLanguage(); StringChangeEx(langCode, '_', '-', True); - launcherArgs := '/lang ' + langCode; + launcherArgs := launcherArgs + ' /lang ' + langCode; end; if IsToDisableAutoUpdate = true then begin launcherArgs := launcherArgs + ' /DisableAutoUpdate'; end; - ExecAsOriginalUser(ExpandConstant('{app}\{#LauncherExeName}'), launcherArgs, '', SW_SHOW, ewNoWait, res); + + if IsNotSilent then + launcherArgs := launcherArgs + ' /CleanInstall'; + + ExecAsOriginalUser(ExpandConstant('{app}\{#LauncherExeName}'), Trim(launcherArgs), '', SW_SHOW, ewNoWait, res); end; end else if CurStep = ssPostInstall then begin - if (IsVerySilent = false) and (IsSilent = false) then begin - if WizardIsTaskSelected('installWebview2') then begin + if IsNotSilent then begin + if not RegValueExists(HKLM, 'SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv') then begin InstallationProgressLabel.Caption := CustomMessage('InstallingWebview2Runtime'); WizardForm.Refresh(); ExtractTemporaryFile('{#Webview2InstallerName}'); LaunchUnelevatedProcess(ExpandConstant('{tmp}\{#Webview2InstallerName}'), '/silent /install', True); end; - if WizardIsTaskSelected('installProtonDrive') then begin - LaunchUnelevatedProcess(ExpandConstant('{app}\{#VersionFolder}\{#ProtonDriveDownloaderName}'), '', False); - end; + if productArguments <> '' then + if WizardIsTaskSelected('desktopicon') then + productArguments := productArguments + ' /CreateDesktopShortcut'; + LaunchUnelevatedProcess(ExpandConstant('{app}\{#VersionFolder}\{#ProtonInstallerName}'), Trim(productArguments), False); end; end; end; @@ -506,14 +751,4 @@ begin LaunchUnelevatedProcessOnUninstall(ExpandConstant('{app}\{#VersionFolder}\{#MyAppExeName}'), '{#ClearAppDataClientArg}', True); UnloadDLL(ExpandConstant('{app}\{#VersionFolder}\Resources\ProtonVPN.InstallActions.x86.dll')); end; -end; - -function ShouldDisplayProtonDriveCheckbox: Boolean; -begin - Result := IsProductInstalled('{F3B95BD2-1311-4B82-8B4A-B9EB7C0500ED}') = 0; -end; - -function ShouldDisplayWebview2Checkbox: Boolean; -begin - Result := not RegValueExists(HKLM, 'SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}', 'pv'); end; \ No newline at end of file diff --git a/Setup/Strings/BrazilianPortuguese.isl b/Setup/Strings/BrazilianPortuguese.isl index 6dbae94d4..918071ce4 100644 --- a/Setup/Strings/BrazilianPortuguese.isl +++ b/Setup/Strings/BrazilianPortuguese.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Instale Proton Drive — Armazenamento de nuvem criptografado (Gratuito com Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN está pronto para ser instalado +InstallOtherApps=Selecione outros aplicativos Proton para instalar. Esses serviços estão inclusos no seu plano. +FreeTrial=Avaliação gratuita +Free=Free +ProtonMailDescription=E-mail criptografado que é privado por padrão. +ProtonDriveDescription=Armazenamento seguro em nuvem que oferece a você o controle dos seus dados. +ProtonPassDescription=Um gerenciador de senhas criptografadas que protege sua identidade on-line. +InstallingWebview2Runtime=Instalando Web View 2 runtime... +CreateDesktopShortcuts=Criar atalho na área de trabalho \ No newline at end of file diff --git a/Setup/Strings/Czech.isl b/Setup/Strings/Czech.isl index a954ab03e..78019b72c 100644 --- a/Setup/Strings/Czech.isl +++ b/Setup/Strings/Czech.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Nainstalujte si Proton Drive - Šifrované cloudové úložiště (zdarma s Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN je připravena k instalaci +InstallOtherApps=Vyberte další aplikace Proton, které chcete nainstalovat. Tyto služby jsou součástí vašeho tarifu. +FreeTrial=Bezplatná zkušební verze +Free=Bezplatné +ProtonMailDescription=Šifrovaný e-mail, který je ve výchozím nastavení soukromý. +ProtonDriveDescription=Bezpečné cloudové úložiště, které vám dává kontrolu nad vašimi daty. +ProtonPassDescription=Šifrovaný správce hesel, který chrání vaši online identitu. +InstallingWebview2Runtime=Instalace Web View 2 runtime... +CreateDesktopShortcuts=Vytvořit zástupce na ploše \ No newline at end of file diff --git a/Setup/Strings/Default.isl b/Setup/Strings/Default.isl index 17f51e74e..ff6fbdbdd 100644 --- a/Setup/Strings/Default.isl +++ b/Setup/Strings/Default.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Install Proton Drive - Encrypted cloud storage (Free with Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN is ready to be installed +InstallOtherApps=Select other Proton apps to install. These services are included in your plan. +FreeTrial=Free trial +Free=Free +ProtonMailDescription=Encrypted email that's private by default. +ProtonDriveDescription=Secure cloud storage that gives you control of your data. +ProtonPassDescription=Encrypted password manager that protects your online identity. +InstallingWebview2Runtime=Installing Web View 2 runtime... +CreateDesktopShortcuts=Create desktop shortcut(s) \ No newline at end of file diff --git a/Setup/Strings/Dutch.isl b/Setup/Strings/Dutch.isl index fb79b0750..ce628ac6f 100644 --- a/Setup/Strings/Dutch.isl +++ b/Setup/Strings/Dutch.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Installeer Proton Drive - Versleutelde cloudopslag (Gratis met Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN is klaar om te worden geïnstalleerd +InstallOtherApps=Selecteer andere Proton-apps om te installeren. Deze diensten zijn inbegrepen in uw abonnement. +FreeTrial=Gratis proefversie +Free=Gratis +ProtonMailDescription=Versleutelde e-mail die standaard privé is. +ProtonDriveDescription=Beveiligde cloudopslag die u de controle over uw gegevens geeft. +ProtonPassDescription=Versleutelde wachtwoordmanager die uw online identiteit beschermt. +InstallingWebview2Runtime=Web View 2 runtime installeren... +CreateDesktopShortcuts=Maak bureaublad snelkoppeling(en) aan \ No newline at end of file diff --git a/Setup/Strings/Finnish.isl b/Setup/Strings/Finnish.isl index f68081951..766bfdf43 100644 --- a/Setup/Strings/Finnish.isl +++ b/Setup/Strings/Finnish.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Asenna Proton Drive - Salattu pilvitallennus (ilmainen Proton VPN:n kanssa) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN on valmis asennettavaksi +InstallOtherApps=Valitse muut asennettavat Proton-sovellukset. Nämä palvelut kuuluvat tilaukseesi. +FreeTrial=Ilmainen kokeilu +Free=Free +ProtonMailDescription=Salattu sähköposti, joka on oletusarvoisesti yksityinen. +ProtonDriveDescription=Suojattu pilvitallennus, jonka avulla hallitset itse omia tietojasi. +ProtonPassDescription=Salattu salasanahallinta, joka suojaa verkkoidentiteettisi. +InstallingWebview2Runtime=Asennetaan Web View 2 Runtimeä.. +CreateDesktopShortcuts=Luo pikakuvakkeet työpöydälle \ No newline at end of file diff --git a/Setup/Strings/French.isl b/Setup/Strings/French.isl index 6f4b0a31d..07c6c9f29 100644 --- a/Setup/Strings/French.isl +++ b/Setup/Strings/French.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Installez Proton Drive : un espace de stockage chiffré dans le cloud (gratuit avec Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN est prêt à être installé. +InstallOtherApps=Sélectionnez d'autres applications Proton à installer. Ces services sont inclus dans votre abonnement. +FreeTrial=Essai gratuit +Free=Gratuit +ProtonMailDescription=Votre messagerie chiffrée, pour des messages privés. +ProtonDriveDescription=Un espace de stockage sécurisé qui vous donne le contrôle de vos données. +ProtonPassDescription=Un gestionnaire de mots de passe chiffré qui protège votre identité en ligne. +InstallingWebview2Runtime=Installation du runtime Web View 2... +CreateDesktopShortcuts=Créer un ou plusieurs raccourcis sur le bureau \ No newline at end of file diff --git a/Setup/Strings/German.isl b/Setup/Strings/German.isl index 241efc6c5..2a3d0735b 100644 --- a/Setup/Strings/German.isl +++ b/Setup/Strings/German.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Proton Drive installieren - Verschlüsselter Cloud-Speicher (kostenlos mit Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN ist bereit zur Installation +InstallOtherApps=Wähle weitere Proton-Apps zur Installation aus. Diese Dienste sind in deinem Abonnement enthalten. +FreeTrial=Kostenlose Testphase +Free=Kostenlos +ProtonMailDescription=Verschlüsselte E-Mails, die standardmäßig privat sind. +ProtonDriveDescription=Sicherer Cloud-Speicher, der dir die volle Kontrolle über deine Daten gibt. +ProtonPassDescription=Ein verschlüsselter Passwort-Manager, der deine Online-Identität schützt. +InstallingWebview2Runtime=Installation der Laufzeitumgebung von Web View 2... +CreateDesktopShortcuts=Desktopverknüpfung(en) erzeugen \ No newline at end of file diff --git a/Setup/Strings/Italian.isl b/Setup/Strings/Italian.isl index 788f62879..dc4c2d5fb 100644 --- a/Setup/Strings/Italian.isl +++ b/Setup/Strings/Italian.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Installa Proton Drive - Archiviazione su cloud crittografata (Gratuita con Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN è pronto per essere installato +InstallOtherApps=Seleziona altre app Proton da installare. Questi servizi sono inclusi nel tuo piano. +FreeTrial=Prova gratuita +Free=Gratuito +ProtonMailDescription=Email crittografata: la privacy al primo posto. +ProtonDriveDescription=Archiviazione sicura su cloud per il pieno controllo dei tuoi dati. +ProtonPassDescription=Gestore di password crittografato che protegge la tua identità online. +InstallingWebview2Runtime=Installazione del runtime di Web View 2... +CreateDesktopShortcuts=Crea un collegamento sul desktop \ No newline at end of file diff --git a/Setup/Strings/Japanese.isl b/Setup/Strings/Japanese.isl index af21eba51..4b54d1142 100644 --- a/Setup/Strings/Japanese.isl +++ b/Setup/Strings/Japanese.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Proton Drive をインストール - 暗号化クラウドストレージ (無料で利用可能) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPNをインストールする準備ができました +InstallOtherApps=インストールする他のProtonアプリを選択してください。これらのサービスはプランに含まれています。 +FreeTrial=無料トライアル +Free=無料 +ProtonMailDescription=デフォルトでプライバシーが保護される、暗号化メール。 +ProtonDriveDescription=自分のデータを自分でコントロールできる、安全なクラウドストレージ。 +ProtonPassDescription=認証情報を保護する、暗号化パスワードマネージャー。 +InstallingWebview2Runtime=Web View 2 ランタイムをインストール中... +CreateDesktopShortcuts=デスクトップにショートカットを作成 \ No newline at end of file diff --git a/Setup/Strings/Norwegian.isl b/Setup/Strings/Norwegian.isl index bb87922e0..244dc125e 100644 --- a/Setup/Strings/Norwegian.isl +++ b/Setup/Strings/Norwegian.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Installer Proton Drive - kryptert skylagring (gratis med Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN er klar til å installeres +InstallOtherApps=Velg andre Proton-apper å installere. Disse tjenestene er inkludert i planen din. +FreeTrial=Gratis prøveversjon +Free=Gratis +ProtonMailDescription=Kryptert e-post som er privat som standard. +ProtonDriveDescription=Sikker skylagring som gir deg kontroll over dataene dine. +ProtonPassDescription=Kryptert passordbehandler som beskytter identiteten din på nettet. +InstallingWebview2Runtime=Installerer Web View 2-kjøreinnstillinger... +CreateDesktopShortcuts=Opprett skrivebordssnarvei(-er) \ No newline at end of file diff --git a/Setup/Strings/Polish.isl b/Setup/Strings/Polish.isl index 3e1f409b8..ac5b35ea5 100644 --- a/Setup/Strings/Polish.isl +++ b/Setup/Strings/Polish.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Zainstaluj Proton Drive - Szyfrowana przestrzeń dyskowa w chmurze (za darmo z usługą Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN jest gotowy do zainstalowania +InstallOtherApps=Wybierz inne aplikacje Proton do zainstalowania. Twój plan zawiera te usługi. +FreeTrial=Darmowa wersja próbna +Free=Za darmo +ProtonMailDescription=Szyfrowana poczta e-mail, która zapewnia prywatność. +ProtonDriveDescription=Bezpieczna przestrzeń dyskowa w chmurze, która daje Ci kontrolę nad Twoimi danymi. +ProtonPassDescription=Szyfrowany menedżer haseł, który chroni Twoją tożsamość online. +InstallingWebview2Runtime=Instalowanie środowiska Web View 2... +CreateDesktopShortcuts=Utwórz skróty na pulpicie \ No newline at end of file diff --git a/Setup/Strings/Portuguese.isl b/Setup/Strings/Portuguese.isl index e61849db6..18ada508a 100644 --- a/Setup/Strings/Portuguese.isl +++ b/Setup/Strings/Portuguese.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Instale Proton Drive: um armazenamento de nuvem encriptado (gratuito com Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=O Proton VPN está pronto para ser instalado. +InstallOtherApps=Selecione outras aplicações Proton para instalar. Esses serviços estão incluídos no seu plano. +FreeTrial=Teste grátis +Free=Grátis +ProtonMailDescription=E-mail encriptado que é privado por predefinição. +ProtonDriveDescription=Armazenamento seguro na nuvem que lhe permite controlar os seus dados. +ProtonPassDescription=Um gestor de palavras-passe encriptado que protege a sua identidade online. +InstallingWebview2Runtime=A instalar Web View 2 runtime... +CreateDesktopShortcuts=Criar atalho(s) no ambiente de trabalho \ No newline at end of file diff --git a/Setup/Strings/Russian.isl b/Setup/Strings/Russian.isl index 6bd59b4d9..fa0826fea 100644 --- a/Setup/Strings/Russian.isl +++ b/Setup/Strings/Russian.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Установите Proton Drive – зашифрованное облачное хранилище (бесплатно с Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN готова к установке +InstallOtherApps=Выберите другие приложения Proton для установки. Эти услуги включены в ваш тариф. +FreeTrial=Бесплатная пробная версия +Free=Бесплатно +ProtonMailDescription=Электронная почта с шифрованием, в которой конфиденциальность обеспечивается по умолчанию. +ProtonDriveDescription=Безопасное облачное хранилище, позволяющее контролировать данные. +ProtonPassDescription=Зашифрованный менеджер паролей, который защищает вашу личную информацию в Интернете. +InstallingWebview2Runtime=Установка Web View 2 runtime... +CreateDesktopShortcuts=Создать ярлык(и) на рабочем столе \ No newline at end of file diff --git a/Setup/Strings/Slovenian.isl b/Setup/Strings/Slovenian.isl index c9a8a179a..2e9c1e660 100644 --- a/Setup/Strings/Slovenian.isl +++ b/Setup/Strings/Slovenian.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Namestite Proton Drive - Šifrirano shranjevanje v oblaku (brezplačno s Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN je pripravljen za namestitev. +InstallOtherApps=Izberite druge aplikacije Proton, ki jih želite namestiti. Te storitve so vključene v vaš paket. +FreeTrial=Brezplačen preizkus +Free=Brezplačno +ProtonMailDescription=Šifrirana in privzeto zasebna e-pošta. +ProtonDriveDescription=Varen prostor za shranjevanje v oblaku, ki nadzor nad podatki ohranja v vaših rokah. +ProtonPassDescription=Šifriran upravitelj gesel, ki varuje vašo spletno identiteto. +InstallingWebview2Runtime=Nameščanje izvajalnika Web View 2 ... +CreateDesktopShortcuts=Ustvari bližnjico/-e na namizju \ No newline at end of file diff --git a/Setup/Strings/Spanish.isl b/Setup/Strings/Spanish.isl index 69dcb3924..2af070e73 100644 --- a/Setup/Strings/Spanish.isl +++ b/Setup/Strings/Spanish.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Instala Proton Drive: almacenamiento en la nube cifrado (gratis con Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN está listo para ser instalado +InstallOtherApps=Seleccione otras aplicaciones Proton para instalar. Estos servicios están incluidos en tu plan. +FreeTrial=Prueba gratuita +Free=Gratis +ProtonMailDescription=Un correo electrónico cifrado y privado por defecto. +ProtonDriveDescription=Almacenamiento seguro en la nube que te otorga el control de tus datos. +ProtonPassDescription=Administrador de claves encriptadas que protege tu identidad en línea. +InstallingWebview2Runtime=Instalando Web View 2 runtime... +CreateDesktopShortcuts=Crear atajo(s) en el escritorio \ No newline at end of file diff --git a/Setup/Strings/Turkish.isl b/Setup/Strings/Turkish.isl index 46d7b5718..40df9038c 100644 --- a/Setup/Strings/Turkish.isl +++ b/Setup/Strings/Turkish.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Proton Drive kurun - Şifrelenmiş bulut depolaması (Proton VPN ile ücretsiz) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN kurulmaya hazır +InstallOtherApps=Kurulacak diğer Proton uygulamalarını seçin. Bu hizmetler tarifenizde bulunuyor. +FreeTrial=Ücretsiz deneme +Free=Free +ProtonMailDescription=Varsayılan olarak kişiye özel şifrelenmiş e-posta. +ProtonDriveDescription=Bilgilerinizin kontrolünü size veren güvenli bulut depolama alanı. +ProtonPassDescription=Çevrim içi kimliğinizi koruyan şifrelenmiş parola yöneticisi. +InstallingWebview2Runtime=Web View 2 işleyicisi kuruluyor... +CreateDesktopShortcuts=Masaüstü kısayollarını oluştur \ No newline at end of file diff --git a/Setup/Strings/Ukrainian.isl b/Setup/Strings/Ukrainian.isl index 8f71586b5..3e8c5e647 100644 --- a/Setup/Strings/Ukrainian.isl +++ b/Setup/Strings/Ukrainian.isl @@ -1,3 +1,10 @@ [CustomMessages] -InstallProtonDriveTitle=Установіть Proton Drive - Зашифроване хмарне сховище (Безплатно з Proton VPN) -InstallingWebview2Runtime=Installing Web View 2 runtime... \ No newline at end of file +InstallerTitle=Proton VPN готовий до встановлення +InstallOtherApps=Виберіть інші застосунки Proton для встановлення. Ці сервіси включені до вашого тарифу. +FreeTrial=Безплатний пробний період +Free=Безплатно +ProtonMailDescription=Зашифрована, приватна електронна пошта. +ProtonDriveDescription=Захищене хмарне сховище, що надає вам контроль особистих даних. +ProtonPassDescription=Зашифрований менеджер паролів, який захищає ваші особисті дані у мережі. +InstallingWebview2Runtime=Встановлення Web View 2 runtime... +CreateDesktopShortcuts=Створити ярлики на робочому столі \ No newline at end of file diff --git a/Setup/tap/arm64/OemVista.inf b/Setup/tap/arm64/OemVista.inf new file mode 100644 index 000000000..af51fdae7 --- /dev/null +++ b/Setup/tap/arm64/OemVista.inf @@ -0,0 +1,196 @@ +; **************************************************************************** +; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc. * +; * This program is free software; you can redistribute it and/or modify * +; * it under the terms of the GNU General Public License version 2 * +; * as published by the Free Software Foundation. * +; **************************************************************************** + +; SYNTAX CHECKER +; cd \WINDDK\3790\tools\chkinf +; chkinf c:\src\openvpn\tap-win32\i386\oemvista.inf +; OUTPUT -> file:///c:/WINDDK/3790/tools/chkinf/htm/c%23+src+openvpn+tap-win32+i386+__OemWin2k.htm + +; INSTALL/REMOVE DRIVER +; tapinstall install OemVista.inf tapoas +; tapinstall update OemVista.inf tapoas +; tapinstall remove tapoas + +;********************************************************* +; Note to Developers: +; +; If you are bundling the TAP-Windows driver with your app, +; you should try to rename it in such a way that it will +; not collide with other instances of TAP-Windows defined +; by other apps. Multiple versions of the TAP-Windows +; driver, each installed by different apps, can coexist +; on the same machine if you follow these guidelines. +; NOTE: these instructions assume you are editing the +; generated OemWin2k.inf file, not the source +; OemWin2k.inf.in file which is preprocessed by winconfig +; and uses macro definitions from settings.in. +; +; (1) Rename all tapXXXX instances in this file to +; something different (use at least 5 characters +; for this name!) +; (2) Change the "!define TAP" definition in openvpn.nsi +; to match what you changed tapXXXX to. +; (3) Change TARGETNAME in SOURCES to match what you +; changed tapXXXX to. +; (4) Change TAP_COMPONENT_ID in common.h to match what +; you changed tapXXXX to. +; (5) Change SZDEPENDENCIES in service.h to match what +; you changed tapXXXX to. +; (6) Change DeviceDescription and Provider strings. +; (7) Change PRODUCT_TAP_WIN_DEVICE_DESCRIPTION in constants.h to what you +; set DeviceDescription to. +; +;********************************************************* + +[Version] + Signature = "$Windows NT$" + CatalogFile = tapprotonvpn.cat + ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} + Provider = %Provider% + Class = Net + PnpLockdown=1 + +; This version number should match the version +; number given in ..\version.m4. + DriverVer = 02/27/2024,9.27.0.0 + +[Strings] + DeviceDescription = "TAP-ProtonVPN Windows Adapter V9" + Provider = "TAP-Windows Provider V9" + +;---------------------------------------------------------------- +; Manufacturer + Product Section (Done) +;---------------------------------------------------------------- +[Manufacturer] + %Provider% = tapprotonvpn, NTARM64 + +[tapprotonvpn.NTARM64] + %DeviceDescription% = tapprotonvpn.ndi, root\tapprotonvpn ; Root enumerated + %DeviceDescription% = tapprotonvpn.ndi, tapprotonvpn ; Legacy + +;--------------------------------------------------------------- +; Driver Section (Done) +;--------------------------------------------------------------- + +;----------------- Characteristics ------------ +; NCF_PHYSICAL = 0x04 +; NCF_VIRTUAL = 0x01 +; NCF_SOFTWARE_ENUMERATED = 0x02 +; NCF_HIDDEN = 0x08 +; NCF_NO_SERVICE = 0x10 +; NCF_HAS_UI = 0x80 +;----------------- Characteristics ------------ + +[tapprotonvpn.ndi] + CopyFiles = tapprotonvpn.driver, tapprotonvpn.files + AddReg = tapprotonvpn.reg + AddReg = tapprotonvpn.params.reg + DelReg = tapprotonvpn.params.delreg + Characteristics = 0x1 + *IfType = 53 ; IF_TYPE_PROP_VIRTUAL + *MediaType = 0x0 ; NdisMedium802_3 + *PhysicalMediaType = 0 ; NdisPhysicalMediumUnspecified + +[tapprotonvpn.ndi.Services] + AddService = tapprotonvpn, 2, tapprotonvpn.service + +[tapprotonvpn.reg] + HKR, Ndi, Service, 0, "tapprotonvpn" + HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" + HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" + HKR, , Manufacturer, 0, "%Provider%" + HKR, , ProductName, 0, "%DeviceDescription%" + +[tapprotonvpn.params.reg] + HKR, Ndi\params\MTU, ParamDesc, 0, "MTU" + HKR, Ndi\params\MTU, Type, 0, "int" + HKR, Ndi\params\MTU, Default, 0, "1500" + HKR, Ndi\params\MTU, Optional, 0, "0" + HKR, Ndi\params\MTU, Min, 0, "100" + HKR, Ndi\params\MTU, Max, 0, "1500" + HKR, Ndi\params\MTU, Step, 0, "1" + HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status" + HKR, Ndi\params\MediaStatus, Type, 0, "enum" + HKR, Ndi\params\MediaStatus, Default, 0, "0" + HKR, Ndi\params\MediaStatus, Optional, 0, "0" + HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled" + HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected" + HKR, Ndi\params\NetworkAddress, ParamDesc, 0, "MAC Address" + HKR, Ndi\params\NetworkAddress, Type, 0, "edit" + HKR, Ndi\params\NetworkAddress, Optional, 0, "1" + HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access" + HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum" + HKR, Ndi\params\AllowNonAdmin, Default, 0, "1" + HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0" + HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed" + HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed" + +[tapprotonvpn.params.delreg] + HKR, Ndi\params\MAC + +;---------------------------------------------------------------- +; Service Section +;---------------------------------------------------------------- + +;---------- Service Type ------------- +; SERVICE_KERNEL_DRIVER = 0x01 +; SERVICE_WIN32_OWN_PROCESS = 0x10 +;---------- Service Type ------------- + +;---------- Start Mode --------------- +; SERVICE_BOOT_START = 0x0 +; SERVICE_SYSTEM_START = 0x1 +; SERVICE_AUTO_START = 0x2 +; SERVICE_DEMAND_START = 0x3 +; SERVICE_DISABLED = 0x4 +;---------- Start Mode --------------- + +[tapprotonvpn.service] + DisplayName = %DeviceDescription% + ServiceType = 1 + StartType = 3 + ErrorControl = 1 + LoadOrderGroup = NDIS + ServiceBinary = %12%\tapprotonvpn.sys + +;----------------------------------------------------------------- +; File Installation +;----------------------------------------------------------------- + +;----------------- Copy Flags ------------ +; COPYFLG_NOSKIP = 0x02 +; COPYFLG_NOVERSIONCHECK = 0x04 +;----------------- Copy Flags ------------ + +; SourceDisksNames +; diskid = description[, [tagfile] [, , subdir]] +; 1 = "Intel Driver Disk 1",e100bex.sys,, + +[SourceDisksNames] + 1 = %DeviceDescription%, tapprotonvpn.sys + +; SourceDisksFiles +; filename_on_source = diskID[, [subdir][, size]] +; e100bex.sys = 1,, ; on distribution disk 1 + +[SourceDisksFiles] +tapprotonvpn.sys = 1 + +[DestinationDirs] + tapprotonvpn.files = 11 + tapprotonvpn.driver = 12 + +[tapprotonvpn.files] +; TapPanel.cpl,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK +; cipsrvr.exe,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + +[tapprotonvpn.driver] + tapprotonvpn.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + +;--------------------------------------------------------------- +; End +;--------------------------------------------------------------- diff --git a/Setup/tap/arm64/tapinstall.exe b/Setup/tap/arm64/tapinstall.exe new file mode 100644 index 000000000..96f2c5ffa Binary files /dev/null and b/Setup/tap/arm64/tapinstall.exe differ diff --git a/Setup/tap/arm64/tapprotonvpn.cat b/Setup/tap/arm64/tapprotonvpn.cat new file mode 100644 index 000000000..c45198fbb Binary files /dev/null and b/Setup/tap/arm64/tapprotonvpn.cat differ diff --git a/Setup/tap/arm64/tapprotonvpn.sys b/Setup/tap/arm64/tapprotonvpn.sys new file mode 100644 index 000000000..d42184634 Binary files /dev/null and b/Setup/tap/arm64/tapprotonvpn.sys differ diff --git a/Setup/tap/OemVista.inf b/Setup/tap/x64/OemVista.inf similarity index 100% rename from Setup/tap/OemVista.inf rename to Setup/tap/x64/OemVista.inf diff --git a/Setup/tap/tapinstall.exe b/Setup/tap/x64/tapinstall.exe similarity index 100% rename from Setup/tap/tapinstall.exe rename to Setup/tap/x64/tapinstall.exe diff --git a/Setup/tap/tapprotonvpn.Sys b/Setup/tap/x64/tapprotonvpn.Sys similarity index 100% rename from Setup/tap/tapprotonvpn.Sys rename to Setup/tap/x64/tapprotonvpn.Sys diff --git a/Setup/tap/tapprotonvpn.cat b/Setup/tap/x64/tapprotonvpn.cat similarity index 100% rename from Setup/tap/tapprotonvpn.cat rename to Setup/tap/x64/tapprotonvpn.cat diff --git a/ci/build-scripts/installer.py b/ci/build-scripts/installer.py index dff2673e1..1ce783155 100644 --- a/ci/build-scripts/installer.py +++ b/ci/build-scripts/installer.py @@ -4,19 +4,8 @@ import pathlib def build(version, hash, setupFile): - fileData = '' - with open(setupFile, 'r') as file: - fileData = file.read() - fileData = re.sub('(#define MyAppVersion \")([0-9+]\.[0-9+]\.[0-9+])(\".+)', rf'\g<1>{version}\3', fileData, 1, flags = re.M | re.DOTALL) - - if hash: - fileData = fileData.replace('#define Hash ""', "#define Hash \"{hash}\"".format(hash=hash)) - - setupFile = pathlib.Path(setupFile).parent.resolve().__str__() + '\\' + 'setup-edited.iss' - print(setupFile) - with open(setupFile, 'w') as file: - file.write(fileData) + createSetupFile(version, hash) p = subprocess.Popen(['iscc', setupFile, "/Ssigntool=signtool.exe $p"], env=os.environ, @@ -24,4 +13,18 @@ def build(version, hash, setupFile): universal_newlines=True) print(p.communicate()[0]) - return p.returncode \ No newline at end of file + return p.returncode + +def createSetupFile(version, hash): + baseSetupFile = 'Setup/SetupBase.iss' + fileData = '' + with open(baseSetupFile, 'r') as file: + fileData = file.read() + + fileData = re.sub('(#define MyAppVersion \")([0-9+]\.[0-9+]\.[0-9+])(\".+)', rf'\g<1>{version}\3', fileData, 1, flags = re.M | re.DOTALL) + + if hash: + fileData = fileData.replace('#define Hash ""', "#define Hash \"{hash}\"".format(hash=hash)) + + with open(baseSetupFile, 'w') as file: + file.write(fileData) \ No newline at end of file diff --git a/ci/build-scripts/main.py b/ci/build-scripts/main.py index c9f7c6e7e..4e3dc0be7 100644 --- a/ci/build-scripts/main.py +++ b/ci/build-scripts/main.py @@ -31,6 +31,7 @@ def print_sha256(file_path): custom_parser = subparsers.add_parser('app-installer') custom_parser.add_argument('hash', type=str, help='Commit hash string') +custom_parser.add_argument('platform', type=str, help='Platform: x64 or arm64') custom_parser = subparsers.add_parser('app-bti-installer') custom_parser.add_argument('hash', type=str, help='Commit hash string') @@ -68,11 +69,11 @@ def print_sha256(file_path): v = win32api.GetFileVersionInfo(exe_path, '\\') semVersion = "%d.%d.%d" % (v['FileVersionMS'] / 65536, v['FileVersionMS'] % 65536, v['FileVersionLS'] / 65536) print('Building app installer') - err = installer.build(semVersion, args.hash, 'Setup/setup.iss') - installer_filename = 'ProtonVPN_v{semVersion}.exe'.format(semVersion=semVersion) - + err = installer.build(semVersion, args.hash, 'Setup/Setup.{platform}.iss'.format(platform=args.platform)) + installer_filename = 'ProtonVPN_v{semVersion}_{platform}.exe'.format(semVersion=semVersion, platform=args.platform) + if 'BTI' in build_path: - installer_filename = 'ProtonVPN_v{semVersion}_BTI.exe'.format(semVersion=semVersion) + installer_filename = 'ProtonVPN_v{semVersion}_{platform}_BTI.exe'.format(semVersion=semVersion, platform=args.platform) installer_path = os.path.join('.\Setup\Installers', installer_filename) print_sha256(installer_path) diff --git a/sign/ProtonVPN.CalloutDriver.ARM64.cab b/sign/ProtonVPN.CalloutDriver.ARM64.cab new file mode 100644 index 000000000..be4902988 Binary files /dev/null and b/sign/ProtonVPN.CalloutDriver.ARM64.cab differ diff --git a/sign/ProtonVPN.CalloutDriver.sys b/sign/ProtonVPN.CalloutDriver.sys new file mode 100644 index 000000000..e8f09d0e5 Binary files /dev/null and b/sign/ProtonVPN.CalloutDriver.sys differ diff --git a/src/Announcements/ProtonVPN.Announcements.Contracts/ProtonVPN.Announcements.Contracts.csproj b/src/Announcements/ProtonVPN.Announcements.Contracts/ProtonVPN.Announcements.Contracts.csproj index 1791135c6..1de12dc47 100644 --- a/src/Announcements/ProtonVPN.Announcements.Contracts/ProtonVPN.Announcements.Contracts.csproj +++ b/src/Announcements/ProtonVPN.Announcements.Contracts/ProtonVPN.Announcements.Contracts.csproj @@ -1,10 +1,11 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/Announcements/ProtonVPN.Announcements.Installers/ProtonVPN.Announcements.Installers.csproj b/src/Announcements/ProtonVPN.Announcements.Installers/ProtonVPN.Announcements.Installers.csproj index 1468de594..43cd8b82d 100644 --- a/src/Announcements/ProtonVPN.Announcements.Installers/ProtonVPN.Announcements.Installers.csproj +++ b/src/Announcements/ProtonVPN.Announcements.Installers/ProtonVPN.Announcements.Installers.csproj @@ -1,10 +1,11 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/Announcements/ProtonVPN.Announcements.Tests/ProtonVPN.Announcements.Tests.csproj b/src/Announcements/ProtonVPN.Announcements.Tests/ProtonVPN.Announcements.Tests.csproj index 2c123ab92..882c785b6 100644 --- a/src/Announcements/ProtonVPN.Announcements.Tests/ProtonVPN.Announcements.Tests.csproj +++ b/src/Announcements/ProtonVPN.Announcements.Tests/ProtonVPN.Announcements.Tests.csproj @@ -1,11 +1,12 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false false + AnyCPU;ARM64 diff --git a/src/Announcements/ProtonVPN.Announcements/ProtonVPN.Announcements.csproj b/src/Announcements/ProtonVPN.Announcements/ProtonVPN.Announcements.csproj index c8fef9b9e..e86864d4d 100644 --- a/src/Announcements/ProtonVPN.Announcements/ProtonVPN.Announcements.csproj +++ b/src/Announcements/ProtonVPN.Announcements/ProtonVPN.Announcements.csproj @@ -1,10 +1,11 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/Api/ProtonVPN.Api.Contracts/ApiResponseResult.cs b/src/Api/ProtonVPN.Api.Contracts/ApiResponseResult.cs index f85d0cf64..84f83e6cb 100644 --- a/src/Api/ProtonVPN.Api.Contracts/ApiResponseResult.cs +++ b/src/Api/ProtonVPN.Api.Contracts/ApiResponseResult.cs @@ -38,7 +38,7 @@ protected ApiResponseResult(HttpResponseMessage responseMessage, bool success, s { ResponseMessage = responseMessage; Actions = value?.Details?.Actions; - LastModified = responseMessage.Content.Headers.LastModified; + LastModified = responseMessage?.Content?.Headers?.LastModified; IsNotModified = isNotModified; } @@ -46,7 +46,7 @@ protected ApiResponseResult(HttpResponseMessage responseMessage, bool success, s : base(default(T), success, error) { ResponseMessage = responseMessage; - LastModified = responseMessage.Content.Headers.LastModified; + LastModified = responseMessage?.Content?.Headers?.LastModified; IsNotModified = isNotModified; } diff --git a/src/Api/ProtonVPN.Api.Contracts/IApiClient.cs b/src/Api/ProtonVPN.Api.Contracts/IApiClient.cs index 77f0689a2..b2673b9bd 100644 --- a/src/Api/ProtonVPN.Api.Contracts/IApiClient.cs +++ b/src/Api/ProtonVPN.Api.Contracts/IApiClient.cs @@ -59,6 +59,7 @@ public interface IApiClient : IClientBase Task> ApplyPromoCodeAsync(PromoCodeRequest promoCodeRequest); Task> ForkAuthSessionAsync(AuthForkSessionRequest request); Task> GetSettingsAsync(); + Task> PostUnauthStatisticalEventsAsync(StatisticalEventsBatch statisticalEvents); Task> PostStatisticalEventsAsync(StatisticalEventsBatch statisticalEvents); Task> GetUserAsync(string accessToken, string uid); Task> GetFeatureFlagsAsync(); diff --git a/src/Api/ProtonVPN.Api.Contracts/ProtonVPN.Api.Contracts.csproj b/src/Api/ProtonVPN.Api.Contracts/ProtonVPN.Api.Contracts.csproj index d3ac4d6b1..ee34a008c 100644 --- a/src/Api/ProtonVPN.Api.Contracts/ProtonVPN.Api.Contracts.csproj +++ b/src/Api/ProtonVPN.Api.Contracts/ProtonVPN.Api.Contracts.csproj @@ -1,10 +1,11 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/Api/ProtonVPN.Api.Contracts/VpnConfig/FeatureFlagsResponse.cs b/src/Api/ProtonVPN.Api.Contracts/VpnConfig/FeatureFlagsResponse.cs index 12bcf2e8c..23121ade4 100644 --- a/src/Api/ProtonVPN.Api.Contracts/VpnConfig/FeatureFlagsResponse.cs +++ b/src/Api/ProtonVPN.Api.Contracts/VpnConfig/FeatureFlagsResponse.cs @@ -40,8 +40,6 @@ public class FeatureFlagsResponse public bool? SmartReconnect { get; set; } - public bool? SafeMode { get; set; } - public bool? PromoCode { get; set; } public bool? ShowNewFreePlan { get; set; } diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Registration/AppServerPortRegister.cs b/src/Api/ProtonVPN.Api.Contracts/VpnConfig/SmartProtocolResponse.cs similarity index 52% rename from src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Registration/AppServerPortRegister.cs rename to src/Api/ProtonVPN.Api.Contracts/VpnConfig/SmartProtocolResponse.cs index cc0054ec4..f171d0dd9 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Registration/AppServerPortRegister.cs +++ b/src/Api/ProtonVPN.Api.Contracts/VpnConfig/SmartProtocolResponse.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Proton AG + * Copyright (c) 2024 Proton AG * * This file is part of ProtonVPN. * @@ -17,23 +17,25 @@ * along with ProtonVPN. If not, see . */ -using ProtonVPN.Logging.Contracts; -using ProtonVPN.ProcessCommunication.Contracts.Registration; +using Newtonsoft.Json; -namespace ProtonVPN.ProcessCommunication.Common.Registration +namespace ProtonVPN.Api.Contracts.VpnConfig { - public class AppServerPortRegister : ServerPortRegisterBase, IAppServerPortRegister + public class SmartProtocolResponse { - private const string KEY = "AppServerPort"; + [JsonProperty(PropertyName = "WireGuard")] + public bool WireGuardUdp { get; set; } - public AppServerPortRegister(ILogger logger) - : base(logger) - { - } + [JsonProperty(PropertyName = "WireGuardTCP")] + public bool WireGuardTcp { get; set; } - protected override string GetKey() - { - return KEY; - } + [JsonProperty(PropertyName = "WireGuardTLS")] + public bool WireGuardTls { get; set; } + + [JsonProperty(PropertyName = "OpenVPN")] + public bool OpenVpnUdp { get; set; } + + [JsonProperty(PropertyName = "OpenVPNTCP")] + public bool OpenVpnTcp { get; set; } } } \ No newline at end of file diff --git a/src/Api/ProtonVPN.Api.Contracts/VpnConfig/VpnConfigResponse.cs b/src/Api/ProtonVPN.Api.Contracts/VpnConfig/VpnConfigResponse.cs index 8f4f9dd84..9a71a568f 100644 --- a/src/Api/ProtonVPN.Api.Contracts/VpnConfig/VpnConfigResponse.cs +++ b/src/Api/ProtonVPN.Api.Contracts/VpnConfig/VpnConfigResponse.cs @@ -34,5 +34,7 @@ public class VpnConfigResponse : BaseResponse public int? ChangeServerLongDelayInSeconds { get; set; } public FeatureFlagsResponse FeatureFlags { get; set; } + + public SmartProtocolResponse SmartProtocol { get; set; } } } \ No newline at end of file diff --git a/src/Api/ProtonVPN.Api.Installers/ProtonVPN.Api.Installers.csproj b/src/Api/ProtonVPN.Api.Installers/ProtonVPN.Api.Installers.csproj index 17105ae91..339e7a803 100644 --- a/src/Api/ProtonVPN.Api.Installers/ProtonVPN.Api.Installers.csproj +++ b/src/Api/ProtonVPN.Api.Installers/ProtonVPN.Api.Installers.csproj @@ -1,10 +1,11 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/Api/ProtonVPN.Api.Tests/ProtonVPN.Api.Tests.csproj b/src/Api/ProtonVPN.Api.Tests/ProtonVPN.Api.Tests.csproj index f98f54f56..3ed511a8e 100644 --- a/src/Api/ProtonVPN.Api.Tests/ProtonVPN.Api.Tests.csproj +++ b/src/Api/ProtonVPN.Api.Tests/ProtonVPN.Api.Tests.csproj @@ -1,11 +1,12 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false false + AnyCPU;ARM64 diff --git a/src/Api/ProtonVPN.Api/ApiAppVersion.cs b/src/Api/ProtonVPN.Api/ApiAppVersion.cs index 5daaca776..69809854b 100644 --- a/src/Api/ProtonVPN.Api/ApiAppVersion.cs +++ b/src/Api/ProtonVPN.Api/ApiAppVersion.cs @@ -18,7 +18,9 @@ */ using System; +using System.Text; using ProtonVPN.Common.Configuration; +using ProtonVPN.Common.OS.Architecture; namespace ProtonVPN.Api { @@ -35,16 +37,18 @@ public ApiAppVersion(IConfiguration appConfig) public string Value() { - string value = $"{_appConfig.ApiClientId}@{GetVersion()}"; + StringBuilder sb = new(); + sb.Append($"{_appConfig.ApiClientId}@{GetVersion()}"); #if DEBUG - value += DEVELOPMENT_SUFFIX; + sb.Append(DEVELOPMENT_SUFFIX); #endif - return value; + sb.Append($"+{OsArchitecture.Value}"); + return sb.ToString(); } public string UserAgent() { - return $"{_appConfig.UserAgent}/{GetVersion()} ({Environment.OSVersion})"; + return $"{_appConfig.UserAgent}/{GetVersion()} ({Environment.OSVersion}; {OsArchitecture.Value})"; } private string GetVersion() diff --git a/src/Api/ProtonVPN.Api/ApiClient.cs b/src/Api/ProtonVPN.Api/ApiClient.cs index f01367756..a6014cc0f 100644 --- a/src/Api/ProtonVPN.Api/ApiClient.cs +++ b/src/Api/ProtonVPN.Api/ApiClient.cs @@ -231,6 +231,13 @@ public async Task> GetSettingsAsync() return await SendRequest(request, "Get user settings"); } + public async Task> PostUnauthStatisticalEventsAsync(StatisticalEventsBatch statisticalEvents) + { + HttpRequestMessage request = GetRequest(HttpMethod.Post, "data/v1/stats/multiple"); + request.Content = GetJsonContent(statisticalEvents); + return await SendRequest(request, "Post statistical events batch"); + } + public async Task> PostStatisticalEventsAsync(StatisticalEventsBatch statisticalEvents) { HttpRequestMessage request = GetAuthorizedRequest(HttpMethod.Post, "data/v1/stats/multiple"); diff --git a/src/Api/ProtonVPN.Api/ProtonVPN.Api.csproj b/src/Api/ProtonVPN.Api/ProtonVPN.Api.csproj index 3ce54a079..96e878ca8 100644 --- a/src/Api/ProtonVPN.Api/ProtonVPN.Api.csproj +++ b/src/Api/ProtonVPN.Api/ProtonVPN.Api.csproj @@ -1,12 +1,13 @@  - net6.0-windows + net8.0-windows Library false true true ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/Builds/ProtonVPN.Builds.ConsoleJob/Program.cs b/src/Builds/ProtonVPN.Builds.ConsoleJob/Program.cs index 0646ad70b..8e68b4850 100644 --- a/src/Builds/ProtonVPN.Builds.ConsoleJob/Program.cs +++ b/src/Builds/ProtonVPN.Builds.ConsoleJob/Program.cs @@ -62,7 +62,7 @@ private static string GetRootDirectory() private static string GetFileContents() { string sentryDsn = GetEnvironmentVariable("SENTRY_DSN_V2"); - string internalReleaseUrl = GetEnvironmentVariable("INTERNAL_RELEASE_URL"); + string internalReleaseUrl = GetEnvironmentVariable("INTERNAL_RELEASE_URL_V1"); string btiApiDomain = GetEnvironmentVariable("BTI_API_DOMAIN"); string btiApiTlsPinningPublicKeyHashes = GetEnvironmentVariable("BTI_API_TLS_PINNINGS"); string btiAlternativeRoutingTlsPinningPublicKeyHashes = GetEnvironmentVariable("BTI_ALT_ROUTE_TLS_PINNINGS"); diff --git a/src/Builds/ProtonVPN.Builds.ConsoleJob/ProtonVPN.Builds.ConsoleJob.csproj b/src/Builds/ProtonVPN.Builds.ConsoleJob/ProtonVPN.Builds.ConsoleJob.csproj index 062072200..d7f7a5852 100644 --- a/src/Builds/ProtonVPN.Builds.ConsoleJob/ProtonVPN.Builds.ConsoleJob.csproj +++ b/src/Builds/ProtonVPN.Builds.ConsoleJob/ProtonVPN.Builds.ConsoleJob.csproj @@ -1,12 +1,13 @@ - net6.0-windows + net8.0-windows enable enable ..\..\bin false Exe false + AnyCPU;ARM64 diff --git a/src/Builds/ProtonVPN.Builds.Variables/ProtonVPN.Builds.Variables.csproj b/src/Builds/ProtonVPN.Builds.Variables/ProtonVPN.Builds.Variables.csproj index 664c8c5fb..7ed31d037 100644 --- a/src/Builds/ProtonVPN.Builds.Variables/ProtonVPN.Builds.Variables.csproj +++ b/src/Builds/ProtonVPN.Builds.Variables/ProtonVPN.Builds.Variables.csproj @@ -1,11 +1,12 @@ - net6.0-windows + net8.0-windows enable ..\..\bin false Library false + AnyCPU;ARM64 diff --git a/src/Common/ProtonVPN.Common.Installers/ProtonVPN.Common.Installers.csproj b/src/Common/ProtonVPN.Common.Installers/ProtonVPN.Common.Installers.csproj index f6e0bfb10..225284189 100644 --- a/src/Common/ProtonVPN.Common.Installers/ProtonVPN.Common.Installers.csproj +++ b/src/Common/ProtonVPN.Common.Installers/ProtonVPN.Common.Installers.csproj @@ -1,10 +1,11 @@ - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/Dns/ProtonVPN.Dns.Contracts/ProtonVPN.Dns.Contracts.csproj b/src/Dns/ProtonVPN.Dns.Contracts/ProtonVPN.Dns.Contracts.csproj index 535738c59..89c17a248 100644 --- a/src/Dns/ProtonVPN.Dns.Contracts/ProtonVPN.Dns.Contracts.csproj +++ b/src/Dns/ProtonVPN.Dns.Contracts/ProtonVPN.Dns.Contracts.csproj @@ -1,10 +1,11 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/Dns/ProtonVPN.Dns.Installers/ProtonVPN.Dns.Installers.csproj b/src/Dns/ProtonVPN.Dns.Installers/ProtonVPN.Dns.Installers.csproj index e5fca20d3..ff2a2217f 100644 --- a/src/Dns/ProtonVPN.Dns.Installers/ProtonVPN.Dns.Installers.csproj +++ b/src/Dns/ProtonVPN.Dns.Installers/ProtonVPN.Dns.Installers.csproj @@ -1,10 +1,11 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/Dns/ProtonVPN.Dns.Tests/ProtonVPN.Dns.Tests.csproj b/src/Dns/ProtonVPN.Dns.Tests/ProtonVPN.Dns.Tests.csproj index 9a4fea553..3867679ad 100644 --- a/src/Dns/ProtonVPN.Dns.Tests/ProtonVPN.Dns.Tests.csproj +++ b/src/Dns/ProtonVPN.Dns.Tests/ProtonVPN.Dns.Tests.csproj @@ -1,19 +1,27 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false false + AnyCPU;ARM64 ..\..\bin\ latest + + ..\..\bin\ + latest + latest + + latest + Properties\GlobalAssemblyInfo.cs diff --git a/src/Dns/ProtonVPN.Dns/ProtonVPN.Dns.csproj b/src/Dns/ProtonVPN.Dns/ProtonVPN.Dns.csproj index 5c72f4c12..86f1c25ea 100644 --- a/src/Dns/ProtonVPN.Dns/ProtonVPN.Dns.csproj +++ b/src/Dns/ProtonVPN.Dns/ProtonVPN.Dns.csproj @@ -1,11 +1,12 @@  - net6.0-windows + net8.0-windows Library false latest ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Installers/ServiceProcessCommunicationModule.cs b/src/EntityMapping/ProtonVPN.EntityMapping.Common.Installers/Extensions/ContainerBuilderExtensions.cs similarity index 60% rename from src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Installers/ServiceProcessCommunicationModule.cs rename to src/EntityMapping/ProtonVPN.EntityMapping.Common.Installers/Extensions/ContainerBuilderExtensions.cs index b37581b57..07fe329c5 100644 --- a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Installers/ServiceProcessCommunicationModule.cs +++ b/src/EntityMapping/ProtonVPN.EntityMapping.Common.Installers/Extensions/ContainerBuilderExtensions.cs @@ -16,17 +16,20 @@ * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ + using Autofac; -using ProtonVPN.ProcessCommunication.Contracts; +using ProtonVPN.EntityMapping.Contracts; + +namespace ProtonVPN.EntityMapping.Common.Installers.Extensions; -namespace ProtonVPN.ProcessCommunication.Service.Installers +public static class ContainerBuilderExtensions { - public class ServiceProcessCommunicationModule : Module + public static void RegisterAllMappersInAssembly(this ContainerBuilder builder) + where TMapper : class, IMapper { - protected override void Load(ContainerBuilder builder) - { - builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As().SingleInstance(); - } + builder.RegisterAssemblyTypes(typeof(TMapper).Assembly) + .Where(t => typeof(IMapper).IsAssignableFrom(t)) + .AsImplementedInterfaces() + .SingleInstance(); } } \ No newline at end of file diff --git a/src/EntityMapping/ProtonVPN.EntityMapping.Common.Installers/ProtonVPN.EntityMapping.Common.Installers.csproj b/src/EntityMapping/ProtonVPN.EntityMapping.Common.Installers/ProtonVPN.EntityMapping.Common.Installers.csproj new file mode 100644 index 000000000..5809e23a1 --- /dev/null +++ b/src/EntityMapping/ProtonVPN.EntityMapping.Common.Installers/ProtonVPN.EntityMapping.Common.Installers.csproj @@ -0,0 +1,22 @@ + + + net8.0-windows + enable + ..\..\bin + false + Library + false + AnyCPU;ARM64 + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + \ No newline at end of file diff --git a/src/EntityMapping/ProtonVPN.EntityMapping.Contracts/ProtonVPN.EntityMapping.Contracts.csproj b/src/EntityMapping/ProtonVPN.EntityMapping.Contracts/ProtonVPN.EntityMapping.Contracts.csproj index 1143759ba..a1eae4638 100644 --- a/src/EntityMapping/ProtonVPN.EntityMapping.Contracts/ProtonVPN.EntityMapping.Contracts.csproj +++ b/src/EntityMapping/ProtonVPN.EntityMapping.Contracts/ProtonVPN.EntityMapping.Contracts.csproj @@ -1,12 +1,13 @@ - net6.0-windows + net8.0-windows enable ..\..\bin false Library false + AnyCPU;ARM64 diff --git a/src/EntityMapping/ProtonVPN.EntityMapping.Installers/ProtonVPN.EntityMapping.Installers.csproj b/src/EntityMapping/ProtonVPN.EntityMapping.Installers/ProtonVPN.EntityMapping.Installers.csproj index 9680a690f..d69b0d91e 100644 --- a/src/EntityMapping/ProtonVPN.EntityMapping.Installers/ProtonVPN.EntityMapping.Installers.csproj +++ b/src/EntityMapping/ProtonVPN.EntityMapping.Installers/ProtonVPN.EntityMapping.Installers.csproj @@ -1,12 +1,13 @@ - net6.0-windows + net8.0-windows enable ..\..\bin false Library false + AnyCPU;ARM64 diff --git a/src/EntityMapping/ProtonVPN.EntityMapping.Tests/ProtonVPN.EntityMapping.Tests.csproj b/src/EntityMapping/ProtonVPN.EntityMapping.Tests/ProtonVPN.EntityMapping.Tests.csproj index 6537daf64..042b19144 100644 --- a/src/EntityMapping/ProtonVPN.EntityMapping.Tests/ProtonVPN.EntityMapping.Tests.csproj +++ b/src/EntityMapping/ProtonVPN.EntityMapping.Tests/ProtonVPN.EntityMapping.Tests.csproj @@ -1,13 +1,14 @@ - net6.0-windows + net8.0-windows enable ..\..\bin\ false Library false false + AnyCPU;ARM64 diff --git a/src/EntityMapping/ProtonVPN.EntityMapping/ProtonVPN.EntityMapping.csproj b/src/EntityMapping/ProtonVPN.EntityMapping/ProtonVPN.EntityMapping.csproj index 2a8539803..25cdb9112 100644 --- a/src/EntityMapping/ProtonVPN.EntityMapping/ProtonVPN.EntityMapping.csproj +++ b/src/EntityMapping/ProtonVPN.EntityMapping/ProtonVPN.EntityMapping.csproj @@ -1,12 +1,13 @@ - net6.0-windows + net8.0-windows enable ..\..\bin false Library false + AnyCPU;ARM64 diff --git a/src/GlobalAssemblyInfo.cs b/src/GlobalAssemblyInfo.cs index d993fe5ee..e3bbc25c2 100644 --- a/src/GlobalAssemblyInfo.cs +++ b/src/GlobalAssemblyInfo.cs @@ -14,8 +14,8 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("3.3.2.0")] -[assembly: AssemblyFileVersion("3.3.2.0")] +[assembly: AssemblyVersion("3.4.3.0")] +[assembly: AssemblyFileVersion("3.4.3.0")] [assembly: ComVisible(false)] [assembly: AssemblyInformationalVersion("$AssemblyVersion")] [assembly: SupportedOSPlatform("windows")] \ No newline at end of file diff --git a/src/HumanVerification/ProtonVPN.HumanVerification.Contracts/ProtonVPN.HumanVerification.Contracts.csproj b/src/HumanVerification/ProtonVPN.HumanVerification.Contracts/ProtonVPN.HumanVerification.Contracts.csproj index 3813214ba..b0b82b61c 100644 --- a/src/HumanVerification/ProtonVPN.HumanVerification.Contracts/ProtonVPN.HumanVerification.Contracts.csproj +++ b/src/HumanVerification/ProtonVPN.HumanVerification.Contracts/ProtonVPN.HumanVerification.Contracts.csproj @@ -1,10 +1,11 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/HumanVerification/ProtonVPN.HumanVerification.Gui/ProtonVPN.HumanVerification.Gui.csproj b/src/HumanVerification/ProtonVPN.HumanVerification.Gui/ProtonVPN.HumanVerification.Gui.csproj index cf3a19f86..90e4e994a 100644 --- a/src/HumanVerification/ProtonVPN.HumanVerification.Gui/ProtonVPN.HumanVerification.Gui.csproj +++ b/src/HumanVerification/ProtonVPN.HumanVerification.Gui/ProtonVPN.HumanVerification.Gui.csproj @@ -1,6 +1,6 @@  - net6.0-windows + net8.0-windows Library latest false @@ -8,6 +8,7 @@ true ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/HumanVerification/ProtonVPN.HumanVerification.Installers/ProtonVPN.HumanVerification.Installers.csproj b/src/HumanVerification/ProtonVPN.HumanVerification.Installers/ProtonVPN.HumanVerification.Installers.csproj index 2dfcd95a9..f513abfd7 100644 --- a/src/HumanVerification/ProtonVPN.HumanVerification.Installers/ProtonVPN.HumanVerification.Installers.csproj +++ b/src/HumanVerification/ProtonVPN.HumanVerification.Installers/ProtonVPN.HumanVerification.Installers.csproj @@ -1,10 +1,11 @@  - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/HumanVerification/ProtonVPN.HumanVerification/ProtonVPN.HumanVerification.csproj b/src/HumanVerification/ProtonVPN.HumanVerification/ProtonVPN.HumanVerification.csproj index 1dc89968f..81815961b 100644 --- a/src/HumanVerification/ProtonVPN.HumanVerification/ProtonVPN.HumanVerification.csproj +++ b/src/HumanVerification/ProtonVPN.HumanVerification/ProtonVPN.HumanVerification.csproj @@ -1,12 +1,13 @@  - net6.0-windows + net8.0-windows Library false true true ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/IssueReporting/ProtonVPN.IssueReporting.Contracts/ProtonVPN.IssueReporting.Contracts.csproj b/src/IssueReporting/ProtonVPN.IssueReporting.Contracts/ProtonVPN.IssueReporting.Contracts.csproj index 59d04f699..ac73cb1cf 100644 --- a/src/IssueReporting/ProtonVPN.IssueReporting.Contracts/ProtonVPN.IssueReporting.Contracts.csproj +++ b/src/IssueReporting/ProtonVPN.IssueReporting.Contracts/ProtonVPN.IssueReporting.Contracts.csproj @@ -1,10 +1,11 @@ - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/IssueReporting/ProtonVPN.IssueReporting.Installers/ProtonVPN.IssueReporting.Installers.csproj b/src/IssueReporting/ProtonVPN.IssueReporting.Installers/ProtonVPN.IssueReporting.Installers.csproj index 84a77aa5b..f32dfbd91 100644 --- a/src/IssueReporting/ProtonVPN.IssueReporting.Installers/ProtonVPN.IssueReporting.Installers.csproj +++ b/src/IssueReporting/ProtonVPN.IssueReporting.Installers/ProtonVPN.IssueReporting.Installers.csproj @@ -1,10 +1,11 @@ - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/IssueReporting/ProtonVPN.IssueReporting/ProtonVPN.IssueReporting.csproj b/src/IssueReporting/ProtonVPN.IssueReporting/ProtonVPN.IssueReporting.csproj index 9ed049dbf..d6bc8a424 100644 --- a/src/IssueReporting/ProtonVPN.IssueReporting/ProtonVPN.IssueReporting.csproj +++ b/src/IssueReporting/ProtonVPN.IssueReporting/ProtonVPN.IssueReporting.csproj @@ -1,10 +1,11 @@ - net6.0-windows + net8.0-windows Library false ..\..\bin\ false + AnyCPU;ARM64 diff --git a/src/IssueReporting/ProtonVPN.IssueReporting/SentryInitializer.cs b/src/IssueReporting/ProtonVPN.IssueReporting/SentryInitializer.cs index 593d11a7e..f0157d751 100644 --- a/src/IssueReporting/ProtonVPN.IssueReporting/SentryInitializer.cs +++ b/src/IssueReporting/ProtonVPN.IssueReporting/SentryInitializer.cs @@ -23,6 +23,7 @@ using System.Text; using ProtonVPN.Builds.Variables; using ProtonVPN.Common.Extensions; +using ProtonVPN.Common.OS.Architecture; using ProtonVPN.Common.OS.DeviceIds; using ProtonVPN.IssueReporting.DiagnosticLogging; using ProtonVPN.IssueReporting.HttpHandlers; @@ -68,6 +69,7 @@ private static SentryOptions GetSentryOptions() { LogSentryEvent(e); e.SetTag("ProcessName", Process.GetCurrentProcess().ProcessName); + e.SetTag("Architecture", OsArchitecture.Value); e.User.Id = DeviceIdStaticBuilder.GetDeviceId(); e.SetExtra("logs", GetLogs()); diff --git a/src/Logging/ProtonVPN.Logging.Contracts/ProtonVPN.Logging.Contracts.csproj b/src/Logging/ProtonVPN.Logging.Contracts/ProtonVPN.Logging.Contracts.csproj index 1143759ba..f9bc1f44c 100644 --- a/src/Logging/ProtonVPN.Logging.Contracts/ProtonVPN.Logging.Contracts.csproj +++ b/src/Logging/ProtonVPN.Logging.Contracts/ProtonVPN.Logging.Contracts.csproj @@ -1,12 +1,13 @@ - + - net6.0-windows + net8.0-windows enable ..\..\bin false Library false + AnyCPU;ARM64 diff --git a/src/Logging/ProtonVPN.Logging.Events/ProtonVPN.Logging.Events.csproj b/src/Logging/ProtonVPN.Logging.Events/ProtonVPN.Logging.Events.csproj index d4dcd7e51..1a724a00b 100644 --- a/src/Logging/ProtonVPN.Logging.Events/ProtonVPN.Logging.Events.csproj +++ b/src/Logging/ProtonVPN.Logging.Events/ProtonVPN.Logging.Events.csproj @@ -1,12 +1,13 @@  - net6.0-windows + net8.0-windows enable ..\..\bin false Library false + AnyCPU;ARM64 diff --git a/src/Logging/ProtonVPN.Logging.Installers/ProtonVPN.Logging.Installers.csproj b/src/Logging/ProtonVPN.Logging.Installers/ProtonVPN.Logging.Installers.csproj index 90bff1507..2b3575ddc 100644 --- a/src/Logging/ProtonVPN.Logging.Installers/ProtonVPN.Logging.Installers.csproj +++ b/src/Logging/ProtonVPN.Logging.Installers/ProtonVPN.Logging.Installers.csproj @@ -1,12 +1,13 @@ - net6.0-windows + net8.0-windows enable ..\..\bin false Library false + AnyCPU;ARM64 diff --git a/src/Logging/ProtonVPN.Logging.Tests/ProtonVPN.Logging.Tests.csproj b/src/Logging/ProtonVPN.Logging.Tests/ProtonVPN.Logging.Tests.csproj index 2f0a2ec30..39bcbb7a1 100644 --- a/src/Logging/ProtonVPN.Logging.Tests/ProtonVPN.Logging.Tests.csproj +++ b/src/Logging/ProtonVPN.Logging.Tests/ProtonVPN.Logging.Tests.csproj @@ -1,13 +1,14 @@ - net6.0-windows + net8.0-windows enable ..\..\bin false Library false false + AnyCPU;ARM64 diff --git a/src/Logging/ProtonVPN.Logging/ProtonVPN.Logging.csproj b/src/Logging/ProtonVPN.Logging/ProtonVPN.Logging.csproj index 83fe26b55..07d56988a 100644 --- a/src/Logging/ProtonVPN.Logging/ProtonVPN.Logging.csproj +++ b/src/Logging/ProtonVPN.Logging/ProtonVPN.Logging.csproj @@ -1,12 +1,13 @@ - net6.0-windows + net8.0-windows enable ..\..\bin false Library false + AnyCPU;ARM64 diff --git a/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Contracts/IPipeStreamProcessIdentifier.cs b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Contracts/IPipeStreamProcessIdentifier.cs new file mode 100644 index 000000000..5675f9471 --- /dev/null +++ b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Contracts/IPipeStreamProcessIdentifier.cs @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.IO.Pipes; + +namespace ProtonVPN.OperatingSystems.Processes.Contracts; + +public interface IPipeStreamProcessIdentifier +{ + string? GetClientProcessFileName(PipeStream pipeStream); + string? GetServerProcessFileName(PipeStream pipeStream); +} diff --git a/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Contracts/ProtonVPN.OperatingSystems.Processes.Contracts.csproj b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Contracts/ProtonVPN.OperatingSystems.Processes.Contracts.csproj new file mode 100644 index 000000000..52239b14a --- /dev/null +++ b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Contracts/ProtonVPN.OperatingSystems.Processes.Contracts.csproj @@ -0,0 +1,14 @@ + + + net8.0-windows + enable + enable + false + ..\..\..\bin + false + AnyCPU;ARM64 + + + + + \ No newline at end of file diff --git a/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Installers/ProcessesModule.cs b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Installers/ProcessesModule.cs new file mode 100644 index 000000000..c9340fe65 --- /dev/null +++ b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Installers/ProcessesModule.cs @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using Autofac; + +namespace ProtonVPN.OperatingSystems.Processes.Installers; + +public class ProcessesModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().AsImplementedInterfaces().SingleInstance(); + } +} \ No newline at end of file diff --git a/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Installers/ProtonVPN.OperatingSystems.Processes.Installers.csproj b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Installers/ProtonVPN.OperatingSystems.Processes.Installers.csproj new file mode 100644 index 000000000..c7f865b22 --- /dev/null +++ b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes.Installers/ProtonVPN.OperatingSystems.Processes.Installers.csproj @@ -0,0 +1,21 @@ + + + net8.0-windows + enable + enable + false + ..\..\..\bin + false + AnyCPU;ARM64 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes/PipeStreamProcessIdentifier.cs b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes/PipeStreamProcessIdentifier.cs new file mode 100644 index 000000000..4f4dd7e0e --- /dev/null +++ b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes/PipeStreamProcessIdentifier.cs @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.Diagnostics; +using System.IO.Pipes; +using System.Runtime.InteropServices; +using ProtonVPN.Logging.Contracts; +using ProtonVPN.Logging.Contracts.Events.AppLogs; +using ProtonVPN.OperatingSystems.Processes.Contracts; + +namespace ProtonVPN.OperatingSystems.Processes; + +public class PipeStreamProcessIdentifier : IPipeStreamProcessIdentifier +{ + private readonly ILogger _logger; + + public PipeStreamProcessIdentifier(ILogger logger) + { + _logger = logger; + } + + public string? GetClientProcessFileName(PipeStream pipeStream) + { + return GetProcessFileName(GetClientProcessId, pipeStream); + } + + private string? GetProcessFileName(Func processIdRequester, PipeStream pipeStream) + { + try + { + int processId = processIdRequester(pipeStream); + Process? process = processId == 0 ? null : Process.GetProcessById(processId); + return process?.MainModule?.FileName; + } + catch (Exception ex) + { + _logger.Error("Failed to get the PipeStream process.", ex); + return null; + } + } + + private int GetClientProcessId(PipeStream pipeStream) + { + if (GetNamedPipeClientProcessId(pipeStream.SafePipeHandle.DangerousGetHandle(), out uint clientProcessId)) + { + return (int)clientProcessId; + } + return 0; + } + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetNamedPipeClientProcessId(IntPtr hNamedPipe, out uint clientProcessId); + + public string? GetServerProcessFileName(PipeStream pipeStream) + { + return GetProcessFileName(GetServerProcessId, pipeStream); + } + + private int GetServerProcessId(PipeStream pipeStream) + { + if (GetNamedPipeServerProcessId(pipeStream.SafePipeHandle.DangerousGetHandle(), out uint serverProcessId)) + { + return (int)serverProcessId; + } + return 0; + } + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetNamedPipeServerProcessId(IntPtr hNamedPipe, out uint serverProcessId); +} diff --git a/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes/ProtonVPN.OperatingSystems.Processes.csproj b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes/ProtonVPN.OperatingSystems.Processes.csproj new file mode 100644 index 000000000..da21dce4e --- /dev/null +++ b/src/OperatingSystems/Processes/ProtonVPN.OperatingSystems.Processes/ProtonVPN.OperatingSystems.Processes.csproj @@ -0,0 +1,18 @@ + + + net8.0-windows + enable + enable + false + ..\..\..\bin + false + AnyCPU;ARM64 + + + + + + + + + \ No newline at end of file diff --git a/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Contracts/IRegistryEditor.cs b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Contracts/IRegistryEditor.cs new file mode 100644 index 000000000..47775db33 --- /dev/null +++ b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Contracts/IRegistryEditor.cs @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonVPN.OperatingSystems.Registries.Contracts +{ + public interface IRegistryEditor + { + public object? ReadObject(RegistryUri uri); + public int? ReadInt(RegistryUri uri); + public string? ReadString(RegistryUri uri); + + /// Returns 'true' if successfully written or 'false' if an error occurred. + public bool WriteInt(RegistryUri uri, int value); + + /// Returns 'true' if successfully written or 'false' if an error occurred. + public bool WriteString(RegistryUri uri, string value); + + /// Returns 'true' if successfully deleted, 'null' if the key does not exist, + /// or 'false' if the key exists but an error occurred when deleting. + public bool? Delete(RegistryUri uri); + } +} \ No newline at end of file diff --git a/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Contracts/ProtonVPN.OperatingSystems.Registries.Contracts.csproj b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Contracts/ProtonVPN.OperatingSystems.Registries.Contracts.csproj new file mode 100644 index 000000000..52239b14a --- /dev/null +++ b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Contracts/ProtonVPN.OperatingSystems.Registries.Contracts.csproj @@ -0,0 +1,14 @@ + + + net8.0-windows + enable + enable + false + ..\..\..\bin + false + AnyCPU;ARM64 + + + + + \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Channels/GrpcChannelWrapper.cs b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Contracts/RegistryUri.cs similarity index 50% rename from src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Channels/GrpcChannelWrapper.cs rename to src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Contracts/RegistryUri.cs index e9123a46f..398a36c66 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Channels/GrpcChannelWrapper.cs +++ b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Contracts/RegistryUri.cs @@ -17,31 +17,31 @@ * along with ProtonVPN. If not, see . */ -using Grpc.Core; -using ProtoBuf.Grpc.Client; +using Microsoft.Win32; -namespace ProtonVPN.ProcessCommunication.Common.Channels +namespace ProtonVPN.OperatingSystems.Registries.Contracts; + +public class RegistryUri { - public class GrpcChannelWrapper : IGrpcChannelWrapper - { - public string ResolvedTarget => _channel.ResolvedTarget; + public RegistryHive HiveKey { get; } + public string Path { get; } + public string Key { get; } - private readonly Channel _channel; + private RegistryUri(RegistryHive hiveKey, string path, string key) + { + HiveKey = hiveKey; + Path = path; + Key = key; + } - public GrpcChannelWrapper(int serverPort) - { - _channel = new Channel("localhost", serverPort, ChannelCredentials.Insecure); - } + public static RegistryUri CreateLocalMachineUri(string path, string key) + => new(RegistryHive.LocalMachine, path: path, key: key); - public T CreateService() - where T : class - { - return _channel.CreateGrpcService(); - } + public static RegistryUri CreateCurrentUserUri(string path, string key) + => new(RegistryHive.CurrentUser, path: path, key: key); - public Task ShutdownAsync() - { - return _channel.ShutdownAsync(); - } + public override string ToString() + { + return $"'{HiveKey}':'{Path}':'{Key}'"; } } \ No newline at end of file diff --git a/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Installers/ProtonVPN.OperatingSystems.Registries.Installers.csproj b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Installers/ProtonVPN.OperatingSystems.Registries.Installers.csproj new file mode 100644 index 000000000..e12a5de4a --- /dev/null +++ b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Installers/ProtonVPN.OperatingSystems.Registries.Installers.csproj @@ -0,0 +1,21 @@ + + + net8.0-windows + enable + enable + false + ..\..\..\bin + false + AnyCPU;ARM64 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/AppProcessCommunicationModule.cs b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Installers/RegistriesModule.cs similarity index 71% rename from src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/AppProcessCommunicationModule.cs rename to src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Installers/RegistriesModule.cs index 21b3ec4e1..d7a7919ee 100644 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/AppProcessCommunicationModule.cs +++ b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Installers/RegistriesModule.cs @@ -18,16 +18,15 @@ */ using Autofac; -using ProtonVPN.ProcessCommunication.Contracts; +using ProtonVPN.OperatingSystems.Registries.Contracts; -namespace ProtonVPN.ProcessCommunication.App.Installers +namespace ProtonVPN.OperatingSystems.Registries.Installers { - public class AppProcessCommunicationModule : Module + public class RegistriesModule : Module { protected override void Load(ContainerBuilder builder) { - builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); } } } \ No newline at end of file diff --git a/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Installers/RegistryEditorFactory.cs b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Installers/RegistryEditorFactory.cs new file mode 100644 index 000000000..ff421adad --- /dev/null +++ b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries.Installers/RegistryEditorFactory.cs @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using ProtonVPN.Logging.Contracts; +using ProtonVPN.OperatingSystems.Registries.Contracts; + +namespace ProtonVPN.OperatingSystems.Registries.Installers; + +public static class RegistryEditorFactory +{ + public static IRegistryEditor Create(ILogger logger) + { + return new RegistryEditor(logger); + } +} diff --git a/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries/ProtonVPN.OperatingSystems.Registries.csproj b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries/ProtonVPN.OperatingSystems.Registries.csproj new file mode 100644 index 000000000..6fcc7b73a --- /dev/null +++ b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries/ProtonVPN.OperatingSystems.Registries.csproj @@ -0,0 +1,18 @@ + + + net8.0-windows + enable + enable + false + ..\..\..\bin + false + AnyCPU;ARM64 + + + + + + + + + \ No newline at end of file diff --git a/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries/RegistryEditor.cs b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries/RegistryEditor.cs new file mode 100644 index 000000000..e9d07a3e7 --- /dev/null +++ b/src/OperatingSystems/Registries/ProtonVPN.OperatingSystems.Registries/RegistryEditor.cs @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2023 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using Microsoft.Win32; +using ProtonVPN.Logging.Contracts; +using ProtonVPN.Logging.Contracts.Events.AppLogs; +using ProtonVPN.Logging.Contracts.Events.OperatingSystemLogs; +using ProtonVPN.OperatingSystems.Registries.Contracts; + +namespace ProtonVPN.OperatingSystems.Registries; + +public class RegistryEditor : IRegistryEditor +{ + private readonly ILogger _logger; + + public RegistryEditor(ILogger logger) + { + _logger = logger; + } + + public object? ReadObject(RegistryUri uri) + { + RegistryKey? key = null; + try + { + key = OpenBaseKey(uri.HiveKey).OpenSubKey(uri.Path); + if (key != null) + { + return key.GetValue(uri.Key); + } + _logger.Error($"Failed to open registry path before reading {uri}."); + } + catch (Exception ex) + { + _logger.Error($"Failed to read registry {uri}.", ex); + } + finally + { + key?.Close(); + } + return null; + } + + public int? ReadInt(RegistryUri uri) + { + object? registryValue = ReadObject(uri); + if (registryValue is not null) + { + int result; + try + { + result = (int)registryValue; + return result; + } + catch + { + } + string? stringValue = null; + try + { + stringValue = registryValue.ToString(); + if (int.TryParse(stringValue, out result)) + { + return result; + } + } + catch (Exception ex) + { + _logger.Error($"Failed when parsing registry value '{stringValue}' to int.", ex); + } + } + return null; + } + + private RegistryKey OpenBaseKey(RegistryHive registryHive) + { + return RegistryKey.OpenBaseKey(registryHive, RegistryView.Registry64); + } + + public string? ReadString(RegistryUri uri) + { + object? registryValue = ReadObject(uri); + if (registryValue is not null) + { + string result; + try + { + result = (string)registryValue; + return result; + } + catch + { + return registryValue.ToString(); + } + } + return null; + } + + public bool WriteInt(RegistryUri uri, int value) + { + return WriteObject(uri, value, RegistryValueKind.DWord); + } + + private bool WriteObject(RegistryUri uri, object value, RegistryValueKind valueKind) + { + bool isSuccess = false; + RegistryKey key = OpenBaseKey(uri.HiveKey).CreateSubKey(uri.Path, writable: true); + if (key == null) + { + string errorMessage = $"Failed to open registry path before writing to {uri}."; + _logger.Error(errorMessage); + } + else + { + try + { + key.SetValue(uri.Key, value, valueKind); + isSuccess = true; + } + catch (Exception ex) + { + _logger.Error($"Failed when writing {value} to {uri}", ex); + } + finally + { + key?.Close(); + } + } + return isSuccess; + } + + public bool WriteString(RegistryUri uri, string value) + { + return WriteObject(uri, value, RegistryValueKind.String); + } + + public bool? Delete(RegistryUri uri) + { + bool? isSuccess = null; + RegistryKey? key = OpenBaseKey(uri.HiveKey).OpenSubKey(uri.Path, RegistryKeyPermissionCheck.ReadWriteSubTree); + if (key != null) + { + try + { + key.DeleteValue(uri.Key, throwOnMissingValue: false); + isSuccess = true; + } + catch (Exception ex) + { + isSuccess = false; + _logger.Error($"Failed deleting registry {uri}.", ex); + } + finally + { + key?.Close(); + } + } + return isSuccess; + } +} \ No newline at end of file diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/ProtonVPN.ProcessCommunication.App.Installers.csproj b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/ProtonVPN.ProcessCommunication.App.Installers.csproj deleted file mode 100644 index df88c1594..000000000 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/ProtonVPN.ProcessCommunication.App.Installers.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net6.0-windows - enable - ..\..\..\bin - false - Library - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - - diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Tests/AppGrpcClientTest.cs b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Tests/AppGrpcClientTest.cs deleted file mode 100644 index 3c11c3791..000000000 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Tests/AppGrpcClientTest.cs +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using Microsoft.VisualStudio.TestTools.UnitTesting; -using NSubstitute; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.ProcessCommunication.Common.Channels; -using ProtonVPN.ProcessCommunication.Common.Tests; -using ProtonVPN.ProcessCommunication.Contracts; -using ProtonVPN.ProcessCommunication.Contracts.Controllers; -using ProtonVPN.ProcessCommunication.Contracts.Registration; - -namespace ProtonVPN.ProcessCommunication.App.Tests -{ - [TestClass] - public class AppGrpcClientTest - { - private const int SERVICE_SERVER_PORT = 1; - private const int APP_SERVER_PORT = 2; - - private ILogger _logger; - private IServiceServerPortRegister _serviceServerPortRegister; - private IGrpcServer _grpcServer; - private IGrpcChannelWrapper _grpcChannelWrapper; - private IGrpcChannelWrapperFactory _grpcChannelWrapperFactory; - private IAppGrpcClient _appGrpcClient; - - [TestInitialize] - public void Initialize() - { - _logger = Substitute.For(); - _serviceServerPortRegister = Substitute.For(); - _grpcServer = Substitute.For(); - _grpcChannelWrapper = Substitute.For(); - _grpcChannelWrapper.CreateService().Returns(c => Substitute.For()); - _grpcChannelWrapper.CreateService().Returns(c => Substitute.For()); - _grpcChannelWrapperFactory = Substitute.For(); - _grpcChannelWrapperFactory.Create(Arg.Any()).Returns(_grpcChannelWrapper); - _appGrpcClient = new AppGrpcClient(_logger, _serviceServerPortRegister, _grpcServer, _grpcChannelWrapperFactory); - } - - [TestCleanup] - public void Cleanup() - { - _logger = null; - _serviceServerPortRegister = null; - _grpcServer = null; - _grpcChannelWrapper = null; - _grpcChannelWrapperFactory = null; - _appGrpcClient = null; - } - - [TestMethod] - public async Task TestCreateAsync() - { - _serviceServerPortRegister.ReadAsync(Arg.Any()).Returns(SERVICE_SERVER_PORT); - _grpcServer.Port.Returns(APP_SERVER_PORT); - - await _appGrpcClient.CreateAsync(); - - Assert.IsNotNull(_appGrpcClient.VpnController); - } - - [TestMethod] - public async Task TestCreateAsync_NoRaceConditionOccurs() - { - _serviceServerPortRegister.ReadAsync(Arg.Any()).Returns(SERVICE_SERVER_PORT); - _grpcServer.Port.Returns(APP_SERVER_PORT); - int numOfCalls = 64; - - ParallelTestRunner.ExecuteInParallel(numOfCalls, - (int _) => _appGrpcClient.CreateAsync()); - - Assert.IsNotNull(_appGrpcClient.VpnController); - await _serviceServerPortRegister.Received(1).ReadAsync(Arg.Any()); - } - - [TestMethod] - public async Task TestCreateAsync_WhenServiceControllerIsNotNull() - { - _serviceServerPortRegister.ReadAsync(Arg.Any()).Returns(SERVICE_SERVER_PORT); - _grpcServer.Port.Returns(APP_SERVER_PORT); - - await _appGrpcClient.CreateAsync(); - - Assert.IsNotNull(_appGrpcClient.VpnController); - await _serviceServerPortRegister.Received(1).ReadAsync(Arg.Any()); - IVpnController vpnController = _appGrpcClient.VpnController; - - await _appGrpcClient.CreateAsync(); - - Assert.AreEqual(vpnController, _appGrpcClient.VpnController); - await _serviceServerPortRegister.Received(1).ReadAsync(Arg.Any()); - } - - [TestMethod] - public async Task TestRecreateAsync() - { - _serviceServerPortRegister.ReadAsync(Arg.Any()).Returns(SERVICE_SERVER_PORT); - _grpcServer.Port.Returns(APP_SERVER_PORT); - - await _appGrpcClient.RecreateAsync(); - - Assert.IsNotNull(_appGrpcClient.VpnController); - } - - [TestMethod] - public async Task TestRecreateAsync_NoRaceConditionOccurs() - { - _serviceServerPortRegister.ReadAsync(Arg.Any()).Returns(SERVICE_SERVER_PORT); - _grpcServer.Port.Returns(APP_SERVER_PORT); - int numOfCalls = 64; - - ParallelTestRunner.ExecuteInParallel(numOfCalls, - (int _) => _appGrpcClient.RecreateAsync()); - - Assert.IsNotNull(_appGrpcClient.VpnController); - await _serviceServerPortRegister.Received(numOfCalls).ReadAsync(Arg.Any()); - await _grpcChannelWrapper.Received(numOfCalls - 1).ShutdownAsync(); - } - - [TestMethod] - public async Task TestRecreateAsync_WhenServiceControllerIsNotNull() - { - _serviceServerPortRegister.ReadAsync(Arg.Any()).Returns(SERVICE_SERVER_PORT); - _grpcServer.Port.Returns(APP_SERVER_PORT); - - await _appGrpcClient.RecreateAsync(); - - Assert.IsNotNull(_appGrpcClient.VpnController); - await _serviceServerPortRegister.Received(1).ReadAsync(Arg.Any()); - IVpnController vpnController = _appGrpcClient.VpnController; - - await _appGrpcClient.RecreateAsync(); - - Assert.IsNotNull(_appGrpcClient.VpnController); - await _serviceServerPortRegister.Received(2).ReadAsync(Arg.Any()); - Assert.AreNotEqual(vpnController, _appGrpcClient.VpnController); - await _grpcChannelWrapper.Received(1).ShutdownAsync(); - } - - [TestMethod] - public async Task TestGetServiceControllerOrThrowAsync() - { - _serviceServerPortRegister.ReadAsync(Arg.Any()).Returns(SERVICE_SERVER_PORT); - _grpcServer.Port.Returns(APP_SERVER_PORT); - TimeSpan timeout = TimeSpan.FromSeconds(0); - await _appGrpcClient.CreateAsync(); - - await _appGrpcClient.GetServiceControllerOrThrowAsync(timeout); - await _appGrpcClient.GetServiceControllerOrThrowAsync(timeout); - } - - [TestMethod] - public async Task TestGetServiceControllerOrThrowAsync_WhenServiceControllerIsCreatedAfterTheCall() - { - _serviceServerPortRegister.ReadAsync(Arg.Any()).Returns(SERVICE_SERVER_PORT); - _grpcServer.Port.Returns(APP_SERVER_PORT); - TimeSpan timeout = TimeSpan.FromSeconds(5); - - Task task = _appGrpcClient.GetServiceControllerOrThrowAsync(timeout); - await Task.Delay(TimeSpan.FromSeconds(1)); - await _appGrpcClient.CreateAsync(); - IVpnController vpnController = await task; - - Assert.IsNotNull(vpnController); - } - - [TestMethod] - [ExpectedException(typeof(TimeoutException))] - public async Task TestGetServiceControllerOrThrowAsync_WhenServiceControllerIsNullAndTimeoutZero() - { - TimeSpan timeout = TimeSpan.FromSeconds(0); - - await _appGrpcClient.GetServiceControllerOrThrowAsync(timeout); - } - - [TestMethod] - [ExpectedException(typeof(TimeoutException))] - public async Task TestGetServiceControllerOrThrowAsync_WhenServiceControllerIsNullAndTimeoutThreeSeconds() - { - TimeSpan timeout = TimeSpan.FromSeconds(3); - - await _appGrpcClient.GetServiceControllerOrThrowAsync(timeout); - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Tests/GrpcServerTest.cs b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Tests/GrpcServerTest.cs deleted file mode 100644 index 16a919674..000000000 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Tests/GrpcServerTest.cs +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using Microsoft.VisualStudio.TestTools.UnitTesting; -using NSubstitute; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.ProcessCommunication.Common.Tests; -using ProtonVPN.ProcessCommunication.Contracts; -using ProtonVPN.ProcessCommunication.Contracts.Controllers; - -namespace ProtonVPN.ProcessCommunication.App.Tests -{ - [TestClass] - public class GrpcServerTest : GrpcServerTestBase - { - private ILogger _logger; - private IAppController _appController; - - [TestInitialize] - public override void Initialize() - { - _logger = Substitute.For(); - _appController = Substitute.For(); - base.Initialize(); - } - - protected override IGrpcServer CreateGrpcServer() - { - return new GrpcServer(_logger, _appController); - } - - [TestCleanup] - public override void Cleanup() - { - _logger = null; - _appController = null; - base.Initialize(); - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Tests/ProtonVPN.ProcessCommunication.App.Tests.csproj b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Tests/ProtonVPN.ProcessCommunication.App.Tests.csproj deleted file mode 100644 index b889c3566..000000000 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Tests/ProtonVPN.ProcessCommunication.App.Tests.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - net6.0-windows - enable - ..\..\..\bin - false - Library - false - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - - - - - diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/AppGrpcClient.cs b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/AppGrpcClient.cs deleted file mode 100644 index 63b2b1599..000000000 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/AppGrpcClient.cs +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using ProtonVPN.Logging.Contracts; -using ProtonVPN.Logging.Contracts.Events.ProcessCommunicationLogs; -using ProtonVPN.ProcessCommunication.Common; -using ProtonVPN.ProcessCommunication.Common.Channels; -using ProtonVPN.ProcessCommunication.Contracts; -using ProtonVPN.ProcessCommunication.Contracts.Controllers; -using ProtonVPN.ProcessCommunication.Contracts.Entities.Communication; -using ProtonVPN.ProcessCommunication.Contracts.Registration; - -namespace ProtonVPN.ProcessCommunication.App -{ - public class AppGrpcClient : GrpcClientBase, IAppGrpcClient - { - private readonly IServiceServerPortRegister _serviceServerPortRegister; - private readonly IGrpcServer _grpcServer; - private readonly SemaphoreSlim _semaphore = new(1, 1); - - public IVpnController VpnController { get; private set; } - public IUpdateController UpdateController { get; private set; } - - public AppGrpcClient(ILogger logger, - IServiceServerPortRegister serviceServerPortRegister, - IGrpcServer grpcServer, - IGrpcChannelWrapperFactory grpcChannelWrapperFactory) - : base(logger, grpcChannelWrapperFactory) - { - _serviceServerPortRegister = serviceServerPortRegister; - _grpcServer = grpcServer; - } - - public async Task CreateAsync() - { - await SafeWrapperAsync(async () => - { - if (VpnController is null || UpdateController is null) - { - await CreateInternalAsync(); - } - }); - } - - private async Task SafeWrapperAsync(Func function) - { - bool isToEnter = await _semaphore.WaitAsync(0); - if (isToEnter) - { - try - { - await function(); - } - catch - { - } - finally - { - _semaphore.Release(); - } - } - } - - private async Task CreateInternalAsync() - { - CancellationTokenSource cts = new CancellationTokenSource(); - int serviceServerPort = await _serviceServerPortRegister.ReadAsync(cts.Token); - await CreateWithPortAsync(serviceServerPort); - int? appServerPort = _grpcServer?.Port; - if (VpnController is not null && appServerPort is not null) - { - await RegisterStateConsumerAsync(appServerPort.Value); - } - } - - private async Task RegisterStateConsumerAsync(int appServerPort) - { - Logger.Info($"Sending the app gRPC server port {appServerPort} to service."); - try - { - await VpnController.RegisterStateConsumer(new StateConsumerIpcEntity - { - ServerPort = appServerPort - }); - } - catch (Exception e) - { - Logger.Error($"An error occurred when " + - $"sending the app gRPC server port {appServerPort} to service.", e); - } - } - - public async Task RecreateAsync() - { - await SafeWrapperAsync(async () => - { - VpnController = null; - UpdateController = null; - await CreateInternalAsync(); - }); - } - - protected override void RegisterServices(IGrpcChannelWrapper channel) - { - VpnController = channel.CreateService(); - UpdateController = channel.CreateService(); - } - - public async Task GetServiceControllerOrThrowAsync(TimeSpan timeout) where T : IServiceController - { - CancellationTokenSource cts = new(timeout); - IServiceController serviceController = GetServiceController(); - - try - { - while (serviceController is null && !cts.IsCancellationRequested) - { - await Task.Delay(TimeSpan.FromSeconds(1), cts.Token); - serviceController = GetServiceController(); - } - } - catch - { - } - - if (serviceController is null) - { - string errorMessage = $"Failed to get the Service Controller within the allotted time '{timeout}'."; - Logger.Error(errorMessage); - throw new TimeoutException(errorMessage); - } - - return (T)serviceController; - } - - public IServiceController GetServiceController() - { - if (typeof(T).IsAssignableFrom(typeof(IVpnController))) - { - return VpnController; - } - - if (typeof(T).IsAssignableFrom(typeof(IUpdateController))) - { - return UpdateController; - } - - throw new NotImplementedException($"Controller of type {typeof(T)} is not supported."); - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/FirstAppInstanceCaller.cs b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/FirstAppInstanceCaller.cs deleted file mode 100644 index 5fe3b0a66..000000000 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/FirstAppInstanceCaller.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using ProtonVPN.Logging.Contracts; -using ProtonVPN.ProcessCommunication.Common.Channels; -using ProtonVPN.ProcessCommunication.Common.Registration; -using ProtonVPN.ProcessCommunication.Contracts.Controllers; - -namespace ProtonVPN.ProcessCommunication.App -{ - public static class FirstAppInstanceCaller - { - public static async Task OpenMainWindowAsync(string args) - { - AppServerPortRegister appServerPortRegister = new(new NullLogger()); - int? appServerPort = appServerPortRegister.ReadOnce(); - if (appServerPort.HasValue && GrpcChannelWrapperFactory.IsPortValid(appServerPort.Value)) - { - await CreateGrpcChannelAndSendOpenWindowCommandAsync(appServerPort.Value, args); - } - } - - private static async Task CreateGrpcChannelAndSendOpenWindowCommandAsync(int appServerPort, string args) - { - try - { - GrpcChannelWrapper grpcChannelWrapper = new(appServerPort); - IAppController appController = grpcChannelWrapper.CreateService(); - await SendOpenWindowCommandAsync(appController, args); - await grpcChannelWrapper.ShutdownAsync(); - } - catch - { - } - } - - private static async Task SendOpenWindowCommandAsync(IAppController appController, string args) - { - try - { - await appController.OpenWindow(args); - } - catch - { - } - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/ProtonVPN.ProcessCommunication.App.csproj b/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/ProtonVPN.ProcessCommunication.App.csproj deleted file mode 100644 index fd63745ae..000000000 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App/ProtonVPN.ProcessCommunication.App.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net6.0-windows - enable - ..\..\..\bin - false - Library - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - - diff --git a/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client.Installers/ClientProcessCommunicationModule.cs b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client.Installers/ClientProcessCommunicationModule.cs new file mode 100644 index 000000000..afbb14339 --- /dev/null +++ b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client.Installers/ClientProcessCommunicationModule.cs @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using Autofac; + +namespace ProtonVPN.ProcessCommunication.Client.Installers; + +public class ClientProcessCommunicationModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().AsImplementedInterfaces().SingleInstance(); + builder.RegisterType().AsImplementedInterfaces().SingleInstance(); + } +} \ No newline at end of file diff --git a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/FirstAppInstanceCallerInitializer.cs b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client.Installers/FirstAppInstanceCallerInitializer.cs similarity index 90% rename from src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/FirstAppInstanceCallerInitializer.cs rename to src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client.Installers/FirstAppInstanceCallerInitializer.cs index 41e1e1010..f94b7665c 100644 --- a/src/ProcessCommunication/App/ProtonVPN.ProcessCommunication.App.Installers/FirstAppInstanceCallerInitializer.cs +++ b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client.Installers/FirstAppInstanceCallerInitializer.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Proton AG + * Copyright (c) 2024 Proton AG * * This file is part of ProtonVPN. * @@ -17,7 +17,7 @@ * along with ProtonVPN. If not, see . */ -namespace ProtonVPN.ProcessCommunication.App.Installers +namespace ProtonVPN.ProcessCommunication.Client.Installers { public static class FirstAppInstanceCallerInitializer { @@ -26,4 +26,4 @@ public static async Task OpenMainWindowAsync(string args) await FirstAppInstanceCaller.OpenMainWindowAsync(args); } } -} \ No newline at end of file +} diff --git a/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client.Installers/ProtonVPN.ProcessCommunication.Client.Installers.csproj b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client.Installers/ProtonVPN.ProcessCommunication.Client.Installers.csproj new file mode 100644 index 000000000..dfec65cb2 --- /dev/null +++ b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client.Installers/ProtonVPN.ProcessCommunication.Client.Installers.csproj @@ -0,0 +1,23 @@ + + + net8.0-windows + enable + ..\..\..\bin + false + Library + false + AnyCPU;ARM64 + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + \ No newline at end of file diff --git a/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/FirstAppInstanceCaller.cs b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/FirstAppInstanceCaller.cs new file mode 100644 index 000000000..39376999c --- /dev/null +++ b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/FirstAppInstanceCaller.cs @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using ProtonVPN.Logging.Contracts; +using ProtonVPN.OperatingSystems.Registries.Contracts; +using ProtonVPN.OperatingSystems.Registries.Installers; +using ProtonVPN.ProcessCommunication.Contracts.Controllers; + +namespace ProtonVPN.ProcessCommunication.Client +{ + public static class FirstAppInstanceCaller + { + public static async Task OpenMainWindowAsync(string args) + { + ILogger logger = new NullLogger(); + IRegistryEditor registryEditor = RegistryEditorFactory.Create(logger); + NamedPipesConnectionFactory namedPipesConnectionFactory = new(registryEditor); + GrpcClient grpcClient = new(logger, namedPipesConnectionFactory); + grpcClient.Create(); + IUiController uiController = await grpcClient.GetServiceControllerOrThrowAsync(TimeSpan.FromMinutes(1)); + await SendOpenWindowCommandAsync(uiController, args); + } + + private static async Task SendOpenWindowCommandAsync(IUiController uiController, string args) + { + try + { + await uiController.OpenWindow(args); + } + catch + { + } + } + } +} diff --git a/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/GrpcClient.cs b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/GrpcClient.cs new file mode 100644 index 000000000..41acc7d83 --- /dev/null +++ b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/GrpcClient.cs @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using Grpc.Net.Client; +using ProtoBuf.Grpc.Client; +using ProtonVPN.Logging.Contracts; +using ProtonVPN.Logging.Contracts.Events.ProcessCommunicationLogs; +using ProtonVPN.ProcessCommunication.Contracts; +using ProtonVPN.ProcessCommunication.Contracts.Controllers; + +namespace ProtonVPN.ProcessCommunication.Client; + +public class GrpcClient : IGrpcClient +{ + private readonly ILogger _logger; + private readonly INamedPipesConnectionFactory _namedPipesConnectionFactory; + private readonly object _lock = new(); + private GrpcChannel _channel; + + public IClientController ClientController { get; private set; } + public IUpdateController UpdateController { get; private set; } + public IVpnController VpnController { get; private set; } + public IUiController UiController { get; private set; } + + public GrpcClient(ILogger logger, INamedPipesConnectionFactory namedPipesConnectionFactory) + { + _logger = logger; + _namedPipesConnectionFactory = namedPipesConnectionFactory; + } + + public void Stop() + { + _namedPipesConnectionFactory.Stop(); + } + + public void CreateIfPipeNameChanged() + { + if (_namedPipesConnectionFactory.HasPipeNameChanged()) + { + Create(); + } + } + + public void Create() + { + lock (_lock) + { + _channel?.Dispose(); + + _channel = CreateChannel(); + + ClientController = _channel.CreateGrpcService(); + UpdateController = _channel.CreateGrpcService(); + VpnController = _channel.CreateGrpcService(); + UiController = _channel.CreateGrpcService(); + } + } + + private GrpcChannel CreateChannel() + { + SocketsHttpHandler socketsHttpHandler = new() + { + ConnectCallback = _namedPipesConnectionFactory.ConnectAsync + }; + + return GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions + { + HttpHandler = socketsHttpHandler + }); + } + + public async Task GetServiceControllerOrThrowAsync(TimeSpan timeout) where T : IServiceController + { + CancellationTokenSource cts = new(timeout); + IServiceController serviceController = GetServiceController(); + + try + { + while (serviceController is null && !cts.IsCancellationRequested) + { + await Task.Delay(TimeSpan.FromMilliseconds(200), cts.Token); + serviceController = GetServiceController(); + } + } + catch + { + } + + if (serviceController is null) + { + string errorMessage = $"Failed to get the Service Controller within the allotted time '{timeout}'."; + _logger.Error(errorMessage); + throw new TimeoutException(errorMessage); + } + + return (T)serviceController; + } + + public IServiceController GetServiceController() + { + if (typeof(T).IsAssignableFrom(typeof(IVpnController))) + { + return VpnController; + } + + if (typeof(T).IsAssignableFrom(typeof(IUpdateController))) + { + return UpdateController; + } + + if (typeof(T).IsAssignableFrom(typeof(IUiController))) + { + return UiController; + } + + throw new NotImplementedException($"Controller of type {typeof(T)} is not supported."); + } +} diff --git a/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/INamedPipesConnectionFactory.cs b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/INamedPipesConnectionFactory.cs new file mode 100644 index 000000000..7170eb8ed --- /dev/null +++ b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/INamedPipesConnectionFactory.cs @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonVPN.ProcessCommunication.Client; + +public interface INamedPipesConnectionFactory +{ + ValueTask ConnectAsync(SocketsHttpConnectionContext _, + CancellationToken cancellationToken = default); + void Stop(); + bool HasPipeNameChanged(); +} diff --git a/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/NamedPipesConnectionFactory.cs b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/NamedPipesConnectionFactory.cs new file mode 100644 index 000000000..439fe0bf6 --- /dev/null +++ b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/NamedPipesConnectionFactory.cs @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.IO.Pipes; +using System.Security.Principal; +using ProtonVPN.Common.Extensions; +using ProtonVPN.OperatingSystems.Registries.Contracts; +using ProtonVPN.ProcessCommunication.Common; + +namespace ProtonVPN.ProcessCommunication.Client; + +public class NamedPipesConnectionFactory : INamedPipesConnectionFactory +{ + private readonly RegistryUri _registryUri = RegistryUri.CreateLocalMachineUri( + NamedPipeConfiguration.REGISTRY_PATH, NamedPipeConfiguration.REGISTRY_KEY); + private readonly TimeSpan _minConnectionRetryInterval = TimeSpan.FromSeconds(1); + private readonly TimeSpan _maxConnectionRetryInterval = TimeSpan.FromSeconds(5); + private readonly TimeSpan _minRegistryRetryInterval = TimeSpan.FromSeconds(1); + private readonly TimeSpan _maxRegistryRetryInterval = TimeSpan.FromSeconds(5); + private readonly IRegistryEditor _registryEditor; + + private TimeSpan? _connectionRetryInterval; + private TimeSpan? _registryRetryInterval; + private string? _pipeName; + private readonly CancellationTokenSource _cancellationTokenSource = new(); + + public NamedPipesConnectionFactory(IRegistryEditor registryEditor) + { + _registryEditor = registryEditor; + } + + public async ValueTask ConnectAsync(SocketsHttpConnectionContext _, + CancellationToken cancellationToken = default) + { + return await InternalConnectAsync(CancellationTokenSource.CreateLinkedTokenSource( + cancellationToken, _cancellationTokenSource.Token).Token); + } + + private async Task InternalConnectAsync(CancellationToken cancellationToken) + { + string pipeName = await GetPipeNameAsync(cancellationToken) ?? throw new ArgumentNullException("PipeName"); + NamedPipeClientStream clientStream = new( + serverName: ".", + pipeName: pipeName, + direction: PipeDirection.InOut, + options: PipeOptions.WriteThrough | PipeOptions.Asynchronous, + impersonationLevel: TokenImpersonationLevel.Anonymous); + + try + { + _pipeName = pipeName; + await clientStream.ConnectAsync(cancellationToken).ConfigureAwait(false); + + // No authorization checks are made because user processes without admin permissions such as this Client + // cannot get the executable path of SYSTEM processes such as our Service + + return clientStream; + } + catch + { + clientStream?.Dispose(); + + _connectionRetryInterval = _connectionRetryInterval is null + ? _minConnectionRetryInterval + : TimeSpanExtensions.Min(_connectionRetryInterval.Value * 2, _maxConnectionRetryInterval); + await Task.Delay(_connectionRetryInterval.Value, cancellationToken); + + throw; + } + } + + private async Task GetPipeNameAsync(CancellationToken cancellationToken) + { + _registryRetryInterval = null; + while (!cancellationToken.IsCancellationRequested) + { + string? pipeName = GetPipeName(); + if (!string.IsNullOrWhiteSpace(pipeName)) + { + return pipeName; + } + + _registryRetryInterval = _registryRetryInterval is null + ? _minRegistryRetryInterval + : TimeSpanExtensions.Min(_registryRetryInterval.Value * 2, _maxRegistryRetryInterval); + await Task.Delay(_registryRetryInterval.Value, cancellationToken); + continue; + } + return null; + } + + private string? GetPipeName() + { + return _registryEditor.ReadString(_registryUri); + } + + public void Stop() + { + _cancellationTokenSource.Cancel(); + } + + public bool HasPipeNameChanged() + { + return _pipeName != GetPipeName(); + } +} \ No newline at end of file diff --git a/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/ProtonVPN.ProcessCommunication.Client.csproj b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/ProtonVPN.ProcessCommunication.Client.csproj new file mode 100644 index 000000000..7b5499d69 --- /dev/null +++ b/src/ProcessCommunication/Client/ProtonVPN.ProcessCommunication.Client/ProtonVPN.ProcessCommunication.Client.csproj @@ -0,0 +1,28 @@ + + + net8.0-windows + enable + ..\..\..\bin + false + Library + false + AnyCPU;ARM64 + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Registration/IServerPortRegister.cs b/src/ProcessCommunication/Common/ProtonVPN.ProcessCommunication.Common/NamedPipeConfiguration.cs similarity index 72% rename from src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Registration/IServerPortRegister.cs rename to src/ProcessCommunication/Common/ProtonVPN.ProcessCommunication.Common/NamedPipeConfiguration.cs index e73b46401..fe24d21f8 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Registration/IServerPortRegister.cs +++ b/src/ProcessCommunication/Common/ProtonVPN.ProcessCommunication.Common/NamedPipeConfiguration.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Proton AG + * Copyright (c) 2024 Proton AG * * This file is part of ProtonVPN. * @@ -17,12 +17,10 @@ * along with ProtonVPN. If not, see . */ -namespace ProtonVPN.ProcessCommunication.Contracts.Registration +namespace ProtonVPN.ProcessCommunication.Common; + +public static class NamedPipeConfiguration { - public interface IServerPortRegister - { - void Write(int serverBoundPort); - void Delete(); - int? ReadOnce(); - } -} \ No newline at end of file + public const string REGISTRY_PATH = @"SOFTWARE\Proton AG\Proton VPN\gRPC"; + public const string REGISTRY_KEY = "PipeName"; +} diff --git a/src/ProcessCommunication/Common/ProtonVPN.ProcessCommunication.Common/ProtonVPN.ProcessCommunication.Common.csproj b/src/ProcessCommunication/Common/ProtonVPN.ProcessCommunication.Common/ProtonVPN.ProcessCommunication.Common.csproj new file mode 100644 index 000000000..c18025019 --- /dev/null +++ b/src/ProcessCommunication/Common/ProtonVPN.ProcessCommunication.Common/ProtonVPN.ProcessCommunication.Common.csproj @@ -0,0 +1,16 @@ + + + net8.0-windows + enable + ..\..\..\bin + false + Library + false + AnyCPU;ARM64 + + + + Properties\GlobalAssemblyInfo.cs + + + \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/Channels/GrpcChannelWrapperFactoryTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/Channels/GrpcChannelWrapperFactoryTest.cs deleted file mode 100644 index 0eeba0b25..000000000 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/Channels/GrpcChannelWrapperFactoryTest.cs +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using Microsoft.VisualStudio.TestTools.UnitTesting; -using NSubstitute; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.ProcessCommunication.Common.Channels; - -namespace ProtonVPN.ProcessCommunication.Common.Tests.Channels -{ - [TestClass] - public class GrpcChannelWrapperFactoryTest - { - private ILogger _logger; - private GrpcChannelWrapperFactory _grpcChannelWrapperFactory; - - [TestInitialize] - public void Initialize() - { - _logger = Substitute.For(); - _grpcChannelWrapperFactory = new GrpcChannelWrapperFactory(_logger); - } - - [TestCleanup] - public void Cleanup() - { - _logger = null; - _grpcChannelWrapperFactory = null; - } - - [TestMethod] - [DataRow(1)] - [DataRow(80)] - [DataRow(65535)] - public void TestCreate(int serverPort) - { - IGrpcChannelWrapper result = _grpcChannelWrapperFactory.Create(serverPort); - - Assert.IsNotNull(result); - Assert.IsNotNull(result.ResolvedTarget); - Assert.AreEqual(result.ResolvedTarget, $"localhost:{serverPort}"); - } - - [TestMethod] - [DataRow(0)] - [DataRow(65536)] - [ExpectedException(typeof(ArgumentException))] - public void TestCreate_Throws(int serverPort) - { - _grpcChannelWrapperFactory.Create(serverPort); - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/GrpcServerTestBase.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/GrpcServerTestBase.cs deleted file mode 100644 index 3f5793f76..000000000 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/GrpcServerTestBase.cs +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using Microsoft.VisualStudio.TestTools.UnitTesting; -using ProtonVPN.ProcessCommunication.Contracts; - -namespace ProtonVPN.ProcessCommunication.Common.Tests -{ - [TestClass] - public abstract class GrpcServerTestBase - { - private bool _isOnStartEventCalled; - private IGrpcServer _grpcServer; - - [TestInitialize] - public virtual void Initialize() - { - _isOnStartEventCalled = false; - _grpcServer = CreateGrpcServer(); - } - - protected abstract IGrpcServer CreateGrpcServer(); - - [TestCleanup] - public virtual void Cleanup() - { - _isOnStartEventCalled = false; - _grpcServer = null; - } - - [TestMethod] - public virtual void TestCreateAndStart() - { - _grpcServer.OnStart += OnGrpcServerStart; - - _grpcServer.CreateAndStart(); - - Assert.IsNotNull(_grpcServer.Port); - Assert.IsTrue(_isOnStartEventCalled); - } - - [TestMethod] - public virtual void TestCreateAndStart_WithoutEventListener() - { - _grpcServer.CreateAndStart(); - - Assert.IsNotNull(_grpcServer.Port); - Assert.IsFalse(_isOnStartEventCalled); - } - - private void OnGrpcServerStart(object sender, EventArgs e) - { - _isOnStartEventCalled = true; - } - - [TestMethod] - public virtual async Task ShutdownAsync_WhenServerIsNull() - { - await _grpcServer.ShutdownAsync(); - } - - [TestMethod] - public virtual async Task ShutdownAsync_WhenServerIsNotNull() - { - _grpcServer.CreateAndStart(); - - await _grpcServer.ShutdownAsync(); - } - - [TestMethod] - public virtual async Task KillAsync_WhenServerIsNull() - { - await _grpcServer.KillAsync(); - } - - [TestMethod] - public virtual async Task KillAsync_WhenServerIsNotNull() - { - _grpcServer.CreateAndStart(); - - await _grpcServer.KillAsync(); - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/ParallelTestRunner.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/ParallelTestRunner.cs deleted file mode 100644 index 4af65ccd3..000000000 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/ParallelTestRunner.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -namespace ProtonVPN.ProcessCommunication.Common.Tests -{ - public static class ParallelTestRunner - { - public static void ExecuteInParallel(int numOfCalls, Func functionToRepeat) - { - IList tasks = new List(); - for (int i = 0; i < numOfCalls; i++) - { - tasks.Add(functionToRepeat(i)); - } - Task.WaitAll(tasks.ToArray()); - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/ProtonVPN.ProcessCommunication.Common.Tests.csproj b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/ProtonVPN.ProcessCommunication.Common.Tests.csproj deleted file mode 100644 index ab8311116..000000000 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/ProtonVPN.ProcessCommunication.Common.Tests.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - net6.0-windows - enable - ..\..\bin - false - Library - false - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - - - - - - diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/Registration/ServiceServerPortRegisterTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/Registration/ServiceServerPortRegisterTest.cs deleted file mode 100644 index ea525ef58..000000000 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common.Tests/Registration/ServiceServerPortRegisterTest.cs +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using Microsoft.VisualStudio.TestTools.UnitTesting; -using NSubstitute; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.ProcessCommunication.Common.Registration; - -namespace ProtonVPN.ProcessCommunication.Common.Tests.Registration -{ - // Initialize() before each call to make sure no cache is being used - [TestClass] - public class ServiceServerPortRegisterTest - { - private ILogger _logger; - private ServiceServerPortRegister _serviceServerPortRegister; - - [TestInitialize] - public void Initialize() - { - _logger = Substitute.For(); - _serviceServerPortRegister = new ServiceServerPortRegister(_logger); - } - - [TestCleanup] - public void Cleanup() - { - _logger = null; - _serviceServerPortRegister = null; - } - - [TestMethod] - public void TestReadOnce_WhenNothingIsWritten() - { - int? result = _serviceServerPortRegister.ReadOnce(); - - Assert.IsNull(result); - } - - [TestMethod] - public void TestWrite_ReadOnce_Delete_ReadOnce() - { - //Write - int timestamp = GetCurrentDayMilliseconds(); - _serviceServerPortRegister.Write(timestamp); - - //ReadOnce - Initialize(); - int? result = _serviceServerPortRegister.ReadOnce(); - Assert.IsNotNull(result); - Assert.AreEqual(result.Value, timestamp); - - //Delete - Initialize(); - _serviceServerPortRegister.Delete(); - - //ReadOnce - Initialize(); - int? result2 = _serviceServerPortRegister.ReadOnce(); - Assert.IsNull(result2); - } - - private int GetCurrentDayMilliseconds() - { - DateTime utcNow = DateTime.UtcNow; - return (int)utcNow.Subtract(new DateTime(utcNow.Year, utcNow.Month, utcNow.Day)).TotalMilliseconds; - } - - [TestMethod] - public async Task TestWrite_ReadAsync_Delete_ReadOnce() - { - //Write - int timestamp = GetCurrentDayMilliseconds(); - _serviceServerPortRegister.Write(timestamp); - - //ReadAsync - CancellationTokenSource cts = new(); - cts.Cancel(); - Initialize(); - int result = await _serviceServerPortRegister.ReadAsync(cts.Token); - Assert.AreEqual(result, timestamp); - - //Delete - Initialize(); - _serviceServerPortRegister.Delete(); - - //ReadOnce - Initialize(); - int? result2 = _serviceServerPortRegister.ReadOnce(); - Assert.IsNull(result2); - } - - [TestMethod] - [ExpectedException(typeof(TaskCanceledException))] - public async Task TestReadAsync_WhenNothingIsWritten() - { - CancellationTokenSource cts = new(); - cts.Cancel(); - - await _serviceServerPortRegister.ReadAsync(cts.Token); - } - - [TestMethod] - public async Task TestReadAsync_WhenSomethingIsWrittenLater() - { - //ReadAsync start - CancellationTokenSource cts = new(); - Task readAsyncTask = _serviceServerPortRegister.ReadAsync(cts.Token); - await Task.Delay(TimeSpan.FromMilliseconds(500)); - - //Write - int timestamp = GetCurrentDayMilliseconds(); - Initialize(); - _serviceServerPortRegister.Write(timestamp); - - //ReadAsync await - int result = await readAsyncTask; - Assert.AreEqual(result, timestamp); - - //Delete - Initialize(); - _serviceServerPortRegister.Delete(); - - //ReadOnce - Initialize(); - int? result2 = _serviceServerPortRegister.ReadOnce(); - Assert.IsNull(result2); - } - - [TestMethod] - public void TestDelete() - { - //ReadOnce - int? result = _serviceServerPortRegister.ReadOnce(); - Assert.IsNull(result); - - //Delete - Initialize(); - _serviceServerPortRegister.Delete(); - - //ReadOnce - Initialize(); - int? result2 = _serviceServerPortRegister.ReadOnce(); - Assert.IsNull(result2); - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Channels/GrpcChannelWrapperFactory.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Channels/GrpcChannelWrapperFactory.cs deleted file mode 100644 index cdc3bf86e..000000000 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Channels/GrpcChannelWrapperFactory.cs +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using ProtonVPN.Logging.Contracts; -using ProtonVPN.Logging.Contracts.Events.ProcessCommunicationLogs; - -namespace ProtonVPN.ProcessCommunication.Common.Channels -{ - public class GrpcChannelWrapperFactory : IGrpcChannelWrapperFactory - { - private readonly ILogger _logger; - - public GrpcChannelWrapperFactory(ILogger logger) - { - _logger = logger; - } - - public IGrpcChannelWrapper Create(int serverPort) - { - ValidatePort(serverPort); - return new GrpcChannelWrapper(serverPort); - } - - public static bool IsPortValid(int serverPort) - { - return serverPort > 0 && serverPort <= ushort.MaxValue; - } - - private void ValidatePort(int serverPort) - { - if (!IsPortValid(serverPort)) - { - string errorMessage = $"Cannot create a gRPC Client to Server Port {serverPort}. " + - $"It needs to be between [1-{ushort.MaxValue}]."; - _logger.Error(errorMessage); - throw new ArgumentException(errorMessage, nameof(serverPort)); - } - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/GrpcClientBase.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/GrpcClientBase.cs deleted file mode 100644 index 771cba01c..000000000 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/GrpcClientBase.cs +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using ProtonVPN.Logging.Contracts; -using ProtonVPN.Logging.Contracts.Events.ProcessCommunicationLogs; -using ProtonVPN.ProcessCommunication.Common.Channels; - -namespace ProtonVPN.ProcessCommunication.Common -{ - public abstract class GrpcClientBase - { - protected int? ServerPort { get; private set; } - protected ILogger Logger { get; private set; } - - private readonly IGrpcChannelWrapperFactory _grpcChannelWrapperFactory; - private readonly object _channelLock = new(); - private IGrpcChannelWrapper _channel; - - protected GrpcClientBase(ILogger logger, IGrpcChannelWrapperFactory grpcChannelWrapperFactory) - { - Logger = logger; - _grpcChannelWrapperFactory = grpcChannelWrapperFactory; - } - - protected async Task CreateWithPortAsync(int serverPort) - { - IGrpcChannelWrapper oldChannel = null; - lock(_channelLock) - { - oldChannel = _channel; - IGrpcChannelWrapper newChannel = _grpcChannelWrapperFactory.Create(serverPort); - RegisterServices(newChannel); - _channel = newChannel; - ServerPort = serverPort; - } - Logger.Info($"A new gRPC Client has been created to Server Port {serverPort}."); - await ShutdownChannelIfExists(oldChannel); - } - - protected abstract void RegisterServices(IGrpcChannelWrapper channel); - - private async Task ShutdownChannelIfExists(IGrpcChannelWrapper channel) - { - if (channel is not null) - { - string serverEndpoint = channel.ResolvedTarget; - try - { - await channel.ShutdownAsync(); - } - catch (Exception e) - { - Logger.Error($"A gRPC Client has failed to stop. Server endpoint: '{serverEndpoint}'", e); - return; - } - Logger.Info($"A gRPC Client has been stopped. Server endpoint: '{serverEndpoint}'"); - } - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/GrpcServerBase.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/GrpcServerBase.cs deleted file mode 100644 index 0fad3c2f4..000000000 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/GrpcServerBase.cs +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ -using Grpc.Core; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.Logging.Contracts.Events.ProcessCommunicationLogs; -using ProtonVPN.ProcessCommunication.Contracts; -using static Grpc.Core.Server; - -namespace ProtonVPN.ProcessCommunication.Common -{ - public abstract class GrpcServerBase : IGrpcServer - { - public int? Port { get; private set; } - - public event EventHandler? OnStart; - - protected ILogger Logger { get; private set; } - protected Server? Server { get; private set; } - - protected GrpcServerBase(ILogger logger) - { - Logger = logger; - } - - public virtual void CreateAndStart() - { - ServerPort serverPort = new("localhost", ServerPort.PickUnused, ServerCredentials.Insecure); - Server = new Server() { Ports = { serverPort } }; - RegisterServices(Server.Services); - Server.Start(); - int port = Server.Ports.First().BoundPort; - Logger.Info($"A new gRPC Server has been created using Port {port}."); - Port = port; - OnStart?.Invoke(this, EventArgs.Empty); - } - - protected abstract void RegisterServices(ServiceDefinitionCollection services); - - public virtual async Task ShutdownAsync() - { - Server? server = Server; - if (server is not null) - { - await server.ShutdownAsync(); - } - } - - public virtual async Task KillAsync() - { - Server? server = Server; - if (server is not null) - { - await server.KillAsync(); - } - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/ProtonVPN.ProcessCommunication.Common.csproj b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/ProtonVPN.ProcessCommunication.Common.csproj deleted file mode 100644 index 696f8aa0f..000000000 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/ProtonVPN.ProcessCommunication.Common.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net6.0-windows - enable - ..\..\bin - false - Library - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - - diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Registration/ServerPortRegisterBase.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Registration/ServerPortRegisterBase.cs deleted file mode 100644 index ddba2c322..000000000 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Registration/ServerPortRegisterBase.cs +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using Microsoft.Win32; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.Logging.Contracts.Events.ProcessCommunicationLogs; - -namespace ProtonVPN.ProcessCommunication.Common.Registration -{ - public abstract class ServerPortRegisterBase - { - private const string PATH = "SOFTWARE\\Proton AG\\Proton VPN\\gRPC"; - - protected ILogger Logger { get; private set; } - - protected ServerPortRegisterBase(ILogger logger) - { - Logger = logger; - } - - public void Write(int serverBoundPort) - { - RegistryKey key = OpenBaseKey().CreateSubKey(PATH); - if (key == null) - { - string errorMessage = "Failed to open registry path before writing the gRPC server port."; - Logger.Error(errorMessage); - throw new Exception(errorMessage); - } - try - { - key.SetValue(GetKey(), serverBoundPort, RegistryValueKind.DWord); - } - catch (Exception ex) - { - Logger.Error("Failed when writing the gRPC server port.", ex); - } - finally - { - key?.Close(); - } - } - - private RegistryKey OpenBaseKey() - { - return RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); - } - - protected abstract string GetKey(); - - public void Delete() - { - RegistryKey key = OpenBaseKey().OpenSubKey(PATH, RegistryKeyPermissionCheck.ReadWriteSubTree); - if (key != null) - { - try - { - key.DeleteValue(GetKey()); - } - catch (Exception ex) - { - Logger.Error("Failed when deleting the gRPC server port.", ex); - } - finally - { - key?.Close(); - } - } - } - - public int? ReadOnce() - { - object rawRegistryValue = ReadRawRegistryValue(); - return ParseRawRegistryValue(rawRegistryValue); - } - - private object ReadRawRegistryValue() - { - RegistryKey key = null; - try - { - key = OpenBaseKey().OpenSubKey(PATH); - if (key == null) - { - Logger.Error("Failed to open registry path before reading the gRPC server port."); - return null; - } - object? serverBoundPortObject = key.GetValue(GetKey()); - return serverBoundPortObject; - } - catch (Exception ex) - { - Logger.Error("Failed to read gRPC server port from registry.", ex); - return null; - } - finally - { - key?.Close(); - } - } - - private int? ParseRawRegistryValue(object registryValue) - { - if (registryValue is not null) - { - int serverBoundPort; - try - { - serverBoundPort = (int)registryValue; - return serverBoundPort; - } - catch - { - } - try - { - if (int.TryParse(registryValue.ToString(), out serverBoundPort)) - { - return serverBoundPort; - } - } - catch (Exception ex) - { - Logger.Error("Failed when parsing the gRPC server port.", ex); - } - } - return null; - } - } -} diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Registration/ServiceServerPortRegister.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Registration/ServiceServerPortRegister.cs deleted file mode 100644 index b2823b314..000000000 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Registration/ServiceServerPortRegister.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using ProtonVPN.Logging.Contracts; -using ProtonVPN.ProcessCommunication.Contracts.Registration; - -namespace ProtonVPN.ProcessCommunication.Common.Registration -{ - public class ServiceServerPortRegister : ServerPortRegisterBase, IServiceServerPortRegister - { - private const string KEY = "ServiceServerPort"; - - private static readonly TimeSpan DELAY = TimeSpan.FromMilliseconds(100); - - public ServiceServerPortRegister(ILogger logger) - : base(logger) - { - } - - protected override string GetKey() - { - return KEY; - } - - public async Task ReadAsync(CancellationToken cancellationToken) - { - while (true) - { - int? serverBoundPort = ReadOnce(); - if (serverBoundPort.HasValue && serverBoundPort.Value > 0) - { - return serverBoundPort.Value; - } - await Task.Delay(DELAY, cancellationToken); - } - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IClientController.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IClientController.cs new file mode 100644 index 000000000..d1f384b2a --- /dev/null +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IClientController.cs @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.ServiceModel; +using ProtonVPN.ProcessCommunication.Contracts.Entities.NetShield; +using ProtonVPN.ProcessCommunication.Contracts.Entities.PortForwarding; +using ProtonVPN.ProcessCommunication.Contracts.Entities.Update; +using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; + +namespace ProtonVPN.ProcessCommunication.Contracts.Controllers; + +[ServiceContract] +public interface IClientController +{ + [OperationContract] + IAsyncEnumerable StreamVpnStateChangeAsync(); + + [OperationContract] + IAsyncEnumerable StreamPortForwardingStateChangeAsync(); + + [OperationContract] + IAsyncEnumerable StreamConnectionDetailsChangeAsync(); + + [OperationContract] + IAsyncEnumerable StreamNetShieldStatisticChangeAsync(); + + [OperationContract] + IAsyncEnumerable StreamUpdateStateChangeAsync(); + + [OperationContract] + IAsyncEnumerable StreamOpenWindowAsync(); +} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IServiceController.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IServiceController.cs index 227b875e7..3692c18ae 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IServiceController.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IServiceController.cs @@ -19,10 +19,9 @@ using System.ServiceModel; -namespace ProtonVPN.ProcessCommunication.Contracts.Controllers +namespace ProtonVPN.ProcessCommunication.Contracts.Controllers; + +[ServiceContract] +public interface IServiceController { - [ServiceContract] - public interface IServiceController - { - } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IUiController.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IUiController.cs new file mode 100644 index 000000000..65a78aa29 --- /dev/null +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IUiController.cs @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.ServiceModel; + +namespace ProtonVPN.ProcessCommunication.Contracts.Controllers; + +[ServiceContract] +public interface IUiController : IServiceController +{ + Task OpenWindow(string args); +} diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IUpdateController.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IUpdateController.cs index cfe63d51e..e1803ae88 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IUpdateController.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IUpdateController.cs @@ -20,13 +20,12 @@ using System.ServiceModel; using ProtonVPN.ProcessCommunication.Contracts.Entities.Update; -namespace ProtonVPN.ProcessCommunication.Contracts.Controllers +namespace ProtonVPN.ProcessCommunication.Contracts.Controllers; + +[ServiceContract] +public interface IUpdateController : IServiceController { - [ServiceContract] - public interface IUpdateController : IServiceController - { - Task CheckForUpdate(UpdateSettingsIpcEntity updateSettingsIpcEntity); + Task CheckForUpdate(UpdateSettingsIpcEntity updateSettingsIpcEntity, CancellationToken cancelToken); - Task StartAutoUpdate(); - } + Task StartAutoUpdate(StartAutoUpdateIpcEntity startAutoUpdateIpcEntity, CancellationToken cancelToken); } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IVpnController.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IVpnController.cs index 542318782..e296c5dc0 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IVpnController.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IVpnController.cs @@ -19,26 +19,21 @@ using System.ServiceModel; using ProtonVPN.ProcessCommunication.Contracts.Entities.Auth; -using ProtonVPN.ProcessCommunication.Contracts.Entities.Communication; using ProtonVPN.ProcessCommunication.Contracts.Entities.Settings; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.Contracts.Controllers -{ - [ServiceContract] - public interface IVpnController : IServiceController - { - Task RegisterStateConsumer(StateConsumerIpcEntity stateConsumer); - - Task Connect(ConnectionRequestIpcEntity connectionRequest); - Task Disconnect(DisconnectionRequestIpcEntity disconnectionRequest); - Task UpdateAuthCertificate(AuthCertificateIpcEntity certificate); - Task GetTrafficBytes(); - Task ApplySettings(MainSettingsIpcEntity settings); +namespace ProtonVPN.ProcessCommunication.Contracts.Controllers; - Task RepeatState(); - Task RepeatPortForwardingState(); +[ServiceContract] +public interface IVpnController : IServiceController +{ + Task Connect(ConnectionRequestIpcEntity connectionRequest, CancellationToken cancelToken); + Task Disconnect(DisconnectionRequestIpcEntity disconnectionRequest, CancellationToken cancelToken); + Task UpdateConnectionCertificate(ConnectionCertificateIpcEntity certificate, CancellationToken cancelToken); + Task GetTrafficBytes(CancellationToken cancelToken); + Task ApplySettings(MainSettingsIpcEntity settings, CancellationToken cancelToken); - Task RequestNetShieldStats(); - } + Task RepeatState(CancellationToken cancelToken); + Task RepeatPortForwardingState(CancellationToken cancelToken); + Task RequestNetShieldStats(CancellationToken cancelToken); } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Registration/IServiceServerPortRegister.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Auth/ConnectionCertificateIpcEntity.cs similarity index 67% rename from src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Registration/IServiceServerPortRegister.cs rename to src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Auth/ConnectionCertificateIpcEntity.cs index f98aafa16..14800c252 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Registration/IServiceServerPortRegister.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Auth/ConnectionCertificateIpcEntity.cs @@ -16,11 +16,16 @@ * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ +using System.Runtime.Serialization; -namespace ProtonVPN.ProcessCommunication.Contracts.Registration +namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Auth; + +[DataContract] +public class ConnectionCertificateIpcEntity { - public interface IServiceServerPortRegister : IServerPortRegister - { - Task ReadAsync(CancellationToken cancellationToken); - } + [DataMember(Order = 1, IsRequired = true)] + public string Pem { get; set; } + + [DataMember(Order = 2, IsRequired = true)] + public DateTime ExpirationDateUtc { get; set; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/NetShield/NetShieldStatisticIpcEntity.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/NetShield/NetShieldStatisticIpcEntity.cs index bda8e28f9..d52fab4a5 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/NetShield/NetShieldStatisticIpcEntity.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/NetShield/NetShieldStatisticIpcEntity.cs @@ -19,21 +19,20 @@ using System.Runtime.Serialization; -namespace ProtonVPN.ProcessCommunication.Contracts.Entities.NetShield +namespace ProtonVPN.ProcessCommunication.Contracts.Entities.NetShield; + +[DataContract] +public class NetShieldStatisticIpcEntity { - [DataContract] - public class NetShieldStatisticIpcEntity - { - [DataMember(Order = 1, IsRequired = true)] - public long NumOfMaliciousUrlsBlocked { get; set; } + [DataMember(Order = 1, IsRequired = true)] + public long NumOfMaliciousUrlsBlocked { get; set; } - [DataMember(Order = 2, IsRequired = true)] - public long NumOfAdvertisementUrlsBlocked { get; set; } + [DataMember(Order = 2, IsRequired = true)] + public long NumOfAdvertisementUrlsBlocked { get; set; } - [DataMember(Order = 3, IsRequired = true)] - public long NumOfTrackingUrlsBlocked { get; set; } + [DataMember(Order = 3, IsRequired = true)] + public long NumOfTrackingUrlsBlocked { get; set; } - [DataMember(Order = 4, IsRequired = true)] - public DateTime TimestampUtc { get; set; } - } + [DataMember(Order = 4, IsRequired = true)] + public DateTime TimestampUtc { get; set; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Settings/MainSettingsIpcEntity.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Settings/MainSettingsIpcEntity.cs index 5ada0590a..0b4b14b15 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Settings/MainSettingsIpcEntity.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Settings/MainSettingsIpcEntity.cs @@ -16,41 +16,47 @@ * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ + using System.Runtime.Serialization; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Settings +namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Settings; + +[DataContract] +public class MainSettingsIpcEntity { - [DataContract] - public class MainSettingsIpcEntity + [DataMember(Order = 1)] + public KillSwitchModeIpcEntity KillSwitchMode { get; set; } + + [DataMember(Order = 2)] + public SplitTunnelSettingsIpcEntity SplitTunnel { get; set; } + + [DataMember(Order = 3)] + public int NetShieldMode { get; set; } + + [DataMember(Order = 4)] + public bool ModerateNat { get; set; } + + [DataMember(Order = 5)] + public bool SplitTcp { get; set; } + + [DataMember(Order = 6)] + public bool Ipv6LeakProtection { get; set; } + + [DataMember(Order = 7)] + public bool IsShareCrashReportsEnabled { get; set; } + + [DataMember(Order = 8)] + public VpnProtocolIpcEntity VpnProtocol { get; set; } + + [DataMember(Order = 9)] + public OpenVpnAdapterIpcEntity OpenVpnAdapter { get; set; } + + [DataMember(Order = 10)] + public bool PortForwarding { get; set; } + + public MainSettingsIpcEntity() { - [DataMember(Order = 1)] - public KillSwitchModeIpcEntity KillSwitchMode { get; set; } - [DataMember(Order = 2)] - public SplitTunnelSettingsIpcEntity SplitTunnel { get; set; } - - [DataMember(Order = 3)] - public int NetShieldMode { get; set; } - - [DataMember(Order = 4)] - public bool ModerateNat { get; set; } - - [DataMember(Order = 5)] - public bool? SplitTcp { get; set; } - [DataMember(Order = 6)] - public bool? AllowNonStandardPorts { get; set; } - [DataMember(Order = 7)] - public bool Ipv6LeakProtection { get; set; } - [DataMember(Order = 8)] - public VpnProtocolIpcEntity VpnProtocol { get; set; } - [DataMember(Order = 9)] - public OpenVpnAdapterIpcEntity OpenVpnAdapter { get; set; } - [DataMember(Order = 10)] - public bool PortForwarding { get; set; } - - public MainSettingsIpcEntity() - { - SplitTunnel = new(); - } + SplitTunnel = new(); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Update/ReleaseIpcEntity.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Update/ReleaseIpcEntity.cs index 55a8c58d1..bd88b15f8 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Update/ReleaseIpcEntity.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Update/ReleaseIpcEntity.cs @@ -34,6 +34,9 @@ public class ReleaseIpcEntity public bool New { get; set; } [DataMember(Order = 4)] + public string ReleaseDate { get; set; } + + [DataMember(Order = 5)] public string[] ChangeLog { get; set; } } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Auth/AuthCertificateIpcEntity.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Update/StartAutoUpdateIpcEntity.cs similarity index 81% rename from src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Auth/AuthCertificateIpcEntity.cs rename to src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Update/StartAutoUpdateIpcEntity.cs index 8d04342e5..37f35c146 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Auth/AuthCertificateIpcEntity.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Update/StartAutoUpdateIpcEntity.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Proton AG + * Copyright (c) 2024 Proton AG * * This file is part of ProtonVPN. * @@ -16,14 +16,15 @@ * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ + using System.Runtime.Serialization; -namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Auth +namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Update { [DataContract] - public class AuthCertificateIpcEntity + public class StartAutoUpdateIpcEntity { [DataMember(Order = 1, IsRequired = true)] - public string Certificate { get; set; } + public Guid RetryId { get; set; } } -} \ No newline at end of file +} diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/ConnectionRequestIpcEntity.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/ConnectionRequestIpcEntity.cs index dae0d291c..e86fe8a55 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/ConnectionRequestIpcEntity.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/ConnectionRequestIpcEntity.cs @@ -25,18 +25,21 @@ namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn public class ConnectionRequestIpcEntity { [DataMember(Order = 1, IsRequired = true)] - public VpnServerIpcEntity[] Servers { get; set; } + public Guid RetryId { get; set; } [DataMember(Order = 2, IsRequired = true)] - public VpnProtocolIpcEntity Protocol { get; set; } + public VpnServerIpcEntity[] Servers { get; set; } [DataMember(Order = 3, IsRequired = true)] - public VpnConfigIpcEntity Config { get; set; } + public VpnProtocolIpcEntity Protocol { get; set; } [DataMember(Order = 4, IsRequired = true)] - public VpnCredentialsIpcEntity Credentials { get; set; } + public VpnConfigIpcEntity Config { get; set; } [DataMember(Order = 5, IsRequired = true)] + public VpnCredentialsIpcEntity Credentials { get; set; } + + [DataMember(Order = 6, IsRequired = true)] public MainSettingsIpcEntity Settings { get; set; } public ConnectionRequestIpcEntity() diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/DisconnectionRequestIpcEntity.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/DisconnectionRequestIpcEntity.cs index 4ff3281b9..84473cb71 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/DisconnectionRequestIpcEntity.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/DisconnectionRequestIpcEntity.cs @@ -25,9 +25,12 @@ namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn public class DisconnectionRequestIpcEntity { [DataMember(Order = 1, IsRequired = true)] - public MainSettingsIpcEntity Settings { get; set; } + public Guid RetryId { get; set; } [DataMember(Order = 2, IsRequired = true)] + public MainSettingsIpcEntity Settings { get; set; } + + [DataMember(Order = 3, IsRequired = true)] public VpnErrorTypeIpcEntity ErrorType { get; set; } diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/TrafficBytesIpcEntity.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/TrafficBytesIpcEntity.cs index 1231b471c..c66d54479 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/TrafficBytesIpcEntity.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/TrafficBytesIpcEntity.cs @@ -24,9 +24,9 @@ namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn public class TrafficBytesIpcEntity { [DataMember(Order = 1, IsRequired = true)] - public double BytesIn { get; set; } + public ulong BytesIn { get; set; } [DataMember(Order = 2, IsRequired = true)] - public double BytesOut { get; set; } + public ulong BytesOut { get; set; } } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnConfigIpcEntity.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnConfigIpcEntity.cs index 842cbb910..8d30d5a7a 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnConfigIpcEntity.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnConfigIpcEntity.cs @@ -48,12 +48,9 @@ public class VpnConfigIpcEntity public bool ModerateNat { get; set; } [DataMember(Order = 9, IsRequired = true)] - public bool? SplitTcp { get; set; } + public bool SplitTcp { get; set; } [DataMember(Order = 10, IsRequired = true)] - public bool? AllowNonStandardPorts { get; set; } - - [DataMember(Order = 11, IsRequired = true)] public bool PortForwarding { get; set; } public VpnConfigIpcEntity() diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnCredentialsIpcEntity.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnCredentialsIpcEntity.cs index 68b8601af..2847ed706 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnCredentialsIpcEntity.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnCredentialsIpcEntity.cs @@ -18,23 +18,23 @@ */ using System.Runtime.Serialization; +using ProtonVPN.ProcessCommunication.Contracts.Entities.Auth; using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; -namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn +namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; + +[DataContract] +public class VpnCredentialsIpcEntity { - [DataContract] - public class VpnCredentialsIpcEntity - { - [DataMember(Order = 1)] - public string Username { get; set; } + [DataMember(Order = 1)] + public string Username { get; set; } - [DataMember(Order = 2)] - public string Password { get; set; } + [DataMember(Order = 2)] + public string Password { get; set; } - [DataMember(Order = 3)] - public string ClientCertPem { get; set; } + [DataMember(Order = 3)] + public ConnectionCertificateIpcEntity Certificate { get; set; } - [DataMember(Order = 4)] - public AsymmetricKeyPairIpcEntity ClientKeyPair { get; set; } - } + [DataMember(Order = 4)] + public AsymmetricKeyPairIpcEntity ClientKeyPair { get; set; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnErrorTypeIpcEntity.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnErrorTypeIpcEntity.cs index d333bf79e..2c00f0121 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnErrorTypeIpcEntity.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnErrorTypeIpcEntity.cs @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ + using System.Runtime.Serialization; namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnProtocolIpcEntity.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnProtocolIpcEntity.cs index 374fcb816..91f3902ab 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnProtocolIpcEntity.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnProtocolIpcEntity.cs @@ -18,27 +18,26 @@ */ using System.Runtime.Serialization; -namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn +namespace ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; + +[DataContract] +public enum VpnProtocolIpcEntity { - [DataContract] - public enum VpnProtocolIpcEntity - { - [EnumMember] - Smart, + [EnumMember] + Smart, - [EnumMember] - OpenVpnTcp, + [EnumMember] + OpenVpnTcp, - [EnumMember] - OpenVpnUdp, + [EnumMember] + OpenVpnUdp, - [EnumMember] - WireGuardUdp, + [EnumMember] + WireGuardUdp, - [EnumMember] - WireGuardTcp, + [EnumMember] + WireGuardTcp, - [EnumMember] - WireGuardTls, - } + [EnumMember] + WireGuardTls, } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IAppGrpcClient.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IGrpcClient.cs similarity index 64% rename from src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IAppGrpcClient.cs rename to src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IGrpcClient.cs index cda96e5b2..117d2d86a 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IAppGrpcClient.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IGrpcClient.cs @@ -18,15 +18,19 @@ */ using ProtonVPN.ProcessCommunication.Contracts.Controllers; -namespace ProtonVPN.ProcessCommunication.Contracts +namespace ProtonVPN.ProcessCommunication.Contracts; + +public interface IGrpcClient { - public interface IAppGrpcClient - { - IVpnController? VpnController { get; } - IUpdateController? UpdateController { get; } + IClientController ClientController { get; } + IUpdateController UpdateController { get; } + IVpnController VpnController { get; } + IUiController UiController { get; } + + void Stop(); + void CreateIfPipeNameChanged(); + void Create(); - Task CreateAsync(); - Task RecreateAsync(); - Task GetServiceControllerOrThrowAsync(TimeSpan timeout) where Controller : IServiceController; - } + Task GetServiceControllerOrThrowAsync(TimeSpan timeout) + where T : IServiceController; } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IGrpcServer.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IGrpcServer.cs index ed2257794..25d47c68e 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IGrpcServer.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IGrpcServer.cs @@ -17,15 +17,10 @@ * along with ProtonVPN. If not, see . */ -namespace ProtonVPN.ProcessCommunication.Contracts -{ - public interface IGrpcServer - { - int? Port { get; } - event EventHandler? OnStart; +namespace ProtonVPN.ProcessCommunication.Contracts; - void CreateAndStart(); - Task ShutdownAsync(); - Task KillAsync(); - } +public interface IGrpcServer +{ + void CreateAndStart(); + Task StopAsync(); } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/ProtonVPN.ProcessCommunication.Contracts.csproj b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/ProtonVPN.ProcessCommunication.Contracts.csproj index c75641b68..cfce7a922 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/ProtonVPN.ProcessCommunication.Contracts.csproj +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/ProtonVPN.ProcessCommunication.Contracts.csproj @@ -1,24 +1,23 @@ - - - - net6.0-windows - enable - ..\..\bin - false - Library - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - - + + + net8.0-windows + enable + ..\..\bin + false + Library + false + AnyCPU;ARM64 + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Common/EnumMapperTestBase.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Common/EnumMapperTestBase.cs index 59651e274..2e2f325a6 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Common/EnumMapperTestBase.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Common/EnumMapperTestBase.cs @@ -20,78 +20,77 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using ProtonVPN.EntityMapping.Contracts; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Common +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Common; + +[TestClass] +public abstract class EnumMapperTestBase + where TLeft : struct, Enum + where TRight : struct, Enum { - [TestClass] - public abstract class EnumMapperTestBase - where TLeft : struct, Enum - where TRight : struct, Enum + private IMapper _mapper; + + [TestInitialize] + public void Initialize() { - private IMapper _mapper; + _mapper = CreateMapper(); + } - [TestInitialize] - public void Initialize() - { - _mapper = CreateMapper(); - } + protected abstract IMapper CreateMapper(); - protected abstract IMapper CreateMapper(); + [TestCleanup] + public void Cleanup() + { + _mapper = null; + } - [TestCleanup] - public void Cleanup() - { - _mapper = null; - } + [TestMethod] + public void TestEnumsHaveEqualUnderlyingType() + { + Assert.AreEqual( + Enum.GetUnderlyingType(typeof(TLeft)), + Enum.GetUnderlyingType(typeof(TRight))); + } - [TestMethod] - public void TestEnumsHaveEqualUnderlyingType() - { - Assert.AreEqual( - Enum.GetUnderlyingType(typeof(TLeft)), - Enum.GetUnderlyingType(typeof(TRight))); - } + [TestMethod] + public void TestEnumsHaveEqualCount() + { + int count = Enum.GetValues().Count(); + Assert.AreEqual(count, Enum.GetValues().Count()); + Assert.AreEqual(count, Enum.GetNames().Count()); + Assert.AreEqual(count, Enum.GetNames().Count()); + } - [TestMethod] - public void TestEnumsHaveEqualCount() - { - int count = Enum.GetValues().Count(); - Assert.AreEqual(count, Enum.GetValues().Count()); - Assert.AreEqual(count, Enum.GetNames().Count()); - Assert.AreEqual(count, Enum.GetNames().Count()); - } + [TestMethod] + public void TestEnumsHaveEqualValues() + { + List leftEntities = Enum.GetValues().ToList(); + List rightEntities = Enum.GetValues().ToList(); - [TestMethod] - public void TestEnumsHaveEqualValues() + for (int i = 0; i < leftEntities.Count; i++) { - List leftEntities = Enum.GetValues().ToList(); - List rightEntities = Enum.GetValues().ToList(); - - for (int i = 0; i < leftEntities.Count; i++) - { - Assert.AreEqual( - GetValueAsUnderlyingType(leftEntities[i]), - GetValueAsUnderlyingType(rightEntities[i])); - Assert.AreEqual(rightEntities[i], _mapper.Map(leftEntities[i])); - Assert.AreEqual(leftEntities[i], _mapper.Map(rightEntities[i])); - } + Assert.AreEqual( + GetValueAsUnderlyingType(leftEntities[i]), + GetValueAsUnderlyingType(rightEntities[i])); + Assert.AreEqual(rightEntities[i], _mapper.Map(leftEntities[i])); + Assert.AreEqual(leftEntities[i], _mapper.Map(rightEntities[i])); } + } - private object GetValueAsUnderlyingType(T value) - where T : struct, Enum - { - return Convert.ChangeType(value, value.GetTypeCode()); - } + private object GetValueAsUnderlyingType(T value) + where T : struct, Enum + { + return Convert.ChangeType(value, value.GetTypeCode()); + } - [TestMethod] - public void TestEnumsHaveEqualNames() - { - List leftEntitynames = Enum.GetNames().ToList(); - List rightEntityNames = Enum.GetNames().ToList(); + [TestMethod] + public void TestEnumsHaveEqualNames() + { + List leftEntitynames = Enum.GetNames().ToList(); + List rightEntityNames = Enum.GetNames().ToList(); - for (int i = 0; i < leftEntitynames.Count; i++) - { - Assert.AreEqual(leftEntitynames[i], rightEntityNames[i]); - } + for (int i = 0; i < leftEntitynames.Count; i++) + { + Assert.AreEqual(leftEntitynames[i], rightEntityNames[i]); } } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/AsymmetricKeyPairMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/AsymmetricKeyPairMapperTest.cs index 8f732a789..20a570b9c 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/AsymmetricKeyPairMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/AsymmetricKeyPairMapperTest.cs @@ -24,113 +24,112 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; using ProtonVPN.ProcessCommunication.EntityMapping.Crypto; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Crypto +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Crypto; + +[TestClass] +public class AsymmetricKeyPairMapperTest { - [TestClass] - public class AsymmetricKeyPairMapperTest - { - private IEntityMapper _entityMapper; - private AsymmetricKeyPairMapper _mapper; + private IEntityMapper _entityMapper; + private AsymmetricKeyPairMapper _mapper; - private SecretKeyIpcEntity _expectedSecretKeyIpcEntity; - private PublicKeyIpcEntity _expectedPublicKeyIpcEntity; - private SecretKey _expectedSecretKey; - private PublicKey _expectedPublicKey; + private SecretKeyIpcEntity _expectedSecretKeyIpcEntity; + private PublicKeyIpcEntity _expectedPublicKeyIpcEntity; + private SecretKey _expectedSecretKey; + private PublicKey _expectedPublicKey; - [TestInitialize] - public void Initialize() - { - _entityMapper = Substitute.For(); - _mapper = new AsymmetricKeyPairMapper(_entityMapper); - - _expectedSecretKeyIpcEntity = new SecretKeyIpcEntity(); - _entityMapper.Map(Arg.Any()).Returns(_expectedSecretKeyIpcEntity); - _expectedPublicKeyIpcEntity = new PublicKeyIpcEntity(); - _entityMapper.Map(Arg.Any()).Returns(_expectedPublicKeyIpcEntity); - - _expectedSecretKey = new SecretKey("PVPN", KeyAlgorithm.Unknown); - _entityMapper.Map(Arg.Any()).Returns(_expectedSecretKey); - _expectedPublicKey = new PublicKey("PVPN", KeyAlgorithm.Unknown); - _entityMapper.Map(Arg.Any()).Returns(_expectedPublicKey); - } - - [TestCleanup] - public void Cleanup() - { - _entityMapper = null; - _mapper = null; - } - - [TestMethod] - public void TestMapLeftToRight_WhenNull() - { - AsymmetricKeyPair entityToMap = null; + [TestInitialize] + public void Initialize() + { + _entityMapper = Substitute.For(); + _mapper = new AsymmetricKeyPairMapper(_entityMapper); + + _expectedSecretKeyIpcEntity = new SecretKeyIpcEntity(); + _entityMapper.Map(Arg.Any()).Returns(_expectedSecretKeyIpcEntity); + _expectedPublicKeyIpcEntity = new PublicKeyIpcEntity(); + _entityMapper.Map(Arg.Any()).Returns(_expectedPublicKeyIpcEntity); + + _expectedSecretKey = new SecretKey("PVPN", KeyAlgorithm.Unknown); + _entityMapper.Map(Arg.Any()).Returns(_expectedSecretKey); + _expectedPublicKey = new PublicKey("PVPN", KeyAlgorithm.Unknown); + _entityMapper.Map(Arg.Any()).Returns(_expectedPublicKey); + } - AsymmetricKeyPairIpcEntity result = _mapper.Map(entityToMap); + [TestCleanup] + public void Cleanup() + { + _entityMapper = null; + _mapper = null; + } - Assert.IsNull(result); - } + [TestMethod] + public void TestMapLeftToRight_WhenNull() + { + AsymmetricKeyPair entityToMap = null; - [TestMethod] - public void TestMapLeftToRight() - { - AsymmetricKeyPair entityToMap = new( - new SecretKey("PVPN", KeyAlgorithm.Unknown), - new PublicKey("PVPN", KeyAlgorithm.Unknown)); + AsymmetricKeyPairIpcEntity result = _mapper.Map(entityToMap); - AsymmetricKeyPairIpcEntity result = _mapper.Map(entityToMap); + Assert.IsNull(result); + } - Assert.IsNotNull(result); - Assert.AreEqual(_expectedSecretKeyIpcEntity, result.SecretKey); - Assert.AreEqual(_expectedPublicKeyIpcEntity, result.PublicKey); - } + [TestMethod] + public void TestMapLeftToRight() + { + AsymmetricKeyPair entityToMap = new( + new SecretKey("PVPN", KeyAlgorithm.Unknown), + new PublicKey("PVPN", KeyAlgorithm.Unknown)); - [TestMethod] - public void TestMapRightToLeft_WhenNull() - { - TestMapRightToLeft(null, null); - } + AsymmetricKeyPairIpcEntity result = _mapper.Map(entityToMap); - private void TestMapRightToLeft(AsymmetricKeyPair expectedResult, AsymmetricKeyPairIpcEntity entityToMap) - { - AsymmetricKeyPair result = _mapper.Map(entityToMap); + Assert.IsNotNull(result); + Assert.AreEqual(_expectedSecretKeyIpcEntity, result.SecretKey); + Assert.AreEqual(_expectedPublicKeyIpcEntity, result.PublicKey); + } - Assert.AreEqual(expectedResult, result); - } + [TestMethod] + public void TestMapRightToLeft_WhenNull() + { + TestMapRightToLeft(null, null); + } - [TestMethod] - public void TestMapRightToLeft_WhenInnerPropertiesAreNull() - { - TestMapRightToLeft(null, new AsymmetricKeyPairIpcEntity()); - } + [TestMethod] + public void TestMapRightToLeft_WhenInnerPropertiesAreNull() + { + TestMapRightToLeft(null, new AsymmetricKeyPairIpcEntity()); + } - [TestMethod] - public void TestMapRightToLeft() + [TestMethod] + public void TestMapRightToLeft() + { + SecretKey secretKey = new("PVPN", KeyAlgorithm.Unknown); + AsymmetricKeyPairIpcEntity entityToMap = new() { - SecretKey secretKey = new SecretKey("PVPN", KeyAlgorithm.Unknown); - AsymmetricKeyPairIpcEntity entityToMap = new() + SecretKey = new SecretKeyIpcEntity() { - SecretKey = new SecretKeyIpcEntity() - { - Bytes = secretKey.Bytes, - Base64 = secretKey.Base64, - Algorithm = (KeyAlgorithmIpcEntity)((int)secretKey.Algorithm), - Pem = secretKey.Pem, - }, - PublicKey = new PublicKeyIpcEntity() - { - Bytes = secretKey.Bytes, - Base64 = secretKey.Base64, - Algorithm = (KeyAlgorithmIpcEntity)((int)secretKey.Algorithm), - Pem = secretKey.Pem, - } - }; - - AsymmetricKeyPair result = _mapper.Map(entityToMap); - - Assert.IsNotNull(result); - Assert.AreEqual(_expectedSecretKey, result.SecretKey); - Assert.AreEqual(_expectedPublicKey, result.PublicKey); - } + Bytes = secretKey.Bytes, + Base64 = secretKey.Base64, + Algorithm = (KeyAlgorithmIpcEntity)(int)secretKey.Algorithm, + Pem = secretKey.Pem, + }, + PublicKey = new PublicKeyIpcEntity() + { + Bytes = secretKey.Bytes, + Base64 = secretKey.Base64, + Algorithm = (KeyAlgorithmIpcEntity)(int)secretKey.Algorithm, + Pem = secretKey.Pem, + } + }; + + AsymmetricKeyPair result = _mapper.Map(entityToMap); + + Assert.IsNotNull(result); + Assert.AreEqual(_expectedSecretKey, result.SecretKey); + Assert.AreEqual(_expectedPublicKey, result.PublicKey); + } + + private void TestMapRightToLeft(AsymmetricKeyPair expectedResult, AsymmetricKeyPairIpcEntity entityToMap) + { + AsymmetricKeyPair result = _mapper.Map(entityToMap); + + Assert.AreEqual(expectedResult, result); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/KeyMapperTestBase.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/KeyMapperTestBase.cs index b7080e431..eb31a9515 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/KeyMapperTestBase.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/KeyMapperTestBase.cs @@ -22,141 +22,140 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Crypto +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Crypto; + +[TestClass] +public abstract class KeyMapperTestBase + where TKey : Key + where TKeyIpcEntity : KeyIpcEntity, new() { - [TestClass] - public abstract class KeyMapperTestBase - where TKey : Key - where TKeyIpcEntity : KeyIpcEntity, new() + private IMapper _mapper; + + [TestInitialize] + public void Initialize() { - private IMapper _mapper; + _mapper = CreateKeyMapper(); + } - [TestInitialize] - public void Initialize() - { - _mapper = CreateKeyMapper(); - } + [TestCleanup] + public void Cleanup() + { + _mapper = null; + } - protected abstract IMapper CreateKeyMapper(); + [TestMethod] + public void TestMapLeftToRight_WhenNull() + { + TKey entityToMap = null; - [TestCleanup] - public void Cleanup() - { - _mapper = null; - } + TKeyIpcEntity result = _mapper.Map(entityToMap); - [TestMethod] - public void TestMapLeftToRight_WhenNull() - { - TKey entityToMap = null; + Assert.AreEqual(null, result); + } - TKeyIpcEntity result = _mapper.Map(entityToMap); + [TestMethod] + public void TestMapLeftToRight() + { + TKey entityToMap = CreateKey("PVPN", KeyAlgorithm.Ed25519); - Assert.AreEqual(null, result); - } + TKeyIpcEntity result = _mapper.Map(entityToMap); - [TestMethod] - public void TestMapLeftToRight() - { - TKey entityToMap = CreateKey("PVPN", KeyAlgorithm.Ed25519); + Assert.IsNotNull(result); + Assert.AreEqual(entityToMap.Bytes, result.Bytes); + Assert.AreEqual(entityToMap.Base64, result.Base64); + Assert.AreEqual((int)entityToMap.Algorithm, (int)result.Algorithm); + Assert.AreEqual(entityToMap.Pem, result.Pem); + } - TKeyIpcEntity result = _mapper.Map(entityToMap); + [TestMethod] + public void TestMapRightToLeft_WhenNull() + { + TKeyIpcEntity entityToMap = null; - Assert.IsNotNull(result); - Assert.AreEqual(entityToMap.Bytes, result.Bytes); - Assert.AreEqual(entityToMap.Base64, result.Base64); - Assert.AreEqual((int)entityToMap.Algorithm, (int)result.Algorithm); - Assert.AreEqual(entityToMap.Pem, result.Pem); - } + TKey result = _mapper.Map(entityToMap); - protected abstract TKey CreateKey(string base64, KeyAlgorithm algorithm); + Assert.AreEqual(null, result); + } - [TestMethod] - public void TestMapRightToLeft_WhenNull() + [TestMethod] + public void TestMapRightToLeft() + { + string base64 = "PVPN"; + byte[] bytes = Convert.FromBase64String(base64); + TKeyIpcEntity entityToMap = new() { - TKeyIpcEntity entityToMap = null; + Bytes = bytes, + Base64 = base64, + Algorithm = KeyAlgorithmIpcEntity.X25519, + Pem = CreateExpectedPem(base64) + }; - TKey result = _mapper.Map(entityToMap); + TKey result = _mapper.Map(entityToMap); - Assert.AreEqual(null, result); + Assert.IsNotNull(result); + Assert.AreEqual(entityToMap.Bytes.Count(), result.Bytes.Count()); + for (int i = 0; i < entityToMap.Bytes.Length; i++) + { + Assert.AreEqual(entityToMap.Bytes[i], result.Bytes[i]); } + Assert.AreEqual(entityToMap.Base64, result.Base64); + Assert.AreEqual((int)entityToMap.Algorithm, (int)result.Algorithm); + Assert.AreEqual(entityToMap.Pem, result.Pem); + } - [TestMethod] - public void TestMapRightToLeft() + [TestMethod] + public void TestMapRightToLeft_WhenBytesAreNull() + { + string base64 = "PVPN"; + byte[] bytes = Convert.FromBase64String(base64); + TKeyIpcEntity entityToMap = new() { - string base64 = "PVPN"; - byte[] bytes = Convert.FromBase64String(base64); - TKeyIpcEntity entityToMap = new() - { - Bytes = bytes, - Base64 = base64, - Algorithm = KeyAlgorithmIpcEntity.X25519, - Pem = CreateExpectedPem(base64) - }; - - TKey result = _mapper.Map(entityToMap); - - Assert.IsNotNull(result); - Assert.AreEqual(entityToMap.Bytes.Count(), result.Bytes.Count()); - for (int i = 0; i < entityToMap.Bytes.Length; i++) - { - Assert.AreEqual(entityToMap.Bytes[i], result.Bytes[i]); - } - Assert.AreEqual(entityToMap.Base64, result.Base64); - Assert.AreEqual((int)entityToMap.Algorithm, (int)result.Algorithm); - Assert.AreEqual(entityToMap.Pem, result.Pem); - } + Base64 = base64, + Algorithm = KeyAlgorithmIpcEntity.X25519, + Pem = CreateExpectedPem(base64) + }; - protected abstract string CreateExpectedPem(string base64); + TKey result = _mapper.Map(entityToMap); - [TestMethod] - public void TestMapRightToLeft_WhenBytesAreNull() + Assert.IsNotNull(result); + Assert.AreEqual(bytes.Count(), result.Bytes.Count()); + for (int i = 0; i < bytes.Length; i++) { - string base64 = "PVPN"; - byte[] bytes = Convert.FromBase64String(base64); - TKeyIpcEntity entityToMap = new() - { - Base64 = base64, - Algorithm = KeyAlgorithmIpcEntity.X25519, - Pem = CreateExpectedPem(base64) - }; - - TKey result = _mapper.Map(entityToMap); - - Assert.IsNotNull(result); - Assert.AreEqual(bytes.Count(), result.Bytes.Count()); - for (int i = 0; i < bytes.Length; i++) - { - Assert.AreEqual(bytes[i], result.Bytes[i]); - } - Assert.AreEqual(entityToMap.Base64, result.Base64); - Assert.AreEqual((int)entityToMap.Algorithm, (int)result.Algorithm); - Assert.AreEqual(entityToMap.Pem, result.Pem); + Assert.AreEqual(bytes[i], result.Bytes[i]); } + Assert.AreEqual(entityToMap.Base64, result.Base64); + Assert.AreEqual((int)entityToMap.Algorithm, (int)result.Algorithm); + Assert.AreEqual(entityToMap.Pem, result.Pem); + } + + [TestMethod] + public void TestMapRightToLeft_WhenBase64IsNull() + { + string base64 = "PVPN"; + byte[] bytes = Convert.FromBase64String(base64); + TKeyIpcEntity entityToMap = new() + { + Bytes = bytes, + Algorithm = KeyAlgorithmIpcEntity.X25519, + Pem = CreateExpectedPem(base64) + }; - [TestMethod] - public void TestMapRightToLeft_WhenBase64IsNull() + TKey result = _mapper.Map(entityToMap); + + Assert.IsNotNull(result); + Assert.AreEqual(entityToMap.Bytes.Count(), result.Bytes.Count()); + for (int i = 0; i < entityToMap.Bytes.Length; i++) { - string base64 = "PVPN"; - byte[] bytes = Convert.FromBase64String(base64); - TKeyIpcEntity entityToMap = new() - { - Bytes = bytes, - Algorithm = KeyAlgorithmIpcEntity.X25519, - Pem = CreateExpectedPem(base64) - }; - - TKey result = _mapper.Map(entityToMap); - - Assert.IsNotNull(result); - Assert.AreEqual(entityToMap.Bytes.Count(), result.Bytes.Count()); - for (int i = 0; i < entityToMap.Bytes.Length; i++) - { - Assert.AreEqual(entityToMap.Bytes[i], result.Bytes[i]); - } - Assert.AreEqual(base64, result.Base64); - Assert.AreEqual((int)entityToMap.Algorithm, (int)result.Algorithm); - Assert.AreEqual(entityToMap.Pem, result.Pem); + Assert.AreEqual(entityToMap.Bytes[i], result.Bytes[i]); } + Assert.AreEqual(base64, result.Base64); + Assert.AreEqual((int)entityToMap.Algorithm, (int)result.Algorithm); + Assert.AreEqual(entityToMap.Pem, result.Pem); } + + protected abstract IMapper CreateKeyMapper(); + + protected abstract TKey CreateKey(string base64, KeyAlgorithm algorithm); + + protected abstract string CreateExpectedPem(string base64); } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/PublicKeyMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/PublicKeyMapperTest.cs index 5f406ab34..680d7e8a0 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/PublicKeyMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/PublicKeyMapperTest.cs @@ -23,24 +23,23 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; using ProtonVPN.ProcessCommunication.EntityMapping.Crypto; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Crypto +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Crypto; + +[TestClass] +public class PublicKeyMapperTest : KeyMapperTestBase { - [TestClass] - public class PublicKeyMapperTest : KeyMapperTestBase + protected override IMapper CreateKeyMapper() { - protected override IMapper CreateKeyMapper() - { - return new PublicKeyMapper(); - } + return new PublicKeyMapper(); + } - protected override PublicKey CreateKey(string base64, KeyAlgorithm algorithm) - { - return new(base64, algorithm); - } + protected override PublicKey CreateKey(string base64, KeyAlgorithm algorithm) + { + return new(base64, algorithm); + } - protected override string CreateExpectedPem(string base64) - { - return $"-----BEGIN PUBLIC KEY-----\r\n{base64}\r\n-----END PUBLIC KEY-----"; - } + protected override string CreateExpectedPem(string base64) + { + return $"-----BEGIN PUBLIC KEY-----\r\n{base64}\r\n-----END PUBLIC KEY-----"; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/SecretKeyMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/SecretKeyMapperTest.cs index 511304182..3ab87fb2b 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/SecretKeyMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/SecretKeyMapperTest.cs @@ -23,24 +23,23 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; using ProtonVPN.ProcessCommunication.EntityMapping.Crypto; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Crypto +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Crypto; + +[TestClass] +public class SecretKeyMapperTest : KeyMapperTestBase { - [TestClass] - public class SecretKeyMapperTest : KeyMapperTestBase + protected override IMapper CreateKeyMapper() { - protected override IMapper CreateKeyMapper() - { - return new SecretKeyMapper(); - } + return new SecretKeyMapper(); + } - protected override SecretKey CreateKey(string base64, KeyAlgorithm algorithm) - { - return new(base64, algorithm); - } + protected override SecretKey CreateKey(string base64, KeyAlgorithm algorithm) + { + return new(base64, algorithm); + } - protected override string CreateExpectedPem(string base64) - { - return $"-----BEGIN PRIVATE KEY-----\r\n{base64}\r\n-----END PRIVATE KEY-----"; - } + protected override string CreateExpectedPem(string base64) + { + return $"-----BEGIN PRIVATE KEY-----\r\n{base64}\r\n-----END PRIVATE KEY-----"; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/ServerPublicKeyMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/ServerPublicKeyMapperTest.cs index 5a284cb67..742fd6968 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/ServerPublicKeyMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Crypto/ServerPublicKeyMapperTest.cs @@ -23,24 +23,23 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; using ProtonVPN.ProcessCommunication.EntityMapping.Crypto; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Crypto +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Crypto; + +[TestClass] +public class ServerPublicKeyMapperTest : KeyMapperTestBase { - [TestClass] - public class ServerPublicKeyMapperTest : KeyMapperTestBase + protected override IMapper CreateKeyMapper() { - protected override IMapper CreateKeyMapper() - { - return new ServerPublicKeyMapper(); - } + return new ServerPublicKeyMapper(); + } - protected override PublicKey CreateKey(string base64, KeyAlgorithm algorithm) - { - return new(base64, algorithm); - } + protected override PublicKey CreateKey(string base64, KeyAlgorithm algorithm) + { + return new(base64, algorithm); + } - protected override string CreateExpectedPem(string base64) - { - return $"-----BEGIN PUBLIC KEY-----\r\n{base64}\r\n-----END PUBLIC KEY-----"; - } + protected override string CreateExpectedPem(string base64) + { + return $"-----BEGIN PUBLIC KEY-----\r\n{base64}\r\n-----END PUBLIC KEY-----"; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/GuestHole/GuestHoleServerMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/GuestHole/GuestHoleServerMapperTest.cs new file mode 100644 index 000000000..5a5aabdb0 --- /dev/null +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/GuestHole/GuestHoleServerMapperTest.cs @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using ProtonVPN.Core.Servers.Contracts; +using ProtonVPN.EntityMapping.Contracts; +using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; +using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; +using ProtonVPN.ProcessCommunication.EntityMapping.GuestHole; + +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.GuestHole; + +[TestClass] +public class GuestHoleServerMapperTest +{ + private IMapper _mapper; + + [TestInitialize] + public void Initialize() + { + _mapper = new GuestHoleServerMapper(); + } + + [TestCleanup] + public void Cleanup() + { + _mapper = null; + } + + [TestMethod] + public void TestMapLeftToRight() + { + GuestHoleServerContract entity = new() + { + Host = "protonvpn.com", + Ip = "192.168.0.0", + Label = "1", + Signature = "sdh2uS26AfSADioe5w6p6S5D2H5fkdY8p9Jfh1F1sdo2a5JfGHroGeunf6K9G4H1c1K/2u3G3oGKdso==" + }; + + VpnServerIpcEntity result = _mapper.Map(entity); + + Assert.IsNotNull(result); + Assert.AreEqual(entity.Host, result.Name); + Assert.AreEqual(entity.Ip, result.Ip); + Assert.AreEqual(entity.Label, result.Label); + Assert.AreEqual(entity.Signature, result.Signature); + Assert.IsNull(result.X25519PublicKey); + } + + [TestMethod] + public void TestMapLeftToRight_WhenNull() + { + GuestHoleServerContract entity = null; + + VpnServerIpcEntity result = _mapper.Map(entity); + + Assert.IsNull(result); + } + + [TestMethod] + public void TestMapRightToLeft() + { + VpnServerIpcEntity entity = new() + { + Name = "protonvpn.com", + Ip = "192.168.0.0", + Label = "1", + Signature = "sdh2uS26AfSADioe5w6p6S5D2H5fkdY8p9Jfh1F1sdo2a5JfGHroGeunf6K9G4H1c1K/2u3G3oGKdso==", + X25519PublicKey = new ServerPublicKeyIpcEntity() + }; + + GuestHoleServerContract result = _mapper.Map(entity); + + Assert.IsNotNull(result); + Assert.AreEqual(entity.Name, result.Host); + Assert.AreEqual(entity.Ip, result.Ip); + Assert.AreEqual(entity.Label, result.Label); + Assert.AreEqual(entity.Signature, result.Signature); + } + + [TestMethod] + public void TestMapRightToLeft_WhenNull() + { + VpnServerIpcEntity entity = null; + + GuestHoleServerContract result = _mapper.Map(entity); + + Assert.IsNull(result); + } +} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/NetShield/NetShieldStatisticMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/NetShield/NetShieldStatisticMapperTest.cs index 2be3926dd..b2fb13d8f 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/NetShield/NetShieldStatisticMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/NetShield/NetShieldStatisticMapperTest.cs @@ -22,85 +22,84 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.NetShield; using ProtonVPN.ProcessCommunication.EntityMapping.NetShield; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.NetShield +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.NetShield; + +[TestClass] +public class NetShieldStatisticMapperTest { - [TestClass] - public class NetShieldStatisticMapperTest - { - private NetShieldStatisticMapper _mapper; + private NetShieldStatisticMapper _mapper; - [TestInitialize] - public void Initialize() - { - _mapper = new(); - } + [TestInitialize] + public void Initialize() + { + _mapper = new(); + } - [TestCleanup] - public void Cleanup() - { - _mapper = null; - } + [TestCleanup] + public void Cleanup() + { + _mapper = null; + } - [TestMethod] - public void TestMapLeftToRight_WhenNull() - { - NetShieldStatistic entityToTest = null; + [TestMethod] + public void TestMapLeftToRight_WhenNull() + { + NetShieldStatistic entityToTest = null; - NetShieldStatisticIpcEntity result = _mapper.Map(entityToTest); + NetShieldStatisticIpcEntity result = _mapper.Map(entityToTest); - Assert.IsNull(result); - } + Assert.IsNull(result); + } - [TestMethod] - public void TestMapLeftToRight() - { - NetShieldStatistic entityToTest = new() - { - NumOfMaliciousUrlsBlocked = DateTime.UtcNow.Millisecond, - NumOfAdvertisementUrlsBlocked = DateTime.UtcNow.Ticks, - NumOfTrackingUrlsBlocked = DateTime.UtcNow.Year - }; - Assert.IsNotNull(entityToTest.TimestampUtc); - - NetShieldStatisticIpcEntity result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(entityToTest.NumOfMaliciousUrlsBlocked, result.NumOfMaliciousUrlsBlocked); - Assert.AreEqual(entityToTest.NumOfAdvertisementUrlsBlocked, result.NumOfAdvertisementUrlsBlocked); - Assert.AreEqual(entityToTest.NumOfTrackingUrlsBlocked, result.NumOfTrackingUrlsBlocked); - Assert.IsNotNull(result.TimestampUtc); - Assert.AreEqual(entityToTest.TimestampUtc, result.TimestampUtc); - } - - [TestMethod] - public void TestMapRightToLeft_WhenNull() + [TestMethod] + public void TestMapLeftToRight() + { + NetShieldStatistic entityToTest = new() { - NetShieldStatisticIpcEntity entityToTest = null; + NumOfMaliciousUrlsBlocked = DateTime.UtcNow.Millisecond, + NumOfAdvertisementUrlsBlocked = DateTime.UtcNow.Ticks, + NumOfTrackingUrlsBlocked = DateTime.UtcNow.Year + }; + Assert.IsNotNull(entityToTest.TimestampUtc); + + NetShieldStatisticIpcEntity result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(entityToTest.NumOfMaliciousUrlsBlocked, result.NumOfMaliciousUrlsBlocked); + Assert.AreEqual(entityToTest.NumOfAdvertisementUrlsBlocked, result.NumOfAdvertisementUrlsBlocked); + Assert.AreEqual(entityToTest.NumOfTrackingUrlsBlocked, result.NumOfTrackingUrlsBlocked); + Assert.IsNotNull(result.TimestampUtc); + Assert.AreEqual(entityToTest.TimestampUtc, result.TimestampUtc); + } - NetShieldStatistic result = _mapper.Map(entityToTest); + [TestMethod] + public void TestMapRightToLeft_WhenNull() + { + NetShieldStatisticIpcEntity entityToTest = null; + + NetShieldStatistic result = _mapper.Map(entityToTest); - Assert.IsNull(result); - } + Assert.IsNull(result); + } - [TestMethod] - public void TestMapRightToLeft() + [TestMethod] + public void TestMapRightToLeft() + { + NetShieldStatisticIpcEntity entityToTest = new() { - NetShieldStatisticIpcEntity entityToTest = new() - { - NumOfMaliciousUrlsBlocked = DateTime.UtcNow.Millisecond, - NumOfAdvertisementUrlsBlocked = DateTime.UtcNow.Ticks, - NumOfTrackingUrlsBlocked = DateTime.UtcNow.Year, - TimestampUtc = DateTime.UtcNow, - }; - - NetShieldStatistic result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(entityToTest.NumOfMaliciousUrlsBlocked, result.NumOfMaliciousUrlsBlocked); - Assert.AreEqual(entityToTest.NumOfAdvertisementUrlsBlocked, result.NumOfAdvertisementUrlsBlocked); - Assert.AreEqual(entityToTest.NumOfTrackingUrlsBlocked, result.NumOfTrackingUrlsBlocked); - Assert.IsNotNull(result.TimestampUtc); - Assert.AreEqual(entityToTest.TimestampUtc, result.TimestampUtc); - } + NumOfMaliciousUrlsBlocked = DateTime.UtcNow.Millisecond, + NumOfAdvertisementUrlsBlocked = DateTime.UtcNow.Ticks, + NumOfTrackingUrlsBlocked = DateTime.UtcNow.Year, + TimestampUtc = DateTime.UtcNow, + }; + + NetShieldStatistic result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(entityToTest.NumOfMaliciousUrlsBlocked, result.NumOfMaliciousUrlsBlocked); + Assert.AreEqual(entityToTest.NumOfAdvertisementUrlsBlocked, result.NumOfAdvertisementUrlsBlocked); + Assert.AreEqual(entityToTest.NumOfTrackingUrlsBlocked, result.NumOfTrackingUrlsBlocked); + Assert.IsNotNull(result.TimestampUtc); + Assert.AreEqual(entityToTest.TimestampUtc, result.TimestampUtc); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/PortForwardingStateMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/PortForwardingStateMapperTest.cs index 356d8a1e8..2ac3a6465 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/PortForwardingStateMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/PortForwardingStateMapperTest.cs @@ -24,101 +24,100 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.PortForwarding; using ProtonVPN.ProcessCommunication.EntityMapping.PortForwarding; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.PortForwarding +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.PortForwarding; + +[TestClass] +public class PortForwardingStateMapperTest { - [TestClass] - public class PortForwardingStateMapperTest + private const PortMappingStatusIpcEntity EXPECTED_PORT_MAPPING_STATUS_IPC_ENTITY = PortMappingStatusIpcEntity.Error; + private const PortMappingStatus EXPECTED_PORT_MAPPING_STATUS = PortMappingStatus.DestroyPortMappingCommunication; + + private IEntityMapper _entityMapper; + private PortForwardingStateMapper _mapper; + private TemporaryMappedPortIpcEntity _expectedTemporaryMappedPortIpcEntity; + private TemporaryMappedPort _expectedTemporaryMappedPort; + + [TestInitialize] + public void Initialize() { - private const PortMappingStatusIpcEntity EXPECTED_PORT_MAPPING_STATUS_IPC_ENTITY = PortMappingStatusIpcEntity.Error; - private const PortMappingStatus EXPECTED_PORT_MAPPING_STATUS = PortMappingStatus.DestroyPortMappingCommunication; + _entityMapper = Substitute.For(); + _mapper = new(_entityMapper); + + _expectedTemporaryMappedPortIpcEntity = new TemporaryMappedPortIpcEntity(); + _entityMapper.Map(Arg.Any()) + .Returns(_expectedTemporaryMappedPortIpcEntity); + _entityMapper.Map(Arg.Any()) + .Returns(EXPECTED_PORT_MAPPING_STATUS_IPC_ENTITY); + + _expectedTemporaryMappedPort = new TemporaryMappedPort(); + _entityMapper.Map(Arg.Any()) + .Returns(_expectedTemporaryMappedPort); + _entityMapper.Map(Arg.Any()) + .Returns(EXPECTED_PORT_MAPPING_STATUS); + } - private IEntityMapper _entityMapper; - private PortForwardingStateMapper _mapper; - private TemporaryMappedPortIpcEntity _expectedTemporaryMappedPortIpcEntity; - private TemporaryMappedPort _expectedTemporaryMappedPort; + [TestCleanup] + public void Cleanup() + { + _entityMapper = null; + _mapper = null; + _expectedTemporaryMappedPortIpcEntity = null; + _expectedTemporaryMappedPort = null; + } - [TestInitialize] - public void Initialize() - { - _entityMapper = Substitute.For(); - _mapper = new(_entityMapper); - - _expectedTemporaryMappedPortIpcEntity = new TemporaryMappedPortIpcEntity(); - _entityMapper.Map(Arg.Any()) - .Returns(_expectedTemporaryMappedPortIpcEntity); - _entityMapper.Map(Arg.Any()) - .Returns(EXPECTED_PORT_MAPPING_STATUS_IPC_ENTITY); - - _expectedTemporaryMappedPort = new TemporaryMappedPort(); - _entityMapper.Map(Arg.Any()) - .Returns(_expectedTemporaryMappedPort); - _entityMapper.Map(Arg.Any()) - .Returns(EXPECTED_PORT_MAPPING_STATUS); - } - - [TestCleanup] - public void Cleanup() - { - _entityMapper = null; - _mapper = null; - _expectedTemporaryMappedPortIpcEntity = null; - _expectedTemporaryMappedPort = null; - } - - [TestMethod] - public void TestMapLeftToRight_WhenNull() - { - PortForwardingState entityToTest = null; + [TestMethod] + public void TestMapLeftToRight_WhenNull() + { + PortForwardingState entityToTest = null; - PortForwardingStateIpcEntity result = _mapper.Map(entityToTest); + PortForwardingStateIpcEntity result = _mapper.Map(entityToTest); - Assert.IsNull(result); - } + Assert.IsNull(result); + } - [TestMethod] - public void TestMapLeftToRight() - { - PortForwardingState entityToTest = new() - { - MappedPort = new TemporaryMappedPort(), - Status = PortMappingStatus.Error, - TimestampUtc = DateTime.UtcNow - }; - - PortForwardingStateIpcEntity result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(_expectedTemporaryMappedPortIpcEntity, result.MappedPort); - Assert.AreEqual(EXPECTED_PORT_MAPPING_STATUS_IPC_ENTITY, result.Status); - Assert.AreEqual(entityToTest.TimestampUtc, result.TimestampUtc); - } - - [TestMethod] - public void TestMapRightToLeft_WhenNull() + [TestMethod] + public void TestMapLeftToRight() + { + PortForwardingState entityToTest = new() { - PortForwardingStateIpcEntity entityToTest = null; + MappedPort = new TemporaryMappedPort(), + Status = PortMappingStatus.Error, + TimestampUtc = DateTime.UtcNow + }; + + PortForwardingStateIpcEntity result = _mapper.Map(entityToTest); - PortForwardingState result = _mapper.Map(entityToTest); + Assert.IsNotNull(result); + Assert.AreEqual(_expectedTemporaryMappedPortIpcEntity, result.MappedPort); + Assert.AreEqual(EXPECTED_PORT_MAPPING_STATUS_IPC_ENTITY, result.Status); + Assert.AreEqual(entityToTest.TimestampUtc, result.TimestampUtc); + } + + [TestMethod] + public void TestMapRightToLeft_WhenNull() + { + PortForwardingStateIpcEntity entityToTest = null; - Assert.IsNull(result); - } + PortForwardingState result = _mapper.Map(entityToTest); - [TestMethod] - public void TestMapRightToLeft() + Assert.IsNull(result); + } + + [TestMethod] + public void TestMapRightToLeft() + { + PortForwardingStateIpcEntity entityToTest = new() { - PortForwardingStateIpcEntity entityToTest = new() - { - MappedPort = new TemporaryMappedPortIpcEntity(), - Status = PortMappingStatusIpcEntity.DestroyPortMappingCommunication, - TimestampUtc = DateTime.UtcNow - }; - - PortForwardingState result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(_expectedTemporaryMappedPort, result.MappedPort); - Assert.AreEqual(EXPECTED_PORT_MAPPING_STATUS, result.Status); - Assert.AreEqual(entityToTest.TimestampUtc, result.TimestampUtc); - } + MappedPort = new TemporaryMappedPortIpcEntity(), + Status = PortMappingStatusIpcEntity.DestroyPortMappingCommunication, + TimestampUtc = DateTime.UtcNow + }; + + PortForwardingState result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(_expectedTemporaryMappedPort, result.MappedPort); + Assert.AreEqual(EXPECTED_PORT_MAPPING_STATUS, result.Status); + Assert.AreEqual(entityToTest.TimestampUtc, result.TimestampUtc); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/PortMappingStatusMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/PortMappingStatusMapperTest.cs index 109d3a8ae..97ceb9c6b 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/PortMappingStatusMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/PortMappingStatusMapperTest.cs @@ -24,14 +24,13 @@ using ProtonVPN.ProcessCommunication.EntityMapping.PortForwarding; using ProtonVPN.ProcessCommunication.EntityMapping.Tests.Common; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.PortForwarding +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.PortForwarding; + +[TestClass] +public class PortMappingStatusMapperTest : EnumMapperTestBase { - [TestClass] - public class PortMappingStatusMapperTest : EnumMapperTestBase + protected override IMapper CreateMapper() { - protected override IMapper CreateMapper() - { - return new PortMappingStatusMapper(); - } + return new PortMappingStatusMapper(); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/TemporaryMappedPortMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/TemporaryMappedPortMapperTest.cs index c34b21096..6aed06ec7 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/TemporaryMappedPortMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/PortForwarding/TemporaryMappedPortMapperTest.cs @@ -22,101 +22,100 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.PortForwarding; using ProtonVPN.ProcessCommunication.EntityMapping.PortForwarding; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.PortForwarding +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.PortForwarding; + +[TestClass] +public class TemporaryMappedPortMapperTest { - [TestClass] - public class TemporaryMappedPortMapperTest - { - private TemporaryMappedPortMapper _mapper; + private TemporaryMappedPortMapper _mapper; - [TestInitialize] - public void Initialize() - { - _mapper = new(); - } + [TestInitialize] + public void Initialize() + { + _mapper = new(); + } - [TestCleanup] - public void Cleanup() - { - _mapper = null; - } + [TestCleanup] + public void Cleanup() + { + _mapper = null; + } - [TestMethod] - public void TestMapLeftToRight_WhenNull() - { - TemporaryMappedPort entityToTest = null; + [TestMethod] + public void TestMapLeftToRight_WhenNull() + { + TemporaryMappedPort entityToTest = null; - TemporaryMappedPortIpcEntity result = _mapper.Map(entityToTest); + TemporaryMappedPortIpcEntity result = _mapper.Map(entityToTest); - Assert.IsNull(result); - } + Assert.IsNull(result); + } - [TestMethod] - public void TestMapLeftToRight_WhenMappedPortIsNull() + [TestMethod] + public void TestMapLeftToRight_WhenMappedPortIsNull() + { + TemporaryMappedPort entityToTest = new() { - TemporaryMappedPort entityToTest = new() - { - Lifetime = TimeSpan.FromMinutes(1), - ExpirationDateUtc = DateTime.UtcNow - }; + Lifetime = TimeSpan.FromMinutes(1), + ExpirationDateUtc = DateTime.UtcNow + }; - TemporaryMappedPortIpcEntity result = _mapper.Map(entityToTest); + TemporaryMappedPortIpcEntity result = _mapper.Map(entityToTest); - Assert.IsNull(result); - } + Assert.IsNull(result); + } - [TestMethod] - public void TestMapLeftToRight() - { - int internalPort = 7; - int externalPort = 28; - TemporaryMappedPort entityToTest = new() - { - MappedPort = new MappedPort(internalPort, externalPort), - Lifetime = TimeSpan.FromMinutes(4), - ExpirationDateUtc = DateTime.UtcNow - }; - - TemporaryMappedPortIpcEntity result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(internalPort, result.InternalPort); - Assert.AreEqual(externalPort, result.ExternalPort); - Assert.AreEqual(entityToTest.Lifetime, result.Lifetime); - Assert.AreEqual(entityToTest.ExpirationDateUtc, result.ExpirationDateUtc); - } - - [TestMethod] - public void TestMapRightToLeft_WhenNull() + [TestMethod] + public void TestMapLeftToRight() + { + int internalPort = 7; + int externalPort = 28; + TemporaryMappedPort entityToTest = new() { - TemporaryMappedPortIpcEntity entityToTest = null; + MappedPort = new MappedPort(internalPort, externalPort), + Lifetime = TimeSpan.FromMinutes(4), + ExpirationDateUtc = DateTime.UtcNow + }; + + TemporaryMappedPortIpcEntity result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(internalPort, result.InternalPort); + Assert.AreEqual(externalPort, result.ExternalPort); + Assert.AreEqual(entityToTest.Lifetime, result.Lifetime); + Assert.AreEqual(entityToTest.ExpirationDateUtc, result.ExpirationDateUtc); + } - TemporaryMappedPort result = _mapper.Map(entityToTest); + [TestMethod] + public void TestMapRightToLeft_WhenNull() + { + TemporaryMappedPortIpcEntity entityToTest = null; - Assert.IsNull(result); - } + TemporaryMappedPort result = _mapper.Map(entityToTest); - [TestMethod] - public void TestMapRightToLeft() + Assert.IsNull(result); + } + + [TestMethod] + public void TestMapRightToLeft() + { + int internalPort = 7; + int externalPort = 28; + TemporaryMappedPortIpcEntity entityToTest = new() { - int internalPort = 7; - int externalPort = 28; - TemporaryMappedPortIpcEntity entityToTest = new() - { - InternalPort = internalPort, - ExternalPort = externalPort, - Lifetime = TimeSpan.FromMinutes(3), - ExpirationDateUtc = DateTime.UtcNow - }; - - TemporaryMappedPort result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.IsNotNull(result.MappedPort); - Assert.AreEqual(entityToTest.InternalPort, result.MappedPort.InternalPort); - Assert.AreEqual(entityToTest.ExternalPort, result.MappedPort.ExternalPort); - Assert.AreEqual(entityToTest.Lifetime, result.Lifetime); - Assert.AreEqual(entityToTest.ExpirationDateUtc, result.ExpirationDateUtc); - } + InternalPort = internalPort, + ExternalPort = externalPort, + Lifetime = TimeSpan.FromMinutes(3), + ExpirationDateUtc = DateTime.UtcNow + }; + + TemporaryMappedPort result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.IsNotNull(result.MappedPort); + Assert.AreEqual(entityToTest.InternalPort, result.MappedPort.InternalPort); + Assert.AreEqual(entityToTest.ExternalPort, result.MappedPort.ExternalPort); + Assert.AreEqual(entityToTest.Lifetime, result.Lifetime); + Assert.AreEqual(entityToTest.ExpirationDateUtc, result.ExpirationDateUtc); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/ProtonVPN.ProcessCommunication.EntityMapping.Tests.csproj b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/ProtonVPN.ProcessCommunication.EntityMapping.Tests.csproj index 56ca92704..bad444981 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/ProtonVPN.ProcessCommunication.EntityMapping.Tests.csproj +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/ProtonVPN.ProcessCommunication.EntityMapping.Tests.csproj @@ -1,27 +1,27 @@ - - - - net6.0-windows - enable - ..\..\bin - false - Library - false - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - - - - + + + net8.0-windows + enable + ..\..\bin + false + Library + false + false + AnyCPU;ARM64 + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/ConnectionDetailsMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/ConnectionDetailsMapperTest.cs index bd2399d93..949d6fcf1 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/ConnectionDetailsMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/ConnectionDetailsMapperTest.cs @@ -22,79 +22,78 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class ConnectionDetailsMapperTest { - [TestClass] - public class ConnectionDetailsMapperTest + private ConnectionDetailsMapper _mapper; + + [TestInitialize] + public void Initialize() { - private ConnectionDetailsMapper _mapper; + _mapper = new(); + } - [TestInitialize] - public void Initialize() - { - _mapper = new(); - } + [TestCleanup] + public void Cleanup() + { + _mapper = null; + } - [TestCleanup] - public void Cleanup() - { - _mapper = null; - } + [TestMethod] + public void TestMapLeftToRight_WhenNull() + { + ConnectionDetails entityToTest = null; + + ConnectionDetailsIpcEntity result = _mapper.Map(entityToTest); + + Assert.IsNull(result); + } - [TestMethod] - public void TestMapLeftToRight_WhenNull() + [TestMethod] + public void TestMapLeftToRight() + { + ConnectionDetails entityToTest = new() { - ConnectionDetails entityToTest = null; + ClientIpAddress = $"A {DateTime.UtcNow}", + ServerIpAddress = $"B {DateTime.UtcNow}", + ClientCountryIsoCode = $"C {DateTime.UtcNow}", + }; - ConnectionDetailsIpcEntity result = _mapper.Map(entityToTest); + ConnectionDetailsIpcEntity result = _mapper.Map(entityToTest); - Assert.IsNull(result); - } + Assert.IsNotNull(result); + Assert.AreEqual(entityToTest.ClientIpAddress, result.ClientIpAddress); + Assert.AreEqual(entityToTest.ServerIpAddress, result.ServerIpAddress); + Assert.AreEqual(entityToTest.ClientCountryIsoCode, result.ClientCountryIsoCode); + } - [TestMethod] - public void TestMapLeftToRight() - { - ConnectionDetails entityToTest = new() - { - ClientIpAddress = $"A {DateTime.UtcNow}", - ServerIpAddress = $"B {DateTime.UtcNow}", - ClientCountryIsoCode = $"C {DateTime.UtcNow}", - }; - - ConnectionDetailsIpcEntity result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(entityToTest.ClientIpAddress, result.ClientIpAddress); - Assert.AreEqual(entityToTest.ServerIpAddress, result.ServerIpAddress); - Assert.AreEqual(entityToTest.ClientCountryIsoCode, result.ClientCountryIsoCode); - } - - [TestMethod] - public void TestMapRightToLeft_WhenNull() - { - ConnectionDetailsIpcEntity entityToTest = null; + [TestMethod] + public void TestMapRightToLeft_WhenNull() + { + ConnectionDetailsIpcEntity entityToTest = null; - ConnectionDetails result = _mapper.Map(entityToTest); + ConnectionDetails result = _mapper.Map(entityToTest); - Assert.IsNull(result); - } + Assert.IsNull(result); + } - [TestMethod] - public void TestMapRightToLeft() + [TestMethod] + public void TestMapRightToLeft() + { + ConnectionDetailsIpcEntity entityToTest = new() { - ConnectionDetailsIpcEntity entityToTest = new() - { - ClientIpAddress = $"A {DateTime.UtcNow}", - ServerIpAddress = $"B {DateTime.UtcNow}", - ClientCountryIsoCode = $"C {DateTime.UtcNow}", - }; - - ConnectionDetails result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(entityToTest.ClientIpAddress, result.ClientIpAddress); - Assert.AreEqual(entityToTest.ServerIpAddress, result.ServerIpAddress); - Assert.AreEqual(entityToTest.ClientCountryIsoCode, result.ClientCountryIsoCode); - } + ClientIpAddress = $"A {DateTime.UtcNow}", + ServerIpAddress = $"B {DateTime.UtcNow}", + ClientCountryIsoCode = $"C {DateTime.UtcNow}", + }; + + ConnectionDetails result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(entityToTest.ClientIpAddress, result.ClientIpAddress); + Assert.AreEqual(entityToTest.ServerIpAddress, result.ServerIpAddress); + Assert.AreEqual(entityToTest.ClientCountryIsoCode, result.ClientCountryIsoCode); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/ConnectionRequestMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/ConnectionRequestMapperTest.cs index 56ee776c4..05cb3bee7 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/ConnectionRequestMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/ConnectionRequestMapperTest.cs @@ -27,131 +27,130 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class ConnectionRequestMapperTest { - [TestClass] - public class ConnectionRequestMapperTest + private IEntityMapper _entityMapper; + private ConnectionRequestMapper _mapper; + + private List _expectedVpnServerIpcEntities; + private VpnProtocolIpcEntity? _expectedVpnProtocolIpcEntity; + private VpnConfigIpcEntity _expectedVpnConfigIpcEntity; + private VpnCredentialsIpcEntity _expectedVpnCredentialsIpcEntity; + private List _expectedVpnHosts; + private VpnProtocol? _expectedVpnProtocol; + private VpnConfig _expectedVpnConfig; + private VpnCredentials? _expectedVpnCredentials; + + [TestInitialize] + public void Initialize() + { + _entityMapper = Substitute.For(); + _mapper = new(_entityMapper); + + _expectedVpnServerIpcEntities = new List() { new VpnServerIpcEntity() }; + _entityMapper.Map(Arg.Any>()) + .Returns(_expectedVpnServerIpcEntities); + + _expectedVpnProtocolIpcEntity = VpnProtocolIpcEntity.OpenVpnUdp; + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnProtocolIpcEntity.Value); + + _expectedVpnConfigIpcEntity = new VpnConfigIpcEntity(); + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnConfigIpcEntity); + + _expectedVpnCredentialsIpcEntity = new VpnCredentialsIpcEntity(); + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnCredentialsIpcEntity); + + _expectedVpnHosts = new List(); + _entityMapper.Map(Arg.Any>()) + .Returns(_expectedVpnHosts); + + _expectedVpnProtocol = VpnProtocol.OpenVpnUdp; + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnProtocol.Value); + + _expectedVpnConfig = new VpnConfig(new VpnConfigParameters()); + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnConfig); + + _expectedVpnCredentials = new VpnCredentials(); + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnCredentials.Value); + } + + [TestCleanup] + public void Cleanup() + { + _entityMapper = null; + _mapper = null; + + _expectedVpnServerIpcEntities = null; + _expectedVpnProtocolIpcEntity = null; + _expectedVpnConfigIpcEntity = null; + _expectedVpnCredentialsIpcEntity = null; + _expectedVpnHosts = null; + _expectedVpnProtocol = null; + _expectedVpnConfig = null; + _expectedVpnCredentials = null; + } + + [TestMethod] + public void TestMapLeftToRight_WhenNull() { - private IEntityMapper _entityMapper; - private ConnectionRequestMapper _mapper; - - private List _expectedVpnServerIpcEntities; - private VpnProtocolIpcEntity? _expectedVpnProtocolIpcEntity; - private VpnConfigIpcEntity _expectedVpnConfigIpcEntity; - private VpnCredentialsIpcEntity _expectedVpnCredentialsIpcEntity; - private List _expectedVpnHosts; - private VpnProtocol? _expectedVpnProtocol; - private VpnConfig _expectedVpnConfig; - private VpnCredentials? _expectedVpnCredentials; - - [TestInitialize] - public void Initialize() - { - _entityMapper = Substitute.For(); - _mapper = new(_entityMapper); - - _expectedVpnServerIpcEntities = new List() { new VpnServerIpcEntity() }; - _entityMapper.Map(Arg.Any>()) - .Returns(_expectedVpnServerIpcEntities); - - _expectedVpnProtocolIpcEntity = VpnProtocolIpcEntity.OpenVpnUdp; - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnProtocolIpcEntity.Value); - - _expectedVpnConfigIpcEntity = new VpnConfigIpcEntity(); - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnConfigIpcEntity); - - _expectedVpnCredentialsIpcEntity = new VpnCredentialsIpcEntity(); - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnCredentialsIpcEntity); - - _expectedVpnHosts = new List(); - _entityMapper.Map(Arg.Any>()) - .Returns(_expectedVpnHosts); - - _expectedVpnProtocol = VpnProtocol.OpenVpnUdp; - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnProtocol.Value); - - _expectedVpnConfig = new VpnConfig(new VpnConfigParameters()); - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnConfig); - - _expectedVpnCredentials = new VpnCredentials(); - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnCredentials.Value); - } - - [TestCleanup] - public void Cleanup() - { - _entityMapper = null; - _mapper = null; - - _expectedVpnServerIpcEntities = null; - _expectedVpnProtocolIpcEntity = null; - _expectedVpnConfigIpcEntity = null; - _expectedVpnCredentialsIpcEntity = null; - _expectedVpnHosts = null; - _expectedVpnProtocol = null; - _expectedVpnConfig = null; - _expectedVpnCredentials = null; - } - - [TestMethod] - public void TestMapLeftToRight_WhenNull() - { - VpnConnectionRequest entityToTest = null; - - ConnectionRequestIpcEntity result = _mapper.Map(entityToTest); - - Assert.IsNull(result); - } - - [TestMethod] - public void TestMapLeftToRight() - { - VpnConnectionRequest entityToTest = new( - new List(), - VpnProtocol.OpenVpnUdp, - new VpnConfig(new VpnConfigParameters()), - new VpnCredentials(string.Empty, new AsymmetricKeyPair( - new SecretKey("PVPN", KeyAlgorithm.Unknown), new PublicKey("PVPN", KeyAlgorithm.Unknown)))); - - ConnectionRequestIpcEntity result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(_expectedVpnServerIpcEntities.Count, result.Servers.Count()); - Assert.AreEqual(_expectedVpnServerIpcEntities.Single(), result.Servers.Single()); - Assert.AreEqual(_expectedVpnProtocolIpcEntity, result.Protocol); - Assert.AreEqual(_expectedVpnConfigIpcEntity, result.Config); - Assert.AreEqual(_expectedVpnCredentialsIpcEntity, result.Credentials); - Assert.IsNotNull(result.Settings); - } - - [TestMethod] - public void TestMapRightToLeft_WhenNull() - { - ConnectionRequestIpcEntity entityToTest = null; - - VpnConnectionRequest result = _mapper.Map(entityToTest); - - Assert.IsNull(result); - } - - [TestMethod] - public void TestMapRightToLeft() - { - ConnectionRequestIpcEntity entityToTest = new(); - - VpnConnectionRequest result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(_expectedVpnHosts, result.Servers); - Assert.AreEqual(_expectedVpnProtocol, result.VpnProtocol); - Assert.AreEqual(_expectedVpnConfig, result.Config); - Assert.AreEqual(_expectedVpnCredentials, result.Credentials); - } + VpnConnectionRequest entityToTest = null; + + ConnectionRequestIpcEntity result = _mapper.Map(entityToTest); + + Assert.IsNull(result); + } + + [TestMethod] + public void TestMapLeftToRight() + { + VpnConnectionRequest entityToTest = new( + new List(), + VpnProtocol.OpenVpnUdp, + new VpnConfig(new VpnConfigParameters()), + new VpnCredentials(string.Empty, new AsymmetricKeyPair( + new SecretKey("PVPN", KeyAlgorithm.Unknown), new PublicKey("PVPN", KeyAlgorithm.Unknown)))); + + ConnectionRequestIpcEntity result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(_expectedVpnServerIpcEntities.Count, result.Servers.Count()); + Assert.AreEqual(_expectedVpnServerIpcEntities.Single(), result.Servers.Single()); + Assert.AreEqual(_expectedVpnProtocolIpcEntity, result.Protocol); + Assert.AreEqual(_expectedVpnConfigIpcEntity, result.Config); + Assert.AreEqual(_expectedVpnCredentialsIpcEntity, result.Credentials); + Assert.IsNotNull(result.Settings); + } + + [TestMethod] + public void TestMapRightToLeft_WhenNull() + { + ConnectionRequestIpcEntity entityToTest = null; + + VpnConnectionRequest result = _mapper.Map(entityToTest); + + Assert.IsNull(result); + } + + [TestMethod] + public void TestMapRightToLeft() + { + ConnectionRequestIpcEntity entityToTest = new(); + + VpnConnectionRequest result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(_expectedVpnHosts, result.Servers); + Assert.AreEqual(_expectedVpnProtocol, result.VpnProtocol); + Assert.AreEqual(_expectedVpnConfig, result.Config); + Assert.AreEqual(_expectedVpnCredentials, result.Credentials); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/KillSwitchModeMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/KillSwitchModeMapperTest.cs index 17a05e42f..c8fe7b509 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/KillSwitchModeMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/KillSwitchModeMapperTest.cs @@ -24,14 +24,13 @@ using ProtonVPN.ProcessCommunication.EntityMapping.Tests.Common; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class KillSwitchModeMapperTest : EnumMapperTestBase { - [TestClass] - public class KillSwitchModeMapperTest : EnumMapperTestBase + protected override IMapper CreateMapper() { - protected override IMapper CreateMapper() - { - return new KillSwitchModeMapper(); - } + return new KillSwitchModeMapper(); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/OpenVpnAdapterMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/OpenVpnAdapterMapperTest.cs index b77f038a0..c64fb34b0 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/OpenVpnAdapterMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/OpenVpnAdapterMapperTest.cs @@ -24,14 +24,13 @@ using ProtonVPN.ProcessCommunication.EntityMapping.Tests.Common; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class OpenVpnAdapterMapperTest : EnumMapperTestBase { - [TestClass] - public class OpenVpnAdapterMapperTest : EnumMapperTestBase + protected override IMapper CreateMapper() { - protected override IMapper CreateMapper() - { - return new OpenVpnAdapterMapper(); - } + return new OpenVpnAdapterMapper(); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/SplitTunnelModeMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/SplitTunnelModeMapperTest.cs index 1fe40158c..95ae172d0 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/SplitTunnelModeMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/SplitTunnelModeMapperTest.cs @@ -24,14 +24,13 @@ using ProtonVPN.ProcessCommunication.EntityMapping.Tests.Common; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class SplitTunnelModeMapperTest : EnumMapperTestBase { - [TestClass] - public class SplitTunnelModeMapperTest : EnumMapperTestBase + protected override IMapper CreateMapper() { - protected override IMapper CreateMapper() - { - return new SplitTunnelModeMapper(); - } + return new SplitTunnelModeMapper(); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/TrafficBytesMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/TrafficBytesMapperTest.cs index cdd52cff7..2394d7dab 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/TrafficBytesMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/TrafficBytesMapperTest.cs @@ -22,75 +22,74 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class TrafficBytesMapperTest { - [TestClass] - public class TrafficBytesMapperTest - { - private TrafficBytesMapper _mapper; + private TrafficBytesMapper _mapper; - [TestInitialize] - public void Initialize() - { - _mapper = new(); - } + [TestInitialize] + public void Initialize() + { + _mapper = new(); + } - [TestCleanup] - public void Cleanup() - { - _mapper = null; - } + [TestCleanup] + public void Cleanup() + { + _mapper = null; + } - [TestMethod] - public void TestMapLeftToRight_WhenZero() - { - InOutBytes entityToTest = InOutBytes.Zero; + [TestMethod] + public void TestMapLeftToRight_WhenZero() + { + InOutBytes entityToTest = InOutBytes.Zero; - TrafficBytesIpcEntity result = _mapper.Map(entityToTest); + TrafficBytesIpcEntity result = _mapper.Map(entityToTest); - Assert.IsNotNull(result); - Assert.AreEqual(0, result.BytesIn); - Assert.AreEqual(0, result.BytesOut); - } + Assert.IsNotNull(result); + Assert.AreEqual(0u, result.BytesIn); + Assert.AreEqual(0u, result.BytesOut); + } - [TestMethod] - public void TestMapLeftToRight() - { - InOutBytes entityToTest = new(DateTime.UtcNow.Ticks, DateTime.UtcNow.Millisecond); + [TestMethod] + public void TestMapLeftToRight() + { + InOutBytes entityToTest = new((ulong)DateTime.UtcNow.Ticks, (ulong)DateTime.UtcNow.Millisecond); - TrafficBytesIpcEntity result = _mapper.Map(entityToTest); + TrafficBytesIpcEntity result = _mapper.Map(entityToTest); - Assert.IsNotNull(result); - Assert.AreEqual(entityToTest.BytesIn, result.BytesIn); - Assert.AreEqual(entityToTest.BytesOut, result.BytesOut); - } + Assert.IsNotNull(result); + Assert.AreEqual(entityToTest.BytesIn, result.BytesIn); + Assert.AreEqual(entityToTest.BytesOut, result.BytesOut); + } - [TestMethod] - public void TestMapRightToLeft_WhenNull() - { - TrafficBytesIpcEntity entityToTest = null; + [TestMethod] + public void TestMapRightToLeft_WhenNull() + { + TrafficBytesIpcEntity entityToTest = null; - InOutBytes result = _mapper.Map(entityToTest); + InOutBytes result = _mapper.Map(entityToTest); - Assert.IsNotNull(result); - Assert.AreEqual(0, result.BytesIn); - Assert.AreEqual(0, result.BytesOut); - } + Assert.IsNotNull(result); + Assert.AreEqual(0u, result.BytesIn); + Assert.AreEqual(0u, result.BytesOut); + } - [TestMethod] - public void TestMapRightToLeft() + [TestMethod] + public void TestMapRightToLeft() + { + TrafficBytesIpcEntity entityToTest = new() { - TrafficBytesIpcEntity entityToTest = new() - { - BytesIn = DateTime.UtcNow.Ticks, - BytesOut = DateTime.UtcNow.Millisecond, - }; - - InOutBytes result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(entityToTest.BytesIn, result.BytesIn); - Assert.AreEqual(entityToTest.BytesOut, result.BytesOut); - } + BytesIn = (ulong)DateTime.UtcNow.Ticks, + BytesOut = (ulong)DateTime.UtcNow.Millisecond, + }; + + InOutBytes result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(entityToTest.BytesIn, result.BytesIn); + Assert.AreEqual(entityToTest.BytesOut, result.BytesOut); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnConfigMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnConfigMapperTest.cs index a352fdbfa..b66381cb9 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnConfigMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnConfigMapperTest.cs @@ -27,189 +27,184 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class VpnConfigMapperTest { - [TestClass] - public class VpnConfigMapperTest - { - private IEntityMapper _entityMapper; - private VpnConfigMapper _mapper; + private IEntityMapper _entityMapper; + private VpnConfigMapper _mapper; - private SplitTunnelModeIpcEntity? _expectedSplitTunnelModeIpcEntity; - private List _expectedVpnProtocolIpcEntities; + private SplitTunnelModeIpcEntity? _expectedSplitTunnelModeIpcEntity; + private List _expectedVpnProtocolIpcEntities; - private SplitTunnelMode? _expectedSplitTunnelMode; - private List _expectedVpnProtocols; + private SplitTunnelMode? _expectedSplitTunnelMode; + private List _expectedVpnProtocols; - [TestInitialize] - public void Initialize() - { - _entityMapper = Substitute.For(); - _mapper = new(_entityMapper); + [TestInitialize] + public void Initialize() + { + _entityMapper = Substitute.For(); + _mapper = new(_entityMapper); - _expectedSplitTunnelModeIpcEntity = SplitTunnelModeIpcEntity.Block; - _entityMapper.Map(Arg.Any()) - .Returns(_expectedSplitTunnelModeIpcEntity.Value); + _expectedSplitTunnelModeIpcEntity = SplitTunnelModeIpcEntity.Block; + _entityMapper.Map(Arg.Any()) + .Returns(_expectedSplitTunnelModeIpcEntity.Value); - _entityMapper.Map(Arg.Any()) - .Returns((CallInfo callInfo) => (VpnProtocolIpcEntity)(int)callInfo[0]); + _entityMapper.Map(Arg.Any()) + .Returns((CallInfo callInfo) => (VpnProtocolIpcEntity)(int)callInfo[0]); - _expectedVpnProtocolIpcEntities = new List() { VpnProtocolIpcEntity.OpenVpnUdp }; - _entityMapper.Map(Arg.Any>()) - .Returns(_expectedVpnProtocolIpcEntities); + _expectedVpnProtocolIpcEntities = new List() { VpnProtocolIpcEntity.OpenVpnUdp }; + _entityMapper.Map(Arg.Any>()) + .Returns(_expectedVpnProtocolIpcEntities); - _expectedSplitTunnelMode = SplitTunnelMode.Block; - _entityMapper.Map(Arg.Any()) - .Returns(_expectedSplitTunnelMode.Value); + _expectedSplitTunnelMode = SplitTunnelMode.Block; + _entityMapper.Map(Arg.Any()) + .Returns(_expectedSplitTunnelMode.Value); - _entityMapper.Map(Arg.Any()) - .Returns((CallInfo callInfo) => (VpnProtocol)(int)callInfo[0]); + _entityMapper.Map(Arg.Any()) + .Returns((CallInfo callInfo) => (VpnProtocol)(int)callInfo[0]); - _expectedVpnProtocols = new List() { VpnProtocol.OpenVpnUdp }; - _entityMapper.Map(Arg.Any>()) - .Returns(_expectedVpnProtocols); - } + _expectedVpnProtocols = new List() { VpnProtocol.OpenVpnUdp }; + _entityMapper.Map(Arg.Any>()) + .Returns(_expectedVpnProtocols); + } - [TestCleanup] - public void Cleanup() - { - _entityMapper = null; - _mapper = null; + [TestCleanup] + public void Cleanup() + { + _entityMapper = null; + _mapper = null; - _expectedSplitTunnelModeIpcEntity = null; - _expectedVpnProtocolIpcEntities = null; + _expectedSplitTunnelModeIpcEntity = null; + _expectedVpnProtocolIpcEntities = null; - _expectedSplitTunnelMode = null; - _expectedVpnProtocols = null; - } + _expectedSplitTunnelMode = null; + _expectedVpnProtocols = null; + } - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void TestMapLeftToRight_ThrowsWhenNull() - { - VpnConfig entityToTest = null; + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void TestMapLeftToRight_ThrowsWhenNull() + { + VpnConfig entityToTest = null; - _mapper.Map(entityToTest); - } + _mapper.Map(entityToTest); + } - [TestMethod] - public void TestMapLeftToRight() + [TestMethod] + public void TestMapLeftToRight() + { + VpnConfig entityToTest = new(new VpnConfigParameters() { - VpnConfig entityToTest = new(new VpnConfigParameters() + Ports = new Dictionary>() { - Ports = new Dictionary>() - { - { VpnProtocol.WireGuardUdp, new List() { 80, 443 } }, - { VpnProtocol.OpenVpnUdp, new List() { 8080, 1 } } - }, - CustomDns = new List() { "172.16.0.0" }, - SplitTunnelMode = SplitTunnelMode.Block, - SplitTunnelIPs = new List() { "192.168.0.0" }, - OpenVpnAdapter = OpenVpnAdapter.Tun, - VpnProtocol = VpnProtocol.OpenVpnUdp, - PreferredProtocols = new List() { VpnProtocol.OpenVpnTcp }, - NetShieldMode = 2, - SplitTcp = true, - ModerateNat = true, - AllowNonStandardPorts = true, - PortForwarding = true, - }); - - VpnConfigIpcEntity result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - AssertPortsAreEquivalent(entityToTest, result); - CollectionAssert.AreEqual(entityToTest.CustomDns.ToList(), result.CustomDns); - Assert.AreEqual(entityToTest.AllowNonStandardPorts, result.AllowNonStandardPorts); - Assert.AreEqual(_expectedSplitTunnelModeIpcEntity, result.SplitTunnelMode); - CollectionAssert.AreEqual(entityToTest.SplitTunnelIPs.ToList(), result.SplitTunnelIPs); - Assert.AreEqual(entityToTest.NetShieldMode, result.NetShieldMode); - Assert.AreEqual((int)entityToTest.VpnProtocol, (int)result.VpnProtocol); - Assert.AreEqual(entityToTest.ModerateNat, result.ModerateNat); - Assert.AreEqual(_expectedVpnProtocolIpcEntities, result.PreferredProtocols); - Assert.AreEqual(entityToTest.SplitTcp, result.SplitTcp); - Assert.AreEqual(entityToTest.PortForwarding, result.PortForwarding); - } + { VpnProtocol.WireGuardUdp, new List() { 80, 443 } }, + { VpnProtocol.OpenVpnUdp, new List() { 8080, 1 } } + }, + CustomDns = new List() { "172.16.0.0" }, + SplitTunnelMode = SplitTunnelMode.Block, + SplitTunnelIPs = new List() { "192.168.0.0" }, + OpenVpnAdapter = OpenVpnAdapter.Tun, + VpnProtocol = VpnProtocol.OpenVpnUdp, + PreferredProtocols = new List() { VpnProtocol.OpenVpnTcp }, + NetShieldMode = 2, + SplitTcp = true, + ModerateNat = true, + PortForwarding = true, + }); + + VpnConfigIpcEntity result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + AssertPortsAreEquivalent(entityToTest, result); + CollectionAssert.AreEqual(entityToTest.CustomDns.ToList(), result.CustomDns); + Assert.AreEqual(_expectedSplitTunnelModeIpcEntity, result.SplitTunnelMode); + CollectionAssert.AreEqual(entityToTest.SplitTunnelIPs.ToList(), result.SplitTunnelIPs); + Assert.AreEqual(entityToTest.NetShieldMode, result.NetShieldMode); + Assert.AreEqual((int)entityToTest.VpnProtocol, (int)result.VpnProtocol); + Assert.AreEqual(entityToTest.ModerateNat, result.ModerateNat); + Assert.AreEqual(_expectedVpnProtocolIpcEntities, result.PreferredProtocols); + Assert.AreEqual(entityToTest.SplitTcp, result.SplitTcp); + Assert.AreEqual(entityToTest.PortForwarding, result.PortForwarding); + } - private void AssertPortsAreEquivalent(VpnConfig entityToTest, VpnConfigIpcEntity result) - { - Assert.IsNotNull(result.Ports); + private void AssertPortsAreEquivalent(VpnConfig entityToTest, VpnConfigIpcEntity result) + { + Assert.IsNotNull(result.Ports); - List>> leftEntityDictionary = entityToTest.Ports.ToList(); - List> rightEntityDictionary = result.Ports.ToList(); - Assert.AreEqual(leftEntityDictionary.Count, rightEntityDictionary.Count); + List>> leftEntityDictionary = entityToTest.Ports.ToList(); + List> rightEntityDictionary = result.Ports.ToList(); + Assert.AreEqual(leftEntityDictionary.Count, rightEntityDictionary.Count); - for (int keyValuePairIndex = 0; keyValuePairIndex < leftEntityDictionary.Count; keyValuePairIndex++) - { - Assert.AreEqual((int)leftEntityDictionary[keyValuePairIndex].Key, (int)rightEntityDictionary[keyValuePairIndex].Key); - CollectionAssert.AreEqual( - leftEntityDictionary[keyValuePairIndex].Value.ToList(), - rightEntityDictionary[keyValuePairIndex].Value); - } + for (int keyValuePairIndex = 0; keyValuePairIndex < leftEntityDictionary.Count; keyValuePairIndex++) + { + Assert.AreEqual((int)leftEntityDictionary[keyValuePairIndex].Key, (int)rightEntityDictionary[keyValuePairIndex].Key); + CollectionAssert.AreEqual( + leftEntityDictionary[keyValuePairIndex].Value.ToList(), + rightEntityDictionary[keyValuePairIndex].Value); } + } - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void TestMapRightToLeft_ThrowsWhenNull() - { - VpnConfigIpcEntity entityToTest = null; + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void TestMapRightToLeft_ThrowsWhenNull() + { + VpnConfigIpcEntity entityToTest = null; - _mapper.Map(entityToTest); - } + _mapper.Map(entityToTest); + } - [TestMethod] - public void TestMapRightToLeft() + [TestMethod] + public void TestMapRightToLeft() + { + VpnConfigIpcEntity entityToTest = new() { - VpnConfigIpcEntity entityToTest = new() + Ports = new Dictionary() { - Ports = new Dictionary() - { - { VpnProtocolIpcEntity.WireGuardUdp, new int[] { 80, 443 } }, - { VpnProtocolIpcEntity.OpenVpnUdp, new int[] { 8080, 1 } } - }, - CustomDns = new List() { "172.16.0.0" }, - SplitTunnelMode = SplitTunnelModeIpcEntity.Block, - SplitTunnelIPs = new List() { "192.168.0.0" }, - NetShieldMode = 2, - VpnProtocol = VpnProtocolIpcEntity.OpenVpnUdp, - PreferredProtocols = new List() { VpnProtocolIpcEntity.OpenVpnTcp }, - SplitTcp = true, - ModerateNat = true, - AllowNonStandardPorts = true, - PortForwarding = true, - }; - - VpnConfig result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - AssertPortsAreEquivalent(entityToTest, result); - CollectionAssert.AreEqual(entityToTest.CustomDns, result.CustomDns.ToList()); - Assert.AreEqual(_expectedSplitTunnelMode, result.SplitTunnelMode); - CollectionAssert.AreEqual(entityToTest.SplitTunnelIPs, result.SplitTunnelIPs.ToList()); - Assert.AreEqual(entityToTest.NetShieldMode, result.NetShieldMode); - Assert.AreEqual((int)entityToTest.VpnProtocol, (int)result.VpnProtocol); - Assert.AreEqual(_expectedVpnProtocols, result.PreferredProtocols); - Assert.AreEqual(entityToTest.SplitTcp, result.SplitTcp); - Assert.AreEqual(entityToTest.ModerateNat, result.ModerateNat); - Assert.AreEqual(entityToTest.AllowNonStandardPorts, result.AllowNonStandardPorts); - Assert.AreEqual(entityToTest.PortForwarding, result.PortForwarding); - } + { VpnProtocolIpcEntity.WireGuardUdp, new int[] { 80, 443 } }, + { VpnProtocolIpcEntity.OpenVpnUdp, new int[] { 8080, 1 } } + }, + CustomDns = new List() { "172.16.0.0" }, + SplitTunnelMode = SplitTunnelModeIpcEntity.Block, + SplitTunnelIPs = new List() { "192.168.0.0" }, + NetShieldMode = 2, + VpnProtocol = VpnProtocolIpcEntity.OpenVpnUdp, + PreferredProtocols = new List() { VpnProtocolIpcEntity.OpenVpnTcp }, + SplitTcp = true, + ModerateNat = true, + PortForwarding = true, + }; + + VpnConfig result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + AssertPortsAreEquivalent(entityToTest, result); + CollectionAssert.AreEqual(entityToTest.CustomDns, result.CustomDns.ToList()); + Assert.AreEqual(_expectedSplitTunnelMode, result.SplitTunnelMode); + CollectionAssert.AreEqual(entityToTest.SplitTunnelIPs, result.SplitTunnelIPs.ToList()); + Assert.AreEqual(entityToTest.NetShieldMode, result.NetShieldMode); + Assert.AreEqual((int)entityToTest.VpnProtocol, (int)result.VpnProtocol); + Assert.AreEqual(_expectedVpnProtocols, result.PreferredProtocols); + Assert.AreEqual(entityToTest.SplitTcp, result.SplitTcp); + Assert.AreEqual(entityToTest.ModerateNat, result.ModerateNat); + Assert.AreEqual(entityToTest.PortForwarding, result.PortForwarding); + } - private void AssertPortsAreEquivalent(VpnConfigIpcEntity entityToTest, VpnConfig result) - { - Assert.IsNotNull(result.Ports); + private void AssertPortsAreEquivalent(VpnConfigIpcEntity entityToTest, VpnConfig result) + { + Assert.IsNotNull(result.Ports); - List> leftEntityDictionary = entityToTest.Ports.ToList(); - List>> rightEntityDictionary = result.Ports.ToList(); - Assert.AreEqual(leftEntityDictionary.Count, rightEntityDictionary.Count); + List> leftEntityDictionary = entityToTest.Ports.ToList(); + List>> rightEntityDictionary = result.Ports.ToList(); + Assert.AreEqual(leftEntityDictionary.Count, rightEntityDictionary.Count); - for (int keyValuePairIndex = 0; keyValuePairIndex < leftEntityDictionary.Count; keyValuePairIndex++) - { - Assert.AreEqual((int)leftEntityDictionary[keyValuePairIndex].Key, (int)rightEntityDictionary[keyValuePairIndex].Key); - CollectionAssert.AreEqual( - leftEntityDictionary[keyValuePairIndex].Value, - rightEntityDictionary[keyValuePairIndex].Value.ToList()); - } + for (int keyValuePairIndex = 0; keyValuePairIndex < leftEntityDictionary.Count; keyValuePairIndex++) + { + Assert.AreEqual((int)leftEntityDictionary[keyValuePairIndex].Key, (int)rightEntityDictionary[keyValuePairIndex].Key); + CollectionAssert.AreEqual( + leftEntityDictionary[keyValuePairIndex].Value, + rightEntityDictionary[keyValuePairIndex].Value.ToList()); } } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnCredentialsMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnCredentialsMapperTest.cs index 1f071b3e8..b8e929db4 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnCredentialsMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnCredentialsMapperTest.cs @@ -22,83 +22,87 @@ using ProtonVPN.Common.Vpn; using ProtonVPN.Crypto; using ProtonVPN.EntityMapping.Contracts; +using ProtonVPN.ProcessCommunication.Contracts.Entities.Auth; using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn -{ - [TestClass] - public class VpnCredentialsMapperTest - { - private IEntityMapper _entityMapper; - private VpnCredentialsMapper _mapper; - - private AsymmetricKeyPairIpcEntity _expectedAsymmetricKeyPairIpcEntity; - private AsymmetricKeyPair _expectedAsymmetricKeyPair; +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; - [TestInitialize] - public void Initialize() - { - _entityMapper = Substitute.For(); - _mapper = new(_entityMapper); +[TestClass] +public class VpnCredentialsMapperTest +{ + private IEntityMapper _entityMapper; + private VpnCredentialsMapper _mapper; - _expectedAsymmetricKeyPairIpcEntity = new AsymmetricKeyPairIpcEntity(); - _entityMapper.Map(Arg.Any()) - .Returns(_expectedAsymmetricKeyPairIpcEntity); + private AsymmetricKeyPairIpcEntity _expectedAsymmetricKeyPairIpcEntity; + private AsymmetricKeyPair _expectedAsymmetricKeyPair; - _expectedAsymmetricKeyPair = new AsymmetricKeyPair( - new SecretKey("PVPN", KeyAlgorithm.Unknown), new PublicKey("PVPN", KeyAlgorithm.Unknown)); - _entityMapper.Map(Arg.Any()) - .Returns(_expectedAsymmetricKeyPair); - } + [TestInitialize] + public void Initialize() + { + _entityMapper = Substitute.For(); + _mapper = new(_entityMapper); - [TestCleanup] - public void Cleanup() - { - _entityMapper = null; - _mapper = null; + _expectedAsymmetricKeyPairIpcEntity = new AsymmetricKeyPairIpcEntity(); + _entityMapper.Map(Arg.Any()) + .Returns(_expectedAsymmetricKeyPairIpcEntity); - _expectedAsymmetricKeyPairIpcEntity = null; - _expectedAsymmetricKeyPair = null; - } + _expectedAsymmetricKeyPair = new AsymmetricKeyPair( + new SecretKey("PVPN", KeyAlgorithm.Unknown), new PublicKey("PVPN", KeyAlgorithm.Unknown)); + _entityMapper.Map(Arg.Any()) + .Returns(_expectedAsymmetricKeyPair); + } - [TestMethod] - public void TestMapLeftToRight_WithCertificate() - { - VpnCredentials entityToTest = new("CERT", new AsymmetricKeyPair( - new SecretKey("PVPN", KeyAlgorithm.Ed25519), new PublicKey("PVPN", KeyAlgorithm.Ed25519))); + [TestCleanup] + public void Cleanup() + { + _entityMapper = null; + _mapper = null; - VpnCredentialsIpcEntity result = _mapper.Map(entityToTest); + _expectedAsymmetricKeyPairIpcEntity = null; + _expectedAsymmetricKeyPair = null; + } - Assert.IsNotNull(result); - Assert.AreEqual(entityToTest.ClientCertPem, result.ClientCertPem); - Assert.AreEqual(_expectedAsymmetricKeyPairIpcEntity, result.ClientKeyPair); - } + [TestMethod] + public void TestMapLeftToRight_WithCertificate() + { + VpnCredentials entityToTest = new("CERT", + new AsymmetricKeyPair( + new SecretKey("PVPN", KeyAlgorithm.Ed25519), + new PublicKey("PVPN", KeyAlgorithm.Ed25519))); + + VpnCredentialsIpcEntity result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.IsNull(result.Username); + Assert.IsNull(result.Password); + Assert.AreEqual(entityToTest.ClientCertPem, result.Certificate.Pem); + Assert.AreEqual(_expectedAsymmetricKeyPairIpcEntity, result.ClientKeyPair); + } - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void TestMapRightToLeft_ThrowsWhenNull() + [TestMethod] + public void TestMapRightToLeft_WithCertificate() + { + VpnCredentialsIpcEntity entityToTest = new() { - VpnCredentialsIpcEntity entityToTest = null; + Certificate = CreateCertificate(), + ClientKeyPair = new AsymmetricKeyPairIpcEntity() + }; + + VpnCredentials result = _mapper.Map(entityToTest); - _mapper.Map(entityToTest); - } + Assert.IsNotNull(result); + Assert.AreEqual(entityToTest.Certificate.Pem, result.ClientCertPem); + Assert.AreEqual(_expectedAsymmetricKeyPair, result.ClientKeyPair); + } - [TestMethod] - public void TestMapRightToLeft_WithCertificate() + private ConnectionCertificateIpcEntity CreateCertificate() + { + return new() { - VpnCredentialsIpcEntity entityToTest = new() - { - ClientCertPem = DateTime.UtcNow.Ticks.ToString(), - ClientKeyPair = new AsymmetricKeyPairIpcEntity() - }; - - VpnCredentials result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(entityToTest.ClientCertPem, result.ClientCertPem); - Assert.AreEqual(_expectedAsymmetricKeyPair, result.ClientKeyPair); - } + Pem = DateTime.UtcNow.Ticks.ToString(), + ExpirationDateUtc = DateTime.UtcNow.AddDays(1), + }; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnErrorTypeMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnErrorTypeMapperTest.cs index 9db0512d7..8dd36b90e 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnErrorTypeMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnErrorTypeMapperTest.cs @@ -24,14 +24,13 @@ using ProtonVPN.ProcessCommunication.EntityMapping.Tests.Common; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class VpnErrorTypeMapperTest : EnumMapperTestBase { - [TestClass] - public class VpnErrorTypeMapperTest : EnumMapperTestBase + protected override IMapper CreateMapper() { - protected override IMapper CreateMapper() - { - return new VpnErrorTypeMapper(); - } + return new VpnErrorMapper(); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnProtocolMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnProtocolMapperTest.cs index 318d5c88e..9606a804f 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnProtocolMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnProtocolMapperTest.cs @@ -24,14 +24,13 @@ using ProtonVPN.ProcessCommunication.EntityMapping.Tests.Common; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class VpnProtocolMapperTest : EnumMapperTestBase { - [TestClass] - public class VpnProtocolMapperTest : EnumMapperTestBase + protected override IMapper CreateMapper() { - protected override IMapper CreateMapper() - { - return new VpnProtocolMapper(); - } + return new VpnProtocolMapper(); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnServerMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnServerMapperTest.cs index a0beddfed..338c2b97f 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnServerMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnServerMapperTest.cs @@ -26,91 +26,90 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class VpnServerMapperTest { - [TestClass] - public class VpnServerMapperTest - { - private IEntityMapper _entityMapper; - private VpnServerMapper _mapper; + private IEntityMapper _entityMapper; + private VpnServerMapper _mapper; - private ServerPublicKeyIpcEntity _expectedServerPublicKeyIpcEntity; - private PublicKey _expectedPublicKey; + private ServerPublicKeyIpcEntity _expectedServerPublicKeyIpcEntity; + private PublicKey _expectedPublicKey; - [TestInitialize] - public void Initialize() - { - _entityMapper = Substitute.For(); - _mapper = new(_entityMapper); + [TestInitialize] + public void Initialize() + { + _entityMapper = Substitute.For(); + _mapper = new(_entityMapper); - _expectedServerPublicKeyIpcEntity = new ServerPublicKeyIpcEntity(); - _entityMapper.Map(Arg.Any()) - .Returns(_expectedServerPublicKeyIpcEntity); + _expectedServerPublicKeyIpcEntity = new ServerPublicKeyIpcEntity(); + _entityMapper.Map(Arg.Any()) + .Returns(_expectedServerPublicKeyIpcEntity); - _expectedPublicKey = new PublicKey("PVPN", KeyAlgorithm.Unknown); - _entityMapper.Map(Arg.Any()) - .Returns(_expectedPublicKey); - } + _expectedPublicKey = new PublicKey("PVPN", KeyAlgorithm.Unknown); + _entityMapper.Map(Arg.Any()) + .Returns(_expectedPublicKey); + } - [TestCleanup] - public void Cleanup() - { - _entityMapper = null; - _mapper = null; + [TestCleanup] + public void Cleanup() + { + _entityMapper = null; + _mapper = null; + + _expectedServerPublicKeyIpcEntity = null; + _expectedPublicKey = null; + } - _expectedServerPublicKeyIpcEntity = null; - _expectedPublicKey = null; - } + [TestMethod] + public void TestMapLeftToRight() + { + VpnHost entityToTest = new( + name: "protonvpn.com", + ip: "192.168.0.0", + label: DateTime.UtcNow.Millisecond.ToString(), + x25519PublicKey: new PublicKey("PVPN", KeyAlgorithm.Unknown), + signature: DateTime.UtcNow.Ticks.ToString()); + + VpnServerIpcEntity result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(entityToTest.Name, result.Name); + Assert.AreEqual(entityToTest.Ip, result.Ip); + Assert.AreEqual(entityToTest.Label, result.Label); + Assert.AreEqual(_expectedServerPublicKeyIpcEntity, result.X25519PublicKey); + Assert.AreEqual(entityToTest.Signature, result.Signature); + } - [TestMethod] - public void TestMapLeftToRight() - { - VpnHost entityToTest = new( - name: "protonvpn.com", - ip: "192.168.0.0", - label: DateTime.UtcNow.Millisecond.ToString(), - x25519PublicKey: new PublicKey("PVPN", KeyAlgorithm.Unknown), - signature: DateTime.UtcNow.Ticks.ToString()); - - VpnServerIpcEntity result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(entityToTest.Name, result.Name); - Assert.AreEqual(entityToTest.Ip, result.Ip); - Assert.AreEqual(entityToTest.Label, result.Label); - Assert.AreEqual(_expectedServerPublicKeyIpcEntity, result.X25519PublicKey); - Assert.AreEqual(entityToTest.Signature, result.Signature); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void TestMapRightToLeft_ThrowsWhenNull() - { - VpnServerIpcEntity entityToTest = null; + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void TestMapRightToLeft_ThrowsWhenNull() + { + VpnServerIpcEntity entityToTest = null; - _mapper.Map(entityToTest); - } + _mapper.Map(entityToTest); + } - [TestMethod] - public void TestMapRightToLeft() + [TestMethod] + public void TestMapRightToLeft() + { + VpnServerIpcEntity entityToTest = new() { - VpnServerIpcEntity entityToTest = new() - { - Name = "protonvpn.com", - Ip = "192.168.0.0", - Label = DateTime.UtcNow.Millisecond.ToString(), - X25519PublicKey = new ServerPublicKeyIpcEntity(), - Signature = DateTime.UtcNow.Ticks.ToString() - }; - - VpnHost result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(entityToTest.Name, result.Name); - Assert.AreEqual(entityToTest.Ip, result.Ip); - Assert.AreEqual(entityToTest.Label, result.Label); - Assert.AreEqual(_expectedPublicKey, result.X25519PublicKey); - Assert.AreEqual(entityToTest.Signature, result.Signature); - } + Name = "protonvpn.com", + Ip = "192.168.0.0", + Label = DateTime.UtcNow.Millisecond.ToString(), + X25519PublicKey = new ServerPublicKeyIpcEntity(), + Signature = DateTime.UtcNow.Ticks.ToString() + }; + + VpnHost result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(entityToTest.Name, result.Name); + Assert.AreEqual(entityToTest.Ip, result.Ip); + Assert.AreEqual(entityToTest.Label, result.Label); + Assert.AreEqual(_expectedPublicKey, result.X25519PublicKey); + Assert.AreEqual(entityToTest.Signature, result.Signature); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnStateChangedEventArgsMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnStateChangedEventArgsMapperTest.cs index b5345afe6..e92bedf79 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnStateChangedEventArgsMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnStateChangedEventArgsMapperTest.cs @@ -27,173 +27,172 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class VpnStateChangedEventArgsMapperTest { - [TestClass] - public class VpnStateChangedEventArgsMapperTest + private IEntityMapper _entityMapper; + private VpnStateChangedEventArgsMapper _mapper; + + private VpnStatusIpcEntity? _expectedVpnStatusIpcEntity; + private VpnErrorTypeIpcEntity? _expectedVpnErrorTypeIpcEntity; + private OpenVpnAdapterIpcEntity? _expectedOpenVpnAdapterIpcEntity; + private VpnProtocolIpcEntity? _expectedVpnProtocolIpcEntity; + private VpnStatus? _expectedVpnStatus; + private VpnError? _expectedVpnError; + private OpenVpnAdapter? _expectedOpenVpnAdapter; + private VpnProtocol? _expectedVpnProtocol; + + [TestInitialize] + public void Initialize() + { + _entityMapper = Substitute.For(); + _mapper = new(_entityMapper); + + _expectedVpnStatusIpcEntity = VpnStatusIpcEntity.Connecting; + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnStatusIpcEntity.Value); + + _expectedVpnErrorTypeIpcEntity = VpnErrorTypeIpcEntity.TapAdapterInUseError; + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnErrorTypeIpcEntity.Value); + + _expectedOpenVpnAdapterIpcEntity = OpenVpnAdapterIpcEntity.Tun; + _entityMapper.MapNullableStruct(Arg.Any()) + .Returns(_expectedOpenVpnAdapterIpcEntity); + + _expectedVpnProtocolIpcEntity = VpnProtocolIpcEntity.OpenVpnUdp; + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnProtocolIpcEntity.Value); + + _expectedVpnStatus = VpnStatus.Authenticating; + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnStatus.Value); + + _expectedVpnError = VpnError.CertificateRevoked; + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnError.Value); + + _expectedOpenVpnAdapter = OpenVpnAdapter.Tun; + _entityMapper.MapNullableStruct(Arg.Any()) + .Returns(_expectedOpenVpnAdapter); + + _expectedVpnProtocol = VpnProtocol.OpenVpnTcp; + _entityMapper.Map(Arg.Any()) + .Returns(_expectedVpnProtocol.Value); + } + + [TestCleanup] + public void Cleanup() + { + _entityMapper = null; + _mapper = null; + + _expectedVpnStatusIpcEntity = null; + _expectedVpnErrorTypeIpcEntity = null; + _expectedOpenVpnAdapterIpcEntity = null; + _expectedVpnProtocolIpcEntity = null; + _expectedVpnStatus = null; + _expectedVpnError = null; + _expectedOpenVpnAdapter = null; + _expectedVpnProtocol = null; + } + + [TestMethod] + public void TestMapLeftToRight_UsingMultipleArgumentConstructor() + { + VpnStateChangedEventArgs entityToTest = new( + status: VpnStatus.AssigningIp, + error: VpnError.TlsError, + endpointIp: "192.168.0.0", + networkBlocked: true, + vpnProtocol: VpnProtocol.OpenVpnTcp, + networkAdapterType: OpenVpnAdapter.Tun, + label: "Proton VPN"); + + VpnStateIpcEntity result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(_expectedVpnStatusIpcEntity, result.Status); + Assert.AreEqual(_expectedVpnErrorTypeIpcEntity, result.Error); + Assert.AreEqual(entityToTest.NetworkBlocked, result.NetworkBlocked); + Assert.AreEqual(entityToTest.State.EntryIp, result.EndpointIp); + Assert.AreEqual(_expectedOpenVpnAdapterIpcEntity, result.OpenVpnAdapterType); + Assert.AreEqual(_expectedVpnProtocolIpcEntity, result.VpnProtocol); + Assert.AreEqual(entityToTest.State.Label, result.Label); + } + + [TestMethod] + public void TestMapLeftToRight_UsingStateArgumentConstructor() + { + VpnStateChangedEventArgs entityToTest = new( + status: VpnStatus.Authenticating, + error: VpnError.NoServers, + server: Server.Empty(), + networkBlocked: true); + + VpnStateIpcEntity result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(_expectedVpnStatusIpcEntity, result.Status); + Assert.AreEqual(_expectedVpnErrorTypeIpcEntity, result.Error); + Assert.AreEqual(entityToTest.NetworkBlocked, result.NetworkBlocked); + Assert.AreEqual(entityToTest.State.EntryIp, result.EndpointIp); + Assert.AreEqual(_expectedOpenVpnAdapterIpcEntity, result.OpenVpnAdapterType); + Assert.AreEqual(_expectedVpnProtocolIpcEntity, result.VpnProtocol); + Assert.AreEqual(entityToTest.State.Label, result.Label); + } + + [TestMethod] + public void TestMapLeftToRight_UsingVpnStateArgumentConstructor() { - private IEntityMapper _entityMapper; - private VpnStateChangedEventArgsMapper _mapper; - - private VpnStatusIpcEntity? _expectedVpnStatusIpcEntity; - private VpnErrorTypeIpcEntity? _expectedVpnErrorTypeIpcEntity; - private OpenVpnAdapterIpcEntity? _expectedOpenVpnAdapterIpcEntity; - private VpnProtocolIpcEntity? _expectedVpnProtocolIpcEntity; - private VpnStatus? _expectedVpnStatus; - private VpnError? _expectedVpnError; - private OpenVpnAdapter? _expectedOpenVpnAdapter; - private VpnProtocol? _expectedVpnProtocol; - - [TestInitialize] - public void Initialize() - { - _entityMapper = Substitute.For(); - _mapper = new(_entityMapper); - - _expectedVpnStatusIpcEntity = VpnStatusIpcEntity.Connecting; - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnStatusIpcEntity.Value); - - _expectedVpnErrorTypeIpcEntity = VpnErrorTypeIpcEntity.TapAdapterInUseError; - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnErrorTypeIpcEntity.Value); - - _expectedOpenVpnAdapterIpcEntity = OpenVpnAdapterIpcEntity.Tun; - _entityMapper.MapNullableStruct(Arg.Any()) - .Returns(_expectedOpenVpnAdapterIpcEntity); - - _expectedVpnProtocolIpcEntity = VpnProtocolIpcEntity.OpenVpnUdp; - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnProtocolIpcEntity.Value); - - _expectedVpnStatus = VpnStatus.Authenticating; - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnStatus.Value); - - _expectedVpnError = VpnError.CertificateRevoked; - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnError.Value); - - _expectedOpenVpnAdapter = OpenVpnAdapter.Tun; - _entityMapper.MapNullableStruct(Arg.Any()) - .Returns(_expectedOpenVpnAdapter); - - _expectedVpnProtocol = VpnProtocol.OpenVpnTcp; - _entityMapper.Map(Arg.Any()) - .Returns(_expectedVpnProtocol.Value); - } - - [TestCleanup] - public void Cleanup() - { - _entityMapper = null; - _mapper = null; - - _expectedVpnStatusIpcEntity = null; - _expectedVpnErrorTypeIpcEntity = null; - _expectedOpenVpnAdapterIpcEntity = null; - _expectedVpnProtocolIpcEntity = null; - _expectedVpnStatus = null; - _expectedVpnError = null; - _expectedOpenVpnAdapter = null; - _expectedVpnProtocol = null; - } - - [TestMethod] - public void TestMapLeftToRight_UsingMultipleArgumentConstructor() - { - VpnStateChangedEventArgs entityToTest = new( - status: VpnStatus.AssigningIp, - error: VpnError.TlsError, - endpointIp: "192.168.0.0", - networkBlocked: true, - vpnProtocol: VpnProtocol.OpenVpnTcp, + VpnStateChangedEventArgs entityToTest = new( + state: new VpnState( + status: VpnStatus.RetrievingConfiguration, + entryIp: "172.16.0.0", + vpnProtocol: VpnProtocol.WireGuardUdp, networkAdapterType: OpenVpnAdapter.Tun, - label: "Proton VPN"); - - VpnStateIpcEntity result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(_expectedVpnStatusIpcEntity, result.Status); - Assert.AreEqual(_expectedVpnErrorTypeIpcEntity, result.Error); - Assert.AreEqual(entityToTest.NetworkBlocked, result.NetworkBlocked); - Assert.AreEqual(entityToTest.State.EntryIp, result.EndpointIp); - Assert.AreEqual(_expectedOpenVpnAdapterIpcEntity, result.OpenVpnAdapterType); - Assert.AreEqual(_expectedVpnProtocolIpcEntity, result.VpnProtocol); - Assert.AreEqual(entityToTest.State.Label, result.Label); - } - - [TestMethod] - public void TestMapLeftToRight_UsingStateArgumentConstructor() - { - VpnStateChangedEventArgs entityToTest = new( - status: VpnStatus.Authenticating, - error: VpnError.NoServers, - server: Server.Empty(), - networkBlocked: true); - - VpnStateIpcEntity result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(_expectedVpnStatusIpcEntity, result.Status); - Assert.AreEqual(_expectedVpnErrorTypeIpcEntity, result.Error); - Assert.AreEqual(entityToTest.NetworkBlocked, result.NetworkBlocked); - Assert.AreEqual(entityToTest.State.EntryIp, result.EndpointIp); - Assert.AreEqual(_expectedOpenVpnAdapterIpcEntity, result.OpenVpnAdapterType); - Assert.AreEqual(_expectedVpnProtocolIpcEntity, result.VpnProtocol); - Assert.AreEqual(entityToTest.State.Label, result.Label); - } - - [TestMethod] - public void TestMapLeftToRight_UsingVpnStateArgumentConstructor() - { - VpnStateChangedEventArgs entityToTest = new( - state: new VpnState( - status: VpnStatus.RetrievingConfiguration, - entryIp: "172.16.0.0", - vpnProtocol: VpnProtocol.WireGuardUdp, - networkAdapterType: OpenVpnAdapter.Tun, - label: "Proton VPN" - ), - error: VpnError.IncorrectVpnConfig, - networkBlocked: true); - - VpnStateIpcEntity result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(_expectedVpnStatusIpcEntity, result.Status); - Assert.AreEqual(_expectedVpnErrorTypeIpcEntity, result.Error); - Assert.AreEqual(entityToTest.NetworkBlocked, result.NetworkBlocked); - Assert.AreEqual(entityToTest.State.EntryIp, result.EndpointIp); - Assert.AreEqual(_expectedOpenVpnAdapterIpcEntity, result.OpenVpnAdapterType); - Assert.AreEqual(_expectedVpnProtocolIpcEntity, result.VpnProtocol); - Assert.AreEqual(entityToTest.State.Label, result.Label); - } - - [TestMethod] - [ExpectedException(typeof(ArgumentNullException))] - public void TestMapRightToLeft_ThrowsWhenNull() - { - VpnStateIpcEntity entityToTest = null; - - _mapper.Map(entityToTest); - } - - [TestMethod] - public void TestMapRightToLeft() - { - VpnStateIpcEntity entityToTest = new(); - - VpnStateChangedEventArgs result = _mapper.Map(entityToTest); - - Assert.IsNotNull(result); - Assert.AreEqual(_expectedVpnStatus, result.State.Status); - Assert.AreEqual(_expectedVpnError, result.Error); - Assert.AreEqual(entityToTest.NetworkBlocked, result.NetworkBlocked); - Assert.AreEqual(entityToTest.EndpointIp, result.State.EntryIp); - Assert.AreEqual(_expectedOpenVpnAdapter, result.State.NetworkAdapterType); - Assert.AreEqual(_expectedVpnProtocol, result.State.VpnProtocol); - Assert.AreEqual(entityToTest.Label, result.State.Label); - } + label: "Proton VPN" + ), + error: VpnError.Unknown, + networkBlocked: true); + + VpnStateIpcEntity result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(_expectedVpnStatusIpcEntity, result.Status); + Assert.AreEqual(_expectedVpnErrorTypeIpcEntity, result.Error); + Assert.AreEqual(entityToTest.NetworkBlocked, result.NetworkBlocked); + Assert.AreEqual(entityToTest.State.EntryIp, result.EndpointIp); + Assert.AreEqual(_expectedOpenVpnAdapterIpcEntity, result.OpenVpnAdapterType); + Assert.AreEqual(_expectedVpnProtocolIpcEntity, result.VpnProtocol); + Assert.AreEqual(entityToTest.State.Label, result.Label); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void TestMapRightToLeft_ThrowsWhenNull() + { + VpnStateIpcEntity entityToTest = null; + + _mapper.Map(entityToTest); + } + + [TestMethod] + public void TestMapRightToLeft() + { + VpnStateIpcEntity entityToTest = new(); + + VpnStateChangedEventArgs result = _mapper.Map(entityToTest); + + Assert.IsNotNull(result); + Assert.AreEqual(_expectedVpnStatus, result.State.Status); + Assert.AreEqual(_expectedVpnError, result.Error); + Assert.AreEqual(entityToTest.NetworkBlocked, result.NetworkBlocked); + Assert.AreEqual(entityToTest.EndpointIp, result.State.EntryIp); + Assert.AreEqual(_expectedOpenVpnAdapter, result.State.NetworkAdapterType); + Assert.AreEqual(_expectedVpnProtocol, result.State.VpnProtocol); + Assert.AreEqual(entityToTest.Label, result.State.Label); } } diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnStatusMapperTest.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnStatusMapperTest.cs index 2f5ea795c..f3ea84e14 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnStatusMapperTest.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnStatusMapperTest.cs @@ -24,14 +24,13 @@ using ProtonVPN.ProcessCommunication.EntityMapping.Tests.Common; using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Tests.Vpn; + +[TestClass] +public class VpnStatusMapperTest : EnumMapperTestBase { - [TestClass] - public class VpnStatusMapperTest : EnumMapperTestBase + protected override IMapper CreateMapper() { - protected override IMapper CreateMapper() - { - return new VpnStatusMapper(); - } + return new VpnStatusMapper(); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/AsymmetricKeyPairMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/AsymmetricKeyPairMapper.cs index 55e341e74..8700474e2 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/AsymmetricKeyPairMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/AsymmetricKeyPairMapper.cs @@ -21,39 +21,38 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Crypto +namespace ProtonVPN.ProcessCommunication.EntityMapping.Crypto; + +public class AsymmetricKeyPairMapper : IMapper { - public class AsymmetricKeyPairMapper : IMapper + private readonly IEntityMapper _entityMapper; + + public AsymmetricKeyPairMapper(IEntityMapper entityMapper) { - private readonly IEntityMapper _entityMapper; + _entityMapper = entityMapper; + } - public AsymmetricKeyPairMapper(IEntityMapper entityMapper) + public AsymmetricKeyPairIpcEntity Map(AsymmetricKeyPair leftEntity) + { + if (leftEntity is null || leftEntity.SecretKey is null || leftEntity.PublicKey is null) { - _entityMapper = entityMapper; + return null; } - - public AsymmetricKeyPairIpcEntity Map(AsymmetricKeyPair leftEntity) + return new AsymmetricKeyPairIpcEntity() { - if (leftEntity is null || leftEntity.SecretKey is null || leftEntity.PublicKey is null) - { - return null; - } - return new AsymmetricKeyPairIpcEntity() - { - SecretKey = _entityMapper.Map(leftEntity.SecretKey), - PublicKey = _entityMapper.Map(leftEntity.PublicKey), - }; - } + SecretKey = _entityMapper.Map(leftEntity.SecretKey), + PublicKey = _entityMapper.Map(leftEntity.PublicKey), + }; + } - public AsymmetricKeyPair Map(AsymmetricKeyPairIpcEntity rightEntity) + public AsymmetricKeyPair Map(AsymmetricKeyPairIpcEntity rightEntity) + { + if (rightEntity is null || rightEntity.SecretKey is null || rightEntity.PublicKey is null) { - if (rightEntity is null || rightEntity.SecretKey is null || rightEntity.PublicKey is null) - { - return null; - } - return new AsymmetricKeyPair( - _entityMapper.Map(rightEntity.SecretKey), - _entityMapper.Map(rightEntity.PublicKey)); + return null; } + return new AsymmetricKeyPair( + _entityMapper.Map(rightEntity.SecretKey), + _entityMapper.Map(rightEntity.PublicKey)); } -} \ No newline at end of file +} diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/KeyMapperBase.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/KeyMapperBase.cs index 58cb7628d..ac1100174 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/KeyMapperBase.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/KeyMapperBase.cs @@ -21,20 +21,19 @@ using ProtonVPN.Crypto; using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Crypto +namespace ProtonVPN.ProcessCommunication.EntityMapping.Crypto; + +public abstract class KeyMapperBase + where TIpcEntity : KeyIpcEntity, new() { - public abstract class KeyMapperBase - where TIpcEntity : KeyIpcEntity, new() + protected TIpcEntity MapKeyToIpcEntity(Key key) { - protected TIpcEntity MapKeyToIpcEntity(Key key) + return new() { - return new() - { - Bytes = key.Bytes, - Base64 = key.Base64, - Algorithm = key.Algorithm.ToString().ToEnum(), - Pem = key.Pem, - }; - } + Bytes = key.Bytes, + Base64 = key.Base64, + Algorithm = key.Algorithm.ToString().ToEnum(), + Pem = key.Pem, + }; } -} \ No newline at end of file +} diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/PublicKeyMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/PublicKeyMapper.cs index 94f238f03..b1be47b38 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/PublicKeyMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/PublicKeyMapper.cs @@ -21,24 +21,23 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Crypto +namespace ProtonVPN.ProcessCommunication.EntityMapping.Crypto; + +public class PublicKeyMapper : KeyMapperBase, IMapper { - public class PublicKeyMapper : KeyMapperBase, IMapper + public PublicKeyIpcEntity Map(PublicKey leftEntity) { - public PublicKeyIpcEntity Map(PublicKey leftEntity) - { - return leftEntity is null - ? null - : MapKeyToIpcEntity(leftEntity); - } + return leftEntity is null + ? null + : MapKeyToIpcEntity(leftEntity); + } - public PublicKey Map(PublicKeyIpcEntity rightEntity) - { - return rightEntity is null - ? null - : rightEntity.Base64 is null - ? new(rightEntity.Bytes, (KeyAlgorithm)rightEntity.Algorithm) - : new(rightEntity.Base64, (KeyAlgorithm)rightEntity.Algorithm); - } + public PublicKey Map(PublicKeyIpcEntity rightEntity) + { + return rightEntity is null + ? null + : rightEntity.Base64 is null + ? new(rightEntity.Bytes, (KeyAlgorithm)rightEntity.Algorithm) + : new(rightEntity.Base64, (KeyAlgorithm)rightEntity.Algorithm); } -} \ No newline at end of file +} diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/SecretKeyMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/SecretKeyMapper.cs index 3378c2f34..67689e263 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/SecretKeyMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/SecretKeyMapper.cs @@ -21,24 +21,23 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Crypto +namespace ProtonVPN.ProcessCommunication.EntityMapping.Crypto; + +public class SecretKeyMapper : KeyMapperBase, IMapper { - public class SecretKeyMapper : KeyMapperBase, IMapper + public SecretKeyIpcEntity Map(SecretKey leftEntity) { - public SecretKeyIpcEntity Map(SecretKey leftEntity) - { - return leftEntity is null - ? null - : MapKeyToIpcEntity(leftEntity); - } + return leftEntity is null + ? null + : MapKeyToIpcEntity(leftEntity); + } - public SecretKey Map(SecretKeyIpcEntity rightEntity) - { - return rightEntity is null - ? null - : rightEntity.Base64 is null - ? new(rightEntity.Bytes, (KeyAlgorithm)rightEntity.Algorithm) - : new(rightEntity.Base64, (KeyAlgorithm)rightEntity.Algorithm); - } + public SecretKey Map(SecretKeyIpcEntity rightEntity) + { + return rightEntity is null + ? null + : rightEntity.Base64 is null + ? new(rightEntity.Bytes, (KeyAlgorithm)rightEntity.Algorithm) + : new(rightEntity.Base64, (KeyAlgorithm)rightEntity.Algorithm); } -} \ No newline at end of file +} diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/ServerPublicKeyMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/ServerPublicKeyMapper.cs index 85f88173f..b3e84a36e 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/ServerPublicKeyMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Crypto/ServerPublicKeyMapper.cs @@ -21,25 +21,23 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Crypto +namespace ProtonVPN.ProcessCommunication.EntityMapping.Crypto; + +public class ServerPublicKeyMapper : KeyMapperBase, IMapper { - public class ServerPublicKeyMapper : KeyMapperBase, IMapper + public ServerPublicKeyIpcEntity Map(PublicKey leftEntity) { - public ServerPublicKeyIpcEntity Map(PublicKey leftEntity) - { - return leftEntity is null - ? null - : MapKeyToIpcEntity(leftEntity); - } - - public PublicKey Map(ServerPublicKeyIpcEntity rightEntity) - { - return rightEntity is null - ? null - : rightEntity.Base64 is null - ? new(rightEntity.Bytes, (KeyAlgorithm)rightEntity.Algorithm) - : new(rightEntity.Base64, (KeyAlgorithm)rightEntity.Algorithm); - } + return leftEntity is null + ? null + : MapKeyToIpcEntity(leftEntity); } -} + public PublicKey Map(ServerPublicKeyIpcEntity rightEntity) + { + return rightEntity is null + ? null + : rightEntity.Base64 is null + ? new(rightEntity.Bytes, (KeyAlgorithm)rightEntity.Algorithm) + : new(rightEntity.Base64, (KeyAlgorithm)rightEntity.Algorithm); + } +} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/GuestHole/GuestHoleServerMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/GuestHole/GuestHoleServerMapper.cs new file mode 100644 index 000000000..1184f9e69 --- /dev/null +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/GuestHole/GuestHoleServerMapper.cs @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using ProtonVPN.Core.Servers.Contracts; +using ProtonVPN.EntityMapping.Contracts; +using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; + +namespace ProtonVPN.ProcessCommunication.EntityMapping.GuestHole; + +public class GuestHoleServerMapper : IMapper +{ + public VpnServerIpcEntity Map(GuestHoleServerContract leftEntity) + { + return leftEntity is null + ? null + : new VpnServerIpcEntity() + { + Name = leftEntity.Host, + Ip = leftEntity.Ip, + Label = leftEntity.Label, + Signature = leftEntity.Signature, + X25519PublicKey = null + }; + } + + public GuestHoleServerContract Map(VpnServerIpcEntity rightEntity) + { + return rightEntity is null + ? null + : new GuestHoleServerContract() + { + Host = rightEntity.Name, + Ip = rightEntity.Ip, + Label = rightEntity.Label, + Signature = rightEntity.Signature + }; + } +} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/NetShield/NetShieldStatisticMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/NetShield/NetShieldStatisticMapper.cs index e014852bf..8e99aca8d 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/NetShield/NetShieldStatisticMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/NetShield/NetShieldStatisticMapper.cs @@ -21,34 +21,33 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.NetShield; -namespace ProtonVPN.ProcessCommunication.EntityMapping.NetShield +namespace ProtonVPN.ProcessCommunication.EntityMapping.NetShield; + +public class NetShieldStatisticMapper : IMapper { - public class NetShieldStatisticMapper : IMapper + public NetShieldStatisticIpcEntity Map(NetShieldStatistic leftEntity) { - public NetShieldStatisticIpcEntity Map(NetShieldStatistic leftEntity) - { - return leftEntity is null - ? null - : new NetShieldStatisticIpcEntity() - { - NumOfMaliciousUrlsBlocked = leftEntity.NumOfMaliciousUrlsBlocked, - NumOfAdvertisementUrlsBlocked = leftEntity.NumOfAdvertisementUrlsBlocked, - NumOfTrackingUrlsBlocked = leftEntity.NumOfTrackingUrlsBlocked, - TimestampUtc = leftEntity.TimestampUtc, - }; - } + return leftEntity is null + ? null + : new NetShieldStatisticIpcEntity() + { + NumOfMaliciousUrlsBlocked = leftEntity.NumOfMaliciousUrlsBlocked, + NumOfAdvertisementUrlsBlocked = leftEntity.NumOfAdvertisementUrlsBlocked, + NumOfTrackingUrlsBlocked = leftEntity.NumOfTrackingUrlsBlocked, + TimestampUtc = leftEntity.TimestampUtc, + }; + } - public NetShieldStatistic Map(NetShieldStatisticIpcEntity rightEntity) - { - return rightEntity is null - ? null - : new NetShieldStatistic() - { - NumOfMaliciousUrlsBlocked = rightEntity.NumOfMaliciousUrlsBlocked, - NumOfAdvertisementUrlsBlocked = rightEntity.NumOfAdvertisementUrlsBlocked, - NumOfTrackingUrlsBlocked = rightEntity.NumOfTrackingUrlsBlocked, - TimestampUtc = rightEntity.TimestampUtc, - }; - } + public NetShieldStatistic Map(NetShieldStatisticIpcEntity rightEntity) + { + return rightEntity is null + ? null + : new NetShieldStatistic() + { + NumOfMaliciousUrlsBlocked = rightEntity.NumOfMaliciousUrlsBlocked, + NumOfAdvertisementUrlsBlocked = rightEntity.NumOfAdvertisementUrlsBlocked, + NumOfTrackingUrlsBlocked = rightEntity.NumOfTrackingUrlsBlocked, + TimestampUtc = rightEntity.TimestampUtc, + }; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/PortForwardingStateMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/PortForwardingStateMapper.cs index d08b63608..6dc4dfd6b 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/PortForwardingStateMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/PortForwardingStateMapper.cs @@ -21,39 +21,38 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.PortForwarding; -namespace ProtonVPN.ProcessCommunication.EntityMapping.PortForwarding +namespace ProtonVPN.ProcessCommunication.EntityMapping.PortForwarding; + +public class PortForwardingStateMapper : IMapper { - public class PortForwardingStateMapper : IMapper - { - private readonly IEntityMapper _entityMapper; + private readonly IEntityMapper _entityMapper; - public PortForwardingStateMapper(IEntityMapper entityMapper) - { - _entityMapper = entityMapper; - } + public PortForwardingStateMapper(IEntityMapper entityMapper) + { + _entityMapper = entityMapper; + } - public PortForwardingStateIpcEntity Map(PortForwardingState leftEntity) - { - return leftEntity is null - ? null - : new PortForwardingStateIpcEntity() - { - MappedPort = _entityMapper.Map(leftEntity.MappedPort), - Status = _entityMapper.Map(leftEntity.Status), - TimestampUtc = leftEntity.TimestampUtc, - }; - } + public PortForwardingStateIpcEntity Map(PortForwardingState leftEntity) + { + return leftEntity is null + ? null + : new PortForwardingStateIpcEntity() + { + MappedPort = _entityMapper.Map(leftEntity.MappedPort), + Status = _entityMapper.Map(leftEntity.Status), + TimestampUtc = leftEntity.TimestampUtc, + }; + } - public PortForwardingState Map(PortForwardingStateIpcEntity rightEntity) - { - return rightEntity is null - ? null - : new PortForwardingState() - { - MappedPort = _entityMapper.Map(rightEntity.MappedPort), - Status = _entityMapper.Map(rightEntity.Status), - TimestampUtc = rightEntity.TimestampUtc, - }; - } + public PortForwardingState Map(PortForwardingStateIpcEntity rightEntity) + { + return rightEntity is null + ? null + : new PortForwardingState() + { + MappedPort = _entityMapper.Map(rightEntity.MappedPort), + Status = _entityMapper.Map(rightEntity.Status), + TimestampUtc = rightEntity.TimestampUtc, + }; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/PortMappingStatusMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/PortMappingStatusMapper.cs index 2170f7d0b..aa575d914 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/PortMappingStatusMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/PortMappingStatusMapper.cs @@ -21,18 +21,17 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.PortForwarding; -namespace ProtonVPN.ProcessCommunication.EntityMapping.PortForwarding +namespace ProtonVPN.ProcessCommunication.EntityMapping.PortForwarding; + +public class PortMappingStatusMapper : IMapper { - public class PortMappingStatusMapper : IMapper + public PortMappingStatusIpcEntity Map(PortMappingStatus leftEntity) { - public PortMappingStatusIpcEntity Map(PortMappingStatus leftEntity) - { - return (PortMappingStatusIpcEntity)leftEntity; - } + return (PortMappingStatusIpcEntity)leftEntity; + } - public PortMappingStatus Map(PortMappingStatusIpcEntity rightEntity) - { - return (PortMappingStatus)rightEntity; - } + public PortMappingStatus Map(PortMappingStatusIpcEntity rightEntity) + { + return (PortMappingStatus)rightEntity; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/TemporaryMappedPortMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/TemporaryMappedPortMapper.cs index c3ad42cea..44bed7423 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/TemporaryMappedPortMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/PortForwarding/TemporaryMappedPortMapper.cs @@ -21,33 +21,32 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.PortForwarding; -namespace ProtonVPN.ProcessCommunication.EntityMapping.PortForwarding +namespace ProtonVPN.ProcessCommunication.EntityMapping.PortForwarding; + +public class TemporaryMappedPortMapper : IMapper { - public class TemporaryMappedPortMapper : IMapper + public TemporaryMappedPortIpcEntity Map(TemporaryMappedPort leftEntity) { - public TemporaryMappedPortIpcEntity Map(TemporaryMappedPort leftEntity) - { - return leftEntity?.MappedPort is null - ? null - : new TemporaryMappedPortIpcEntity() - { - InternalPort = leftEntity.MappedPort.InternalPort, - ExternalPort = leftEntity.MappedPort.ExternalPort, - Lifetime = leftEntity.Lifetime, - ExpirationDateUtc = leftEntity.ExpirationDateUtc, - }; - } + return leftEntity?.MappedPort is null + ? null + : new TemporaryMappedPortIpcEntity() + { + InternalPort = leftEntity.MappedPort.InternalPort, + ExternalPort = leftEntity.MappedPort.ExternalPort, + Lifetime = leftEntity.Lifetime, + ExpirationDateUtc = leftEntity.ExpirationDateUtc, + }; + } - public TemporaryMappedPort Map(TemporaryMappedPortIpcEntity rightEntity) - { - return rightEntity is null - ? null - : new TemporaryMappedPort() - { - MappedPort = new MappedPort(internalPort: rightEntity.InternalPort, externalPort: rightEntity.ExternalPort), - Lifetime = rightEntity.Lifetime, - ExpirationDateUtc = rightEntity.ExpirationDateUtc, - }; - } + public TemporaryMappedPort Map(TemporaryMappedPortIpcEntity rightEntity) + { + return rightEntity is null + ? null + : new TemporaryMappedPort() + { + MappedPort = new MappedPort(internalPort: rightEntity.InternalPort, externalPort: rightEntity.ExternalPort), + Lifetime = rightEntity.Lifetime, + ExpirationDateUtc = rightEntity.ExpirationDateUtc, + }; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/ProtonVPN.ProcessCommunication.EntityMapping.csproj b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/ProtonVPN.ProcessCommunication.EntityMapping.csproj index eea427e69..794356bf3 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/ProtonVPN.ProcessCommunication.EntityMapping.csproj +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/ProtonVPN.ProcessCommunication.EntityMapping.csproj @@ -1,23 +1,21 @@ - - - - net6.0-windows - enable - ..\..\bin - false - Library - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - + + + net8.0-windows + enable + ..\..\bin + false + Library + false + AnyCPU;ARM64 + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Update/ReleaseMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Update/ReleaseMapper.cs index 7416d9867..94ec88cf6 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Update/ReleaseMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Update/ReleaseMapper.cs @@ -21,32 +21,31 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Update; using ProtonVPN.Update.Contracts; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Update +namespace ProtonVPN.ProcessCommunication.EntityMapping.Update; + +public class ReleaseMapper : IMapper { - public class ReleaseMapper : IMapper + public ReleaseIpcEntity Map(ReleaseContract leftEntity) { - public ReleaseIpcEntity Map(ReleaseContract leftEntity) + return new ReleaseIpcEntity { - return new ReleaseIpcEntity - { - ChangeLog = leftEntity.ChangeLog.ToArray(), - EarlyAccess = leftEntity.EarlyAccess, - New = leftEntity.New, - Version = leftEntity.Version.ToString(), - }; - } + ChangeLog = leftEntity.ChangeLog.ToArray(), + EarlyAccess = leftEntity.EarlyAccess, + New = leftEntity.New, + Version = leftEntity.Version.ToString(), + }; + } - public ReleaseContract Map(ReleaseIpcEntity rightEntity) - { - bool isVersionValid = Version.TryParse(rightEntity.Version, out Version version); + public ReleaseContract Map(ReleaseIpcEntity rightEntity) + { + bool isVersionValid = Version.TryParse(rightEntity.Version, out Version version); - return new ReleaseContract - { - ChangeLog = rightEntity.ChangeLog, - EarlyAccess = rightEntity.EarlyAccess, - New = rightEntity.New, - Version = isVersionValid ? version : new Version(), - }; - } + return new ReleaseContract + { + ChangeLog = rightEntity.ChangeLog, + EarlyAccess = rightEntity.EarlyAccess, + New = rightEntity.New, + Version = isVersionValid ? version : new Version(), + }; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Update/UpdateStateMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Update/UpdateStateMapper.cs index 7b731d05e..e417d8e3e 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Update/UpdateStateMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Update/UpdateStateMapper.cs @@ -21,43 +21,42 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Update; using ProtonVPN.Update.Contracts; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Update +namespace ProtonVPN.ProcessCommunication.EntityMapping.Update; + +public class UpdateStateMapper : IMapper { - public class UpdateStateMapper : IMapper - { - private readonly IEntityMapper _entityMapper; + private readonly IEntityMapper _entityMapper; - public UpdateStateMapper(IEntityMapper entityMapper) - { - _entityMapper = entityMapper; - } + public UpdateStateMapper(IEntityMapper entityMapper) + { + _entityMapper = entityMapper; + } - public UpdateStateIpcEntity Map(AppUpdateStateContract leftEntity) + public UpdateStateIpcEntity Map(AppUpdateStateContract leftEntity) + { + return new UpdateStateIpcEntity { - return new UpdateStateIpcEntity - { - IsAvailable = leftEntity.IsAvailable, - FileArguments = leftEntity.FileArguments, - FilePath = leftEntity.FilePath, - Version = leftEntity.Version.ToString(), - IsReady = leftEntity.IsReady, - ReleaseHistory = _entityMapper.Map(leftEntity.ReleaseHistory).ToArray(), - Status = (UpdateStatusIpcEntity)leftEntity.Status, - }; - } + IsAvailable = leftEntity.IsAvailable, + FileArguments = leftEntity.FileArguments, + FilePath = leftEntity.FilePath, + Version = leftEntity.Version.ToString(), + IsReady = leftEntity.IsReady, + ReleaseHistory = _entityMapper.Map(leftEntity.ReleaseHistory).ToArray(), + Status = (UpdateStatusIpcEntity)leftEntity.Status, + }; + } - public AppUpdateStateContract Map(UpdateStateIpcEntity rightEntity) + public AppUpdateStateContract Map(UpdateStateIpcEntity rightEntity) + { + return new AppUpdateStateContract { - return new AppUpdateStateContract - { - IsAvailable = rightEntity.IsAvailable, - FileArguments = rightEntity.FileArguments, - FilePath = rightEntity.FilePath, - Version = new Version(rightEntity.Version), - IsReady = rightEntity.IsReady, - Status = (AppUpdateStatus)rightEntity.Status, - ReleaseHistory = _entityMapper.Map(rightEntity.ReleaseHistory) - }; - } + IsAvailable = rightEntity.IsAvailable, + FileArguments = rightEntity.FileArguments, + FilePath = rightEntity.FilePath, + Version = new Version(rightEntity.Version), + IsReady = rightEntity.IsReady, + Status = (AppUpdateStatus)rightEntity.Status, + ReleaseHistory = _entityMapper.Map(rightEntity.ReleaseHistory) + }; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/ConnectionDetailsMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/ConnectionDetailsMapper.cs index a22abbee4..3bbffdb40 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/ConnectionDetailsMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/ConnectionDetailsMapper.cs @@ -21,32 +21,31 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class ConnectionDetailsMapper : IMapper { - public class ConnectionDetailsMapper : IMapper + public ConnectionDetailsIpcEntity Map(ConnectionDetails leftEntity) { - public ConnectionDetailsIpcEntity Map(ConnectionDetails leftEntity) - { - return leftEntity is null - ? null - : new ConnectionDetailsIpcEntity() - { - ClientIpAddress = leftEntity.ClientIpAddress, - ClientCountryIsoCode = leftEntity.ClientCountryIsoCode, - ServerIpAddress = leftEntity.ServerIpAddress, - }; - } + return leftEntity is null + ? null + : new ConnectionDetailsIpcEntity() + { + ClientIpAddress = leftEntity.ClientIpAddress, + ClientCountryIsoCode = leftEntity.ClientCountryIsoCode, + ServerIpAddress = leftEntity.ServerIpAddress, + }; + } - public ConnectionDetails Map(ConnectionDetailsIpcEntity rightEntity) - { - return rightEntity is null - ? null - : new ConnectionDetails - { - ClientIpAddress = rightEntity.ClientIpAddress, - ClientCountryIsoCode = rightEntity.ClientCountryIsoCode, - ServerIpAddress = rightEntity.ServerIpAddress, - }; - } + public ConnectionDetails Map(ConnectionDetailsIpcEntity rightEntity) + { + return rightEntity is null + ? null + : new ConnectionDetails + { + ClientIpAddress = rightEntity.ClientIpAddress, + ClientCountryIsoCode = rightEntity.ClientCountryIsoCode, + ServerIpAddress = rightEntity.ServerIpAddress, + }; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/ConnectionRequestMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/ConnectionRequestMapper.cs index b1a8f55b3..0a01c7470 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/ConnectionRequestMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/ConnectionRequestMapper.cs @@ -23,39 +23,39 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class ConnectionRequestMapper : IMapper { - public class ConnectionRequestMapper : IMapper - { - private readonly IEntityMapper _entityMapper; + private readonly IEntityMapper _entityMapper; - public ConnectionRequestMapper(IEntityMapper entityMapper) - { - _entityMapper = entityMapper; - } + public ConnectionRequestMapper(IEntityMapper entityMapper) + { + _entityMapper = entityMapper; + } - public ConnectionRequestIpcEntity Map(VpnConnectionRequest leftEntity) - { - return leftEntity is null - ? null - : new() + public ConnectionRequestIpcEntity Map(VpnConnectionRequest leftEntity) + { + return leftEntity is null + ? null + : new() { + RetryId = Guid.NewGuid(), Servers = _entityMapper.Map(leftEntity.Servers).ToArray(), Protocol = _entityMapper.Map(leftEntity.VpnProtocol), Config = _entityMapper.Map(leftEntity.Config), Credentials = _entityMapper.Map(leftEntity.Credentials) }; - } + } - public VpnConnectionRequest Map(ConnectionRequestIpcEntity rightEntity) - { - return rightEntity is null - ? null - : new( - servers: _entityMapper.Map(rightEntity.Servers), - vpnProtocol: _entityMapper.Map(rightEntity.Protocol), - config: _entityMapper.Map(rightEntity.Config), - credentials: _entityMapper.Map(rightEntity.Credentials)); - } + public VpnConnectionRequest Map(ConnectionRequestIpcEntity rightEntity) + { + return rightEntity is null + ? null + : new( + servers: _entityMapper.Map(rightEntity.Servers), + vpnProtocol: _entityMapper.Map(rightEntity.Protocol), + config: _entityMapper.Map(rightEntity.Config), + credentials: _entityMapper.Map(rightEntity.Credentials)); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/KillSwitchModeMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/KillSwitchModeMapper.cs index e530ca3b4..252dff7a2 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/KillSwitchModeMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/KillSwitchModeMapper.cs @@ -21,30 +21,29 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class KillSwitchModeMapper : IMapper { - public class KillSwitchModeMapper : IMapper + public KillSwitchModeIpcEntity Map(KillSwitchMode leftEntity) { - public KillSwitchModeIpcEntity Map(KillSwitchMode leftEntity) + return leftEntity switch { - return leftEntity switch - { - KillSwitchMode.Off => KillSwitchModeIpcEntity.Off, - KillSwitchMode.Soft => KillSwitchModeIpcEntity.Soft, - KillSwitchMode.Hard => KillSwitchModeIpcEntity.Hard, - _ => throw new NotImplementedException("KillSwitchMode has an unknown value.") - }; - } + KillSwitchMode.Off => KillSwitchModeIpcEntity.Off, + KillSwitchMode.Soft => KillSwitchModeIpcEntity.Soft, + KillSwitchMode.Hard => KillSwitchModeIpcEntity.Hard, + _ => throw new NotImplementedException("KillSwitchMode has an unknown value.") + }; + } - public KillSwitchMode Map(KillSwitchModeIpcEntity rightEntity) + public KillSwitchMode Map(KillSwitchModeIpcEntity rightEntity) + { + return rightEntity switch { - return rightEntity switch - { - KillSwitchModeIpcEntity.Off => KillSwitchMode.Off, - KillSwitchModeIpcEntity.Soft => KillSwitchMode.Soft, - KillSwitchModeIpcEntity.Hard => KillSwitchMode.Hard, - _ => throw new NotImplementedException("KillSwitchMode has an unknown value.") - }; - } + KillSwitchModeIpcEntity.Off => KillSwitchMode.Off, + KillSwitchModeIpcEntity.Soft => KillSwitchMode.Soft, + KillSwitchModeIpcEntity.Hard => KillSwitchMode.Hard, + _ => throw new NotImplementedException("KillSwitchMode has an unknown value.") + }; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/OpenVpnAdapterMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/OpenVpnAdapterMapper.cs index aee0f262e..0024d03bc 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/OpenVpnAdapterMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/OpenVpnAdapterMapper.cs @@ -21,28 +21,27 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class OpenVpnAdapterMapper : IMapper { - public class OpenVpnAdapterMapper : IMapper + public OpenVpnAdapterIpcEntity Map(OpenVpnAdapter leftEntity) { - public OpenVpnAdapterIpcEntity Map(OpenVpnAdapter leftEntity) + return leftEntity switch { - return leftEntity switch - { - OpenVpnAdapter.Tap => OpenVpnAdapterIpcEntity.Tap, - OpenVpnAdapter.Tun => OpenVpnAdapterIpcEntity.Tun, - _ => throw new NotImplementedException("OpenVpnAdapter has an unknown value.") - }; - } + OpenVpnAdapter.Tap => OpenVpnAdapterIpcEntity.Tap, + OpenVpnAdapter.Tun => OpenVpnAdapterIpcEntity.Tun, + _ => throw new NotImplementedException("OpenVpnAdapter has an unknown value.") + }; + } - public OpenVpnAdapter Map(OpenVpnAdapterIpcEntity rightEntity) + public OpenVpnAdapter Map(OpenVpnAdapterIpcEntity rightEntity) + { + return rightEntity switch { - return rightEntity switch - { - OpenVpnAdapterIpcEntity.Tap => OpenVpnAdapter.Tap, - OpenVpnAdapterIpcEntity.Tun => OpenVpnAdapter.Tun, - _ => throw new NotImplementedException("OpenVpnAdapter has an unknown value.") - }; - } + OpenVpnAdapterIpcEntity.Tap => OpenVpnAdapter.Tap, + OpenVpnAdapterIpcEntity.Tun => OpenVpnAdapter.Tun, + _ => throw new NotImplementedException("OpenVpnAdapter has an unknown value.") + }; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/SplitTunnelModeMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/SplitTunnelModeMapper.cs index 2fe6393af..0336dc063 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/SplitTunnelModeMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/SplitTunnelModeMapper.cs @@ -21,30 +21,29 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class SplitTunnelModeMapper : IMapper { - public class SplitTunnelModeMapper : IMapper + public SplitTunnelModeIpcEntity Map(SplitTunnelMode leftEntity) { - public SplitTunnelModeIpcEntity Map(SplitTunnelMode leftEntity) + return leftEntity switch { - return leftEntity switch - { - SplitTunnelMode.Disabled => SplitTunnelModeIpcEntity.Disabled, - SplitTunnelMode.Block => SplitTunnelModeIpcEntity.Block, - SplitTunnelMode.Permit => SplitTunnelModeIpcEntity.Permit, - _ => throw new NotImplementedException("SplitTunnelMode has an unknown value.") - }; - } + SplitTunnelMode.Disabled => SplitTunnelModeIpcEntity.Disabled, + SplitTunnelMode.Block => SplitTunnelModeIpcEntity.Block, + SplitTunnelMode.Permit => SplitTunnelModeIpcEntity.Permit, + _ => throw new NotImplementedException("SplitTunnelMode has an unknown value.") + }; + } - public SplitTunnelMode Map(SplitTunnelModeIpcEntity rightEntity) + public SplitTunnelMode Map(SplitTunnelModeIpcEntity rightEntity) + { + return rightEntity switch { - return rightEntity switch - { - SplitTunnelModeIpcEntity.Disabled => SplitTunnelMode.Disabled, - SplitTunnelModeIpcEntity.Block => SplitTunnelMode.Block, - SplitTunnelModeIpcEntity.Permit => SplitTunnelMode.Permit, - _ => throw new NotImplementedException("SplitTunnelMode has an unknown value.") - }; - } + SplitTunnelModeIpcEntity.Disabled => SplitTunnelMode.Disabled, + SplitTunnelModeIpcEntity.Block => SplitTunnelMode.Block, + SplitTunnelModeIpcEntity.Permit => SplitTunnelMode.Permit, + _ => throw new NotImplementedException("SplitTunnelMode has an unknown value.") + }; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/TrafficBytesMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/TrafficBytesMapper.cs index f84c70e2a..0bdd26ab7 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/TrafficBytesMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/TrafficBytesMapper.cs @@ -21,20 +21,19 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class TrafficBytesMapper : IMapper { - public class TrafficBytesMapper : IMapper + public TrafficBytesIpcEntity Map(InOutBytes leftEntity) { - public TrafficBytesIpcEntity Map(InOutBytes leftEntity) - { - return new() { BytesIn = leftEntity.BytesIn, BytesOut = leftEntity.BytesOut }; - } + return new() { BytesIn = (ulong)leftEntity.BytesIn, BytesOut = (ulong)leftEntity.BytesOut }; + } - public InOutBytes Map(TrafficBytesIpcEntity rightEntity) - { - return rightEntity is null - ? InOutBytes.Zero - : new(bytesIn: rightEntity.BytesIn, bytesOut: rightEntity.BytesOut); - } + public InOutBytes Map(TrafficBytesIpcEntity rightEntity) + { + return rightEntity is null + ? InOutBytes.Zero + : new(bytesIn: rightEntity.BytesIn, bytesOut: rightEntity.BytesOut); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnConfigMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnConfigMapper.cs index 5391bfe0c..d71e06792 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnConfigMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnConfigMapper.cs @@ -23,70 +23,79 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class VpnConfigMapper : IMapper { - public class VpnConfigMapper : IMapper + private const bool DEFAULT_SPLIT_TCP_VALUE = true; + + private readonly IEntityMapper _entityMapper; + + public VpnConfigMapper(IEntityMapper entityMapper) { - private readonly IEntityMapper _entityMapper; + _entityMapper = entityMapper; + } - public VpnConfigMapper(IEntityMapper entityMapper) + public VpnConfigIpcEntity Map(VpnConfig leftEntity) + { + if (leftEntity is null) { - _entityMapper = entityMapper; + throw new ArgumentNullException(nameof(VpnConfig), + $"The {nameof(VpnConfig)} parameter cannot be mapped from null to {nameof(VpnConfigIpcEntity)}."); } + Dictionary portConfig = leftEntity.Ports.ToDictionary( + p => _entityMapper.Map(p.Key), + p => ReadOnlyCollectionToArray(p.Value)); - public VpnConfigIpcEntity Map(VpnConfig leftEntity) + return new VpnConfigIpcEntity { - if (leftEntity is null) - { - throw new ArgumentNullException(nameof(VpnConfig), - $"The {nameof(VpnConfig)} parameter cannot be mapped from null to {nameof(VpnConfigIpcEntity)}."); - } - Dictionary portConfig = leftEntity.Ports.ToDictionary( - p => _entityMapper.Map(p.Key), - p => p.Value.ToArray()); + Ports = portConfig, + CustomDns = leftEntity.CustomDns.ToList(), + SplitTunnelMode = _entityMapper.Map(leftEntity.SplitTunnelMode), + SplitTunnelIPs = leftEntity.SplitTunnelIPs.ToList(), + NetShieldMode = leftEntity.NetShieldMode, + VpnProtocol = _entityMapper.Map(leftEntity.VpnProtocol), + ModerateNat = leftEntity.ModerateNat, + PreferredProtocols = _entityMapper.Map(leftEntity.PreferredProtocols), + SplitTcp = leftEntity.SplitTcp ?? DEFAULT_SPLIT_TCP_VALUE, + PortForwarding = leftEntity.PortForwarding, + }; + } - return new VpnConfigIpcEntity - { - Ports = portConfig, - CustomDns = leftEntity.CustomDns.ToList(), - AllowNonStandardPorts = leftEntity.AllowNonStandardPorts, - SplitTunnelMode = _entityMapper.Map(leftEntity.SplitTunnelMode), - SplitTunnelIPs = leftEntity.SplitTunnelIPs.ToList(), - NetShieldMode = leftEntity.NetShieldMode, - VpnProtocol = _entityMapper.Map(leftEntity.VpnProtocol), - ModerateNat = leftEntity.ModerateNat, - PreferredProtocols = _entityMapper.Map(leftEntity.PreferredProtocols), - SplitTcp = leftEntity.SplitTcp, - PortForwarding = leftEntity.PortForwarding, - }; - } + private static int[] ReadOnlyCollectionToArray(IReadOnlyCollection? collection) + { + return collection?.ToArray() ?? []; + } - public VpnConfig Map(VpnConfigIpcEntity rightEntity) + public VpnConfig Map(VpnConfigIpcEntity rightEntity) + { + if (rightEntity is null) { - if (rightEntity is null) + throw new ArgumentNullException(nameof(VpnConfigIpcEntity), + $"The {nameof(VpnConfigIpcEntity)} parameter cannot be mapped from null to {nameof(VpnConfig)}."); + } + Dictionary> portConfig = rightEntity.Ports.ToDictionary( + p => _entityMapper.Map(p.Key), + p => ArrayToReadOnlyCollection(p.Value)); + + return new VpnConfig( + new VpnConfigParameters { - throw new ArgumentNullException(nameof(VpnConfigIpcEntity), - $"The {nameof(VpnConfigIpcEntity)} parameter cannot be mapped from null to {nameof(VpnConfig)}."); - } - Dictionary> portConfig = rightEntity.Ports.ToDictionary( - p => _entityMapper.Map(p.Key), - p => (IReadOnlyCollection)p.Value.ToList()); + Ports = portConfig, + CustomDns = rightEntity.CustomDns, + SplitTunnelMode = _entityMapper.Map(rightEntity.SplitTunnelMode), + SplitTunnelIPs = rightEntity.SplitTunnelIPs, + VpnProtocol = _entityMapper.Map(rightEntity.VpnProtocol), + PreferredProtocols = _entityMapper.Map(rightEntity.PreferredProtocols), + ModerateNat = rightEntity.ModerateNat, + NetShieldMode = rightEntity.NetShieldMode, + SplitTcp = rightEntity.SplitTcp, + PortForwarding = rightEntity.PortForwarding, + }); + } - return new VpnConfig( - new VpnConfigParameters - { - Ports = portConfig, - CustomDns = rightEntity.CustomDns, - SplitTunnelMode = _entityMapper.Map(rightEntity.SplitTunnelMode), - SplitTunnelIPs = rightEntity.SplitTunnelIPs, - VpnProtocol = _entityMapper.Map(rightEntity.VpnProtocol), - PreferredProtocols = _entityMapper.Map(rightEntity.PreferredProtocols), - ModerateNat = rightEntity.ModerateNat, - NetShieldMode = rightEntity.NetShieldMode, - SplitTcp = rightEntity.SplitTcp, - AllowNonStandardPorts = rightEntity.AllowNonStandardPorts, - PortForwarding = rightEntity.PortForwarding, - }); - } + private static IReadOnlyCollection ArrayToReadOnlyCollection(int[]? array) + { + return (IReadOnlyCollection)array?.ToList() ?? []; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnCredentialsMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnCredentialsMapper.cs index 5b41cb5a3..57253fa6f 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnCredentialsMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnCredentialsMapper.cs @@ -23,31 +23,33 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class VpnCredentialsMapper : IMapper { - public class VpnCredentialsMapper : IMapper - { - private readonly IEntityMapper _entityMapper; + private readonly IEntityMapper _entityMapper; - public VpnCredentialsMapper(IEntityMapper entityMapper) - { - _entityMapper = entityMapper; - } + public VpnCredentialsMapper(IEntityMapper entityMapper) + { + _entityMapper = entityMapper; + } - public VpnCredentialsIpcEntity Map(VpnCredentials leftEntity) + public VpnCredentialsIpcEntity Map(VpnCredentials leftEntity) + { + return new() { - return new() - { - ClientCertPem = leftEntity.ClientCertPem, - ClientKeyPair = _entityMapper.Map(leftEntity.ClientKeyPair) - }; - } + Certificate = new() + { + Pem = leftEntity.ClientCertPem ?? string.Empty, + ExpirationDateUtc = DateTime.MinValue, + }, + ClientKeyPair = _entityMapper.Map(leftEntity.ClientKeyPair) + }; + } - public VpnCredentials Map(VpnCredentialsIpcEntity rightEntity) - { - return rightEntity is null - ? throw new ArgumentNullException($"The {nameof(VpnCredentialsIpcEntity)} to be mapped is null.") - : new(rightEntity.ClientCertPem, _entityMapper.Map(rightEntity.ClientKeyPair)); - } + public VpnCredentials Map(VpnCredentialsIpcEntity rightEntity) + { + return new(rightEntity.Certificate.Pem, + _entityMapper.Map(rightEntity.ClientKeyPair)); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnErrorTypeMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnErrorMapper.cs similarity index 68% rename from src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnErrorTypeMapper.cs rename to src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnErrorMapper.cs index f3b16a798..234f1f606 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnErrorTypeMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnErrorMapper.cs @@ -21,18 +21,17 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class VpnErrorMapper : IMapper { - public class VpnErrorTypeMapper : IMapper + public VpnErrorTypeIpcEntity Map(VpnError leftEntity) { - public VpnErrorTypeIpcEntity Map(VpnError leftEntity) - { - return (VpnErrorTypeIpcEntity)leftEntity; - } + return (VpnErrorTypeIpcEntity)leftEntity; + } - public VpnError Map(VpnErrorTypeIpcEntity rightEntity) - { - return (VpnError)rightEntity; - } + public VpnError Map(VpnErrorTypeIpcEntity rightEntity) + { + return (VpnError)rightEntity; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnProtocolMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnProtocolMapper.cs index 3b94621f7..53c681ff8 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnProtocolMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnProtocolMapper.cs @@ -21,36 +21,35 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class VpnProtocolMapper : IMapper { - public class VpnProtocolMapper : IMapper + public VpnProtocolIpcEntity Map(VpnProtocol leftEntity) { - public VpnProtocolIpcEntity Map(VpnProtocol leftEntity) + return leftEntity switch { - return leftEntity switch - { - VpnProtocol.OpenVpnUdp => VpnProtocolIpcEntity.OpenVpnUdp, - VpnProtocol.OpenVpnTcp => VpnProtocolIpcEntity.OpenVpnTcp, - VpnProtocol.WireGuardUdp => VpnProtocolIpcEntity.WireGuardUdp, - VpnProtocol.WireGuardTcp => VpnProtocolIpcEntity.WireGuardTcp, - VpnProtocol.WireGuardTls => VpnProtocolIpcEntity.WireGuardTls, - VpnProtocol.Smart => VpnProtocolIpcEntity.Smart, - _ => throw new NotImplementedException("VpnProtocol has an unknown value.") - }; - } + VpnProtocol.OpenVpnUdp => VpnProtocolIpcEntity.OpenVpnUdp, + VpnProtocol.OpenVpnTcp => VpnProtocolIpcEntity.OpenVpnTcp, + VpnProtocol.WireGuardUdp => VpnProtocolIpcEntity.WireGuardUdp, + VpnProtocol.WireGuardTcp => VpnProtocolIpcEntity.WireGuardTcp, + VpnProtocol.WireGuardTls => VpnProtocolIpcEntity.WireGuardTls, + VpnProtocol.Smart => VpnProtocolIpcEntity.Smart, + _ => throw new NotImplementedException("VpnProtocol has an unknown value.") + }; + } - public VpnProtocol Map(VpnProtocolIpcEntity rightEntity) + public VpnProtocol Map(VpnProtocolIpcEntity rightEntity) + { + return rightEntity switch { - return rightEntity switch - { - VpnProtocolIpcEntity.OpenVpnTcp => VpnProtocol.OpenVpnTcp, - VpnProtocolIpcEntity.OpenVpnUdp => VpnProtocol.OpenVpnUdp, - VpnProtocolIpcEntity.WireGuardUdp => VpnProtocol.WireGuardUdp, - VpnProtocolIpcEntity.WireGuardTcp => VpnProtocol.WireGuardTcp, - VpnProtocolIpcEntity.WireGuardTls => VpnProtocol.WireGuardTls, - VpnProtocolIpcEntity.Smart => VpnProtocol.Smart, - _ => throw new NotImplementedException("VpnProtocol has an unknown value."), - }; - } + VpnProtocolIpcEntity.OpenVpnTcp => VpnProtocol.OpenVpnTcp, + VpnProtocolIpcEntity.OpenVpnUdp => VpnProtocol.OpenVpnUdp, + VpnProtocolIpcEntity.WireGuardUdp => VpnProtocol.WireGuardUdp, + VpnProtocolIpcEntity.WireGuardTcp => VpnProtocol.WireGuardTcp, + VpnProtocolIpcEntity.WireGuardTls => VpnProtocol.WireGuardTls, + VpnProtocolIpcEntity.Smart => VpnProtocol.Smart, + _ => throw new NotImplementedException("VpnProtocol has an unknown value."), + }; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnServerMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnServerMapper.cs index 23309c08d..33a68e3ea 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnServerMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnServerMapper.cs @@ -23,38 +23,37 @@ using ProtonVPN.ProcessCommunication.Contracts.Entities.Crypto; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class VpnServerMapper : IMapper { - public class VpnServerMapper : IMapper - { - private readonly IEntityMapper _entityMapper; + private readonly IEntityMapper _entityMapper; - public VpnServerMapper(IEntityMapper entityMapper) - { - _entityMapper = entityMapper; - } + public VpnServerMapper(IEntityMapper entityMapper) + { + _entityMapper = entityMapper; + } - public VpnServerIpcEntity Map(VpnHost leftEntity) + public VpnServerIpcEntity Map(VpnHost leftEntity) + { + return new() { - return new() - { - Name = leftEntity.Name, - Ip = leftEntity.Ip, - Label = leftEntity.Label, - X25519PublicKey = _entityMapper.Map(leftEntity.X25519PublicKey), - Signature = leftEntity.Signature, - }; - } + Name = leftEntity.Name, + Ip = leftEntity.Ip, + Label = leftEntity.Label, + X25519PublicKey = _entityMapper.Map(leftEntity.X25519PublicKey), + Signature = leftEntity.Signature, + }; + } - public VpnHost Map(VpnServerIpcEntity rightEntity) + public VpnHost Map(VpnServerIpcEntity rightEntity) + { + if (rightEntity is null) { - if (rightEntity is null) - { - throw new ArgumentNullException(nameof(VpnServerIpcEntity), - $"The {nameof(VpnServerIpcEntity)} parameter cannot be mapped from null to {nameof(VpnHost)}."); - } - return new(rightEntity.Name, rightEntity.Ip, rightEntity.Label, - _entityMapper.Map(rightEntity.X25519PublicKey), rightEntity.Signature); + throw new ArgumentNullException(nameof(VpnServerIpcEntity), + $"The {nameof(VpnServerIpcEntity)} parameter cannot be mapped from null to {nameof(VpnHost)}."); } + return new(rightEntity.Name, rightEntity.Ip, rightEntity.Label, + _entityMapper.Map(rightEntity.X25519PublicKey), rightEntity.Signature); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnStateChangedEventArgsMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnStateChangedEventArgsMapper.cs index da276fe44..5e584d5c5 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnStateChangedEventArgsMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnStateChangedEventArgsMapper.cs @@ -23,46 +23,45 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class VpnStateChangedEventArgsMapper : IMapper { - public class VpnStateChangedEventArgsMapper : IMapper - { - private readonly IEntityMapper _entityMapper; + private readonly IEntityMapper _entityMapper; - public VpnStateChangedEventArgsMapper(IEntityMapper entityMapper) - { - _entityMapper = entityMapper; - } + public VpnStateChangedEventArgsMapper(IEntityMapper entityMapper) + { + _entityMapper = entityMapper; + } - public VpnStateIpcEntity Map(VpnStateChangedEventArgs leftEntity) + public VpnStateIpcEntity Map(VpnStateChangedEventArgs leftEntity) + { + return new VpnStateIpcEntity() { - return new VpnStateIpcEntity() - { - Status = _entityMapper.Map(leftEntity.State.Status), - Error = _entityMapper.Map(leftEntity.Error), - NetworkBlocked = leftEntity.NetworkBlocked, - EndpointIp = leftEntity.State.EntryIp, - OpenVpnAdapterType = _entityMapper.MapNullableStruct(leftEntity.State.NetworkAdapterType), - VpnProtocol = _entityMapper.Map(leftEntity.State.VpnProtocol), - Label = leftEntity.State.Label - }; - } + Status = _entityMapper.Map(leftEntity.State.Status), + Error = _entityMapper.Map(leftEntity.Error), + NetworkBlocked = leftEntity.NetworkBlocked, + EndpointIp = leftEntity.State.EntryIp, + OpenVpnAdapterType = _entityMapper.MapNullableStruct(leftEntity.State.NetworkAdapterType), + VpnProtocol = _entityMapper.Map(leftEntity.State.VpnProtocol), + Label = leftEntity.State.Label + }; + } - public VpnStateChangedEventArgs Map(VpnStateIpcEntity rightEntity) + public VpnStateChangedEventArgs Map(VpnStateIpcEntity rightEntity) + { + if (rightEntity is null) { - if (rightEntity is null) - { - throw new ArgumentNullException(nameof(VpnStateIpcEntity), - $"The {nameof(VpnStateIpcEntity)} parameter cannot be mapped from null to {nameof(VpnStateChangedEventArgs)}."); - } - return new VpnStateChangedEventArgs( - status: _entityMapper.Map(rightEntity.Status), - error: _entityMapper.Map(rightEntity.Error), - endpointIp: rightEntity.EndpointIp, - networkBlocked: rightEntity.NetworkBlocked, - vpnProtocol: _entityMapper.Map(rightEntity.VpnProtocol), - networkAdapterType: _entityMapper.MapNullableStruct(rightEntity.OpenVpnAdapterType), - label: rightEntity.Label); + throw new ArgumentNullException(nameof(VpnStateIpcEntity), + $"The {nameof(VpnStateIpcEntity)} parameter cannot be mapped from null to {nameof(VpnStateChangedEventArgs)}."); } + return new VpnStateChangedEventArgs( + status: _entityMapper.Map(rightEntity.Status), + error: _entityMapper.Map(rightEntity.Error), + endpointIp: rightEntity.EndpointIp, + networkBlocked: rightEntity.NetworkBlocked, + vpnProtocol: _entityMapper.Map(rightEntity.VpnProtocol), + networkAdapterType: _entityMapper.MapNullableStruct(rightEntity.OpenVpnAdapterType), + label: rightEntity.Label); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnStatusMapper.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnStatusMapper.cs index 2694c9ab5..ec1ade68e 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnStatusMapper.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnStatusMapper.cs @@ -21,18 +21,17 @@ using ProtonVPN.EntityMapping.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; -namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn +namespace ProtonVPN.ProcessCommunication.EntityMapping.Vpn; + +public class VpnStatusMapper : IMapper { - public class VpnStatusMapper : IMapper + public VpnStatusIpcEntity Map(VpnStatus leftEntity) { - public VpnStatusIpcEntity Map(VpnStatus leftEntity) - { - return (VpnStatusIpcEntity)leftEntity; - } + return (VpnStatusIpcEntity)leftEntity; + } - public VpnStatus Map(VpnStatusIpcEntity rightEntity) - { - return (VpnStatus)rightEntity; - } + public VpnStatus Map(VpnStatusIpcEntity rightEntity) + { + return (VpnStatus)rightEntity; } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Installers/ProcessCommunicationModule.cs b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Installers/ProcessCommunicationModule.cs index 1b70b6fcb..ef251c3d2 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Installers/ProcessCommunicationModule.cs +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Installers/ProcessCommunicationModule.cs @@ -18,26 +18,15 @@ */ using Autofac; -using ProtonVPN.EntityMapping.Contracts; -using ProtonVPN.ProcessCommunication.Common.Channels; -using ProtonVPN.ProcessCommunication.Common.Registration; -using ProtonVPN.ProcessCommunication.EntityMapping.Crypto; +using ProtonVPN.EntityMapping.Common.Installers.Extensions; +using ProtonVPN.ProcessCommunication.EntityMapping.Vpn; -namespace ProtonVPN.ProcessCommunication.Installers +namespace ProtonVPN.ProcessCommunication.Installers; + +public class ProcessCommunicationModule : Module { - public class ProcessCommunicationModule : Module + protected override void Load(ContainerBuilder builder) { - protected override void Load(ContainerBuilder builder) - { - builder.RegisterType().AsImplementedInterfaces().SingleInstance(); - - builder.RegisterType().AsImplementedInterfaces().SingleInstance(); - builder.RegisterType().AsImplementedInterfaces().SingleInstance(); - - builder.RegisterAssemblyTypes(typeof(AsymmetricKeyPairMapper).Assembly) - .Where(t => typeof(IMapper).IsAssignableFrom(t)) - .AsImplementedInterfaces() - .SingleInstance(); - } + builder.RegisterAllMappersInAssembly(); } } \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Installers/ProtonVPN.ProcessCommunication.Installers.csproj b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Installers/ProtonVPN.ProcessCommunication.Installers.csproj index 0952015b1..9f1d3df1d 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Installers/ProtonVPN.ProcessCommunication.Installers.csproj +++ b/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Installers/ProtonVPN.ProcessCommunication.Installers.csproj @@ -1,24 +1,23 @@ - - - - net6.0-windows - enable - ..\..\bin - false - Library - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - - + + + net8.0-windows + enable + ..\..\bin + false + Library + false + AnyCPU;ARM64 + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + \ No newline at end of file diff --git a/src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server.Installers/ProtonVPN.ProcessCommunication.Server.Installers.csproj b/src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server.Installers/ProtonVPN.ProcessCommunication.Server.Installers.csproj new file mode 100644 index 000000000..d3e28c966 --- /dev/null +++ b/src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server.Installers/ProtonVPN.ProcessCommunication.Server.Installers.csproj @@ -0,0 +1,23 @@ + + + net8.0-windows + enable + ..\..\..\bin + false + Library + false + AnyCPU;ARM64 + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IServiceGrpcClient.cs b/src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server.Installers/ServerProcessCommunicationModule.cs similarity index 66% rename from src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IServiceGrpcClient.cs rename to src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server.Installers/ServerProcessCommunicationModule.cs index 2466b766f..f0a7de298 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/IServiceGrpcClient.cs +++ b/src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server.Installers/ServerProcessCommunicationModule.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Proton AG + * Copyright (c) 2024 Proton AG * * This file is part of ProtonVPN. * @@ -16,16 +16,16 @@ * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ -using ProtonVPN.ProcessCommunication.Contracts.Controllers; -namespace ProtonVPN.ProcessCommunication.Contracts +using Autofac; +using ProtonVPN.ProcessCommunication.Contracts; + +namespace ProtonVPN.ProcessCommunication.Server.Installers; + +public class ServerProcessCommunicationModule : Module { - public interface IServiceGrpcClient + protected override void Load(ContainerBuilder builder) { - IAppController? AppController { get; } - - Task CreateAsync(int serverPort); - Task RecreateAsync(); - bool IsRecreatable(); + builder.RegisterType().As().SingleInstance(); } } \ No newline at end of file diff --git a/src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server/GrpcServer.cs b/src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server/GrpcServer.cs new file mode 100644 index 000000000..870507f03 --- /dev/null +++ b/src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server/GrpcServer.cs @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.IO.Pipes; +using System.Security.AccessControl; +using System.Security.Principal; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Connections; +using Microsoft.AspNetCore.Connections.Features; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using ProtoBuf.Grpc.Server; +using ProtonVPN.Common.Configuration; +using ProtonVPN.Common.Extensions; +using ProtonVPN.Crypto; +using ProtonVPN.Logging.Contracts.Events.ProcessCommunicationLogs; +using ProtonVPN.OperatingSystems.Processes.Contracts; +using ProtonVPN.OperatingSystems.Registries.Contracts; +using ProtonVPN.ProcessCommunication.Common; +using ProtonVPN.ProcessCommunication.Contracts; +using ProtonVPN.ProcessCommunication.Contracts.Controllers; +using ILogger = ProtonVPN.Logging.Contracts.ILogger; + +namespace ProtonVPN.ProcessCommunication.Server; + +public class GrpcServer : IGrpcServer +{ + // AUTHENTICATED_USERS - A group that includes all users whose identities were authenticated + // when they logged on. Users authenticated as Guest or Anonymous are not members of this group. + private const string AUTHENTICATED_USERS_SID = "S-1-5-11"; + + private readonly RegistryUri _registryUri = RegistryUri.CreateLocalMachineUri( + NamedPipeConfiguration.REGISTRY_PATH, NamedPipeConfiguration.REGISTRY_KEY); + + private readonly ILogger _logger; + private readonly IClientController _clientController; + private readonly IUpdateController _updateController; + private readonly IVpnController _vpnController; + private readonly IUiController _uiController; + private readonly IPipeStreamProcessIdentifier _pipeStreamProcessIdentifier; + private readonly IConfiguration _config; + private readonly IRegistryEditor _registryEditor; + + private WebApplication _app; + private CancellationTokenSource _cancellationTokenSource = new(); + + public GrpcServer(ILogger logger, + IClientController clientController, + IUpdateController updateController, + IVpnController vpnController, + IUiController uiController, + IPipeStreamProcessIdentifier pipeStreamProcessIdentifier, + IConfiguration configuration, + IRegistryEditor registryEditor) + { + _logger = logger; + _clientController = clientController; + _updateController = updateController; + _vpnController = vpnController; + _uiController = uiController; + _pipeStreamProcessIdentifier = pipeStreamProcessIdentifier; + _config = configuration; + _registryEditor = registryEditor; + } + + public void CreateAndStart() + { + if (!_cancellationTokenSource.Token.IsCancellationRequested) + { + _app = Create(); + _app.RunAsync().ContinueWith(t => RetryAsync()).IgnoreExceptions(); + } + } + + private async Task RetryAsync() + { + await Task.Delay(TimeSpan.FromSeconds(3), _cancellationTokenSource.Token); + CreateAndStart(); + } + + public async Task StopAsync() + { + _cancellationTokenSource.Cancel(); + DeletePipeNameFromRegistry(); + + // The code below is kept commented to remind why it should not be done. Stopping the gRPC server gracefully + // leads to the client side Stream to take a long time to detect the server is down. When the gRPC server + // suddenly dies as in this case or if the service is killed, the client side Stream immediately detects it. + //await _app?.StopAsync(); + } + + private WebApplication Create() + { + DeletePipeNameFromRegistry(); + string pipeName = GeneratePipeName(); + WebApplicationBuilder builder = WebApplication.CreateBuilder(); + builder.Logging.ClearProviders(); + ConfigureKestrel(builder, pipeName); + PipeSecurity pipeSecurity = CreatePipeSecurity(); + ConfigureNamedPipes(builder, pipeSecurity); + + builder.Services.AddSingleton(_clientController); + builder.Services.AddSingleton(_updateController); + builder.Services.AddSingleton(_vpnController); + builder.Services.AddSingleton(_uiController); + builder.Services.AddCodeFirstGrpc(); + + WebApplication app = builder.Build(); + + app.MapGrpcService(); + app.MapGrpcService(); + app.MapGrpcService(); + app.MapGrpcService(); + + app.Lifetime.ApplicationStarted.Register(() => WritePipeNameToRegistry(pipeName)); + app.Lifetime.ApplicationStopping.Register(DeletePipeNameFromRegistry); + + return app; + } + + private void ConfigureKestrel(WebApplicationBuilder builder, string pipeName) + { + builder.WebHost.ConfigureKestrel(serverOptions => + { + serverOptions.Listen(new NamedPipeEndPoint(pipeName), listenOptions => + { + listenOptions.Protocols = HttpProtocols.Http2; + listenOptions.Use((ConnectionContext context, Func next) => + { + return RequestDelegateAsync(context, next); + }); + }); + }); + } + + private string GeneratePipeName() + { + return $"ProtonVPN-{HashGenerator.GenerateRandomString(32)}"; + } + + private async Task RequestDelegateAsync(ConnectionContext context, Func next) + { + if (!IsAuthorized(context)) + { + context.Abort(); + } + + await next(); + } + + private bool IsAuthorized(ConnectionContext context) + { + if (context is IConnectionNamedPipeFeature connectionNamedPipeFeature) + { + string clientProcessFileName = _pipeStreamProcessIdentifier.GetClientProcessFileName(connectionNamedPipeFeature.NamedPipe) ?? string.Empty; + string serverProcessFileName = _pipeStreamProcessIdentifier.GetServerProcessFileName(connectionNamedPipeFeature.NamedPipe) ?? string.Empty; + + if (!_config.ServiceExePath.Equals(serverProcessFileName, StringComparison.InvariantCultureIgnoreCase)) + { + _logger.Warn("The owner of the Named Pipe is not this Service. Dispose and recreate."); + _app.DisposeAsync(); + RetryAsync(); + return false; + } + + if (_config.AppExePath.Equals(clientProcessFileName, StringComparison.InvariantCultureIgnoreCase)) + { + return true; + } + + _logger.Warn($"The connected client is unauthorized ({clientProcessFileName})."); + } + + return false; + } + + private PipeSecurity CreatePipeSecurity() + { + SecurityIdentifier targetSid = new(AUTHENTICATED_USERS_SID); + + PipeSecurity pipeSecurity = new(); + pipeSecurity.AddAccessRule( + new PipeAccessRule( + targetSid, + PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, + AccessControlType.Allow + ) + ); + + return pipeSecurity; + } + + private void ConfigureNamedPipes(WebApplicationBuilder builder, PipeSecurity pipeSecurity) + { + builder.WebHost.UseNamedPipes(serverOptions => + { + serverOptions.PipeSecurity = pipeSecurity; + serverOptions.CurrentUserOnly = false; + serverOptions.MaxWriteBufferSize = 100 * 1024 * 1024; // 100MB + serverOptions.MaxReadBufferSize = 100 * 1024 * 1024; // 100MB + serverOptions.ListenerQueueCount = 1; + }); + } + + private void WritePipeNameToRegistry(string pipeName) + { + _registryEditor.WriteString(_registryUri, pipeName); + } + + private void DeletePipeNameFromRegistry() + { + _registryEditor.Delete(_registryUri); + } +} diff --git a/src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server/ProtonVPN.ProcessCommunication.Server.csproj b/src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server/ProtonVPN.ProcessCommunication.Server.csproj new file mode 100644 index 000000000..75e5f0406 --- /dev/null +++ b/src/ProcessCommunication/Server/ProtonVPN.ProcessCommunication.Server/ProtonVPN.ProcessCommunication.Server.csproj @@ -0,0 +1,27 @@ + + + net8.0-windows + enable + ..\..\..\bin + false + Library + false + AnyCPU;ARM64 + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Installers/ProtonVPN.ProcessCommunication.Service.Installers.csproj b/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Installers/ProtonVPN.ProcessCommunication.Service.Installers.csproj deleted file mode 100644 index bd3fcfcf1..000000000 --- a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Installers/ProtonVPN.ProcessCommunication.Service.Installers.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net6.0-windows - enable - ..\..\..\bin - false - Library - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - - diff --git a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Tests/GrpcServerTest.cs b/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Tests/GrpcServerTest.cs deleted file mode 100644 index b39d15a3f..000000000 --- a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Tests/GrpcServerTest.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using Microsoft.VisualStudio.TestTools.UnitTesting; -using NSubstitute; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.ProcessCommunication.Common.Tests; -using ProtonVPN.ProcessCommunication.Contracts; -using ProtonVPN.ProcessCommunication.Contracts.Controllers; -using ProtonVPN.ProcessCommunication.Contracts.Registration; - -namespace ProtonVPN.ProcessCommunication.Service.Tests -{ - [TestClass] - public class GrpcServerTest : GrpcServerTestBase - { - private ILogger _logger; - private IVpnController _vpnController; - private IUpdateController _updateController; - private IServiceServerPortRegister _serviceServerPortRegister; - private IAppServerPortRegister _appServerPortRegister; - - [TestInitialize] - public override void Initialize() - { - _logger = Substitute.For(); - _vpnController = Substitute.For(); - _updateController = Substitute.For(); - _serviceServerPortRegister = Substitute.For(); - _appServerPortRegister = Substitute.For(); - base.Initialize(); - } - - protected override IGrpcServer CreateGrpcServer() - { - return new GrpcServer(_logger, _vpnController, _updateController, _serviceServerPortRegister, _appServerPortRegister); - } - - [TestCleanup] - public override void Cleanup() - { - _logger = null; - _vpnController = null; - _updateController = null; - _serviceServerPortRegister = null; - _appServerPortRegister = null; - base.Initialize(); - } - - [TestMethod] - public override void TestCreateAndStart() - { - base.TestCreateAndStart(); - _serviceServerPortRegister.Received(1).Write(Arg.Any()); - } - - [TestMethod] - public override void TestCreateAndStart_WithoutEventListener() - { - base.TestCreateAndStart_WithoutEventListener(); - _serviceServerPortRegister.Received(1).Write(Arg.Any()); - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Tests/ProtonVPN.ProcessCommunication.Service.Tests.csproj b/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Tests/ProtonVPN.ProcessCommunication.Service.Tests.csproj deleted file mode 100644 index 738ea7ad4..000000000 --- a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Tests/ProtonVPN.ProcessCommunication.Service.Tests.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - net6.0-windows - enable - ..\..\..\bin - false - Library - false - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - - - - - diff --git a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Tests/ServiceGrpcClientTest.cs b/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Tests/ServiceGrpcClientTest.cs deleted file mode 100644 index a8ceb1b88..000000000 --- a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service.Tests/ServiceGrpcClientTest.cs +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using Microsoft.VisualStudio.TestTools.UnitTesting; -using NSubstitute; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.ProcessCommunication.Common.Channels; -using ProtonVPN.ProcessCommunication.Common.Registration; -using ProtonVPN.ProcessCommunication.Common.Tests; -using ProtonVPN.ProcessCommunication.Contracts; -using ProtonVPN.ProcessCommunication.Contracts.Controllers; -using ProtonVPN.ProcessCommunication.Contracts.Registration; - -namespace ProtonVPN.ProcessCommunication.Service.Tests -{ - [TestClass] - public class ServiceGrpcClientTest - { - private const int APP_SERVER_PORT = 3; - - private ILogger _logger; - private IGrpcChannelWrapper _grpcChannelWrapper; - private IGrpcChannelWrapperFactory _grpcChannelWrapperFactory; - private IAppServerPortRegister _appServerPortRegister; - private IServiceGrpcClient _serviceGrpcClient; - - [TestInitialize] - public void Initialize() - { - _logger = Substitute.For(); - _grpcChannelWrapper = Substitute.For(); - _grpcChannelWrapper.CreateService().Returns(c => Substitute.For()); - _grpcChannelWrapperFactory = Substitute.For(); - _grpcChannelWrapperFactory.Create(Arg.Any()).Returns(_grpcChannelWrapper); - _appServerPortRegister = Substitute.For(); - _serviceGrpcClient = new ServiceGrpcClient(_logger, _grpcChannelWrapperFactory, _appServerPortRegister); - } - - [TestCleanup] - public void Cleanup() - { - _logger = null; - _grpcChannelWrapper = null; - _grpcChannelWrapperFactory = null; - _appServerPortRegister = null; - _serviceGrpcClient = null; - } - - [TestMethod] - public async Task TestCreateAsync() - { - await _serviceGrpcClient.CreateAsync(APP_SERVER_PORT); - - _appServerPortRegister.Received(1).Write(Arg.Any()); - _appServerPortRegister.Received(1).Write(APP_SERVER_PORT); - Assert.IsNotNull(_serviceGrpcClient.AppController); - } - - [TestMethod] - public void TestCreateAsync_NoRaceConditionOccurs() - { - int numOfCalls = 64; - - ParallelTestRunner.ExecuteInParallel(numOfCalls, - (int i) => _serviceGrpcClient.CreateAsync(APP_SERVER_PORT + i)); - - _appServerPortRegister.Received(numOfCalls).Write(Arg.Any()); - Assert.IsNotNull(_serviceGrpcClient.AppController); - _grpcChannelWrapperFactory.Received(numOfCalls).Create(Arg.Any()); - } - - [TestMethod] - public async Task TestRecreateAsync() - { - await _serviceGrpcClient.CreateAsync(APP_SERVER_PORT); - - _appServerPortRegister.Received(1).Write(Arg.Any()); - _appServerPortRegister.Received(1).Write(APP_SERVER_PORT); - - await _serviceGrpcClient.RecreateAsync(); - - _appServerPortRegister.Received(2).Write(Arg.Any()); - _appServerPortRegister.Received(2).Write(APP_SERVER_PORT); - Assert.IsNotNull(_serviceGrpcClient.AppController); - } - - [TestMethod] - public async Task TestRecreateAsync_WhenPortIsNull() - { - await _serviceGrpcClient.RecreateAsync(); - - _appServerPortRegister.Received(0).Write(Arg.Any()); - Assert.IsNull(_serviceGrpcClient.AppController); - } - - [TestMethod] - public async Task TestRecreateAsync_NoRaceConditionOccurs() - { - await _serviceGrpcClient.CreateAsync(APP_SERVER_PORT); - int numOfCalls = 64; - - ParallelTestRunner.ExecuteInParallel(numOfCalls, - (int _) => _serviceGrpcClient.RecreateAsync()); - - _appServerPortRegister.Received(numOfCalls + 1).Write(Arg.Any()); - _appServerPortRegister.Received(numOfCalls + 1).Write(APP_SERVER_PORT); - Assert.IsNotNull(_serviceGrpcClient.AppController); - _grpcChannelWrapperFactory.Received(numOfCalls + 1).Create(Arg.Any()); - await _grpcChannelWrapper.Received(numOfCalls).ShutdownAsync(); - } - - [TestMethod] - public void TestIsRecreatable_WhenServerPortIsNull() - { - bool result = _serviceGrpcClient.IsRecreatable(); - - Assert.IsFalse(result); - } - - [TestMethod] - public async Task TestIsRecreatable_WhenServerPortHasValue() - { - await _serviceGrpcClient.CreateAsync(APP_SERVER_PORT); - - bool result = _serviceGrpcClient.IsRecreatable(); - - Assert.IsTrue(result); - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service/GrpcServer.cs b/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service/GrpcServer.cs deleted file mode 100644 index 26b71ee46..000000000 --- a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service/GrpcServer.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using ProtoBuf.Grpc.Server; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.ProcessCommunication.Common; -using ProtonVPN.ProcessCommunication.Contracts.Controllers; -using ProtonVPN.ProcessCommunication.Contracts.Registration; -using static Grpc.Core.Server; - -namespace ProtonVPN.ProcessCommunication.Service -{ - public class GrpcServer : GrpcServerBase - { - private readonly IVpnController _vpnController; - private readonly IUpdateController _updateController; - private readonly IServiceServerPortRegister _serviceServerPortRegister; - private readonly IAppServerPortRegister _appServerPortRegister; - - public GrpcServer(ILogger logger, - IVpnController vpnController, - IUpdateController updateController, - IServiceServerPortRegister serviceServerPortRegister, - IAppServerPortRegister appServerPortRegister) - : base(logger) - { - _vpnController = vpnController; - _updateController = updateController; - _serviceServerPortRegister = serviceServerPortRegister; - _appServerPortRegister = appServerPortRegister; - } - - protected override void RegisterServices(ServiceDefinitionCollection services) - { - services.AddCodeFirst(_vpnController); - services.AddCodeFirst(_updateController); - } - - public override void CreateAndStart() - { - base.CreateAndStart(); - int? serverPort = Port; - if (serverPort.HasValue && serverPort.Value > 0) - { - _serviceServerPortRegister.Write(serverPort.Value); - } - } - - public override async Task ShutdownAsync() - { - _serviceServerPortRegister.Delete(); - _appServerPortRegister.Delete(); - await base.ShutdownAsync(); - } - - public override async Task KillAsync() - { - _serviceServerPortRegister.Delete(); - _appServerPortRegister.Delete(); - await base.KillAsync(); - } - } -} \ No newline at end of file diff --git a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service/ProtonVPN.ProcessCommunication.Service.csproj b/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service/ProtonVPN.ProcessCommunication.Service.csproj deleted file mode 100644 index fd63745ae..000000000 --- a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service/ProtonVPN.ProcessCommunication.Service.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net6.0-windows - enable - ..\..\..\bin - false - Library - false - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - - diff --git a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service/ServiceGrpcClient.cs b/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service/ServiceGrpcClient.cs deleted file mode 100644 index 1d3b31ea1..000000000 --- a/src/ProcessCommunication/Service/ProtonVPN.ProcessCommunication.Service/ServiceGrpcClient.cs +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using ProtonVPN.Logging.Contracts; -using ProtonVPN.Logging.Contracts.Events.ProcessCommunicationLogs; -using ProtonVPN.ProcessCommunication.Common; -using ProtonVPN.ProcessCommunication.Common.Channels; -using ProtonVPN.ProcessCommunication.Contracts; -using ProtonVPN.ProcessCommunication.Contracts.Controllers; -using ProtonVPN.ProcessCommunication.Contracts.Registration; - -namespace ProtonVPN.ProcessCommunication.Service -{ - public class ServiceGrpcClient : GrpcClientBase, IServiceGrpcClient - { - private readonly IAppServerPortRegister _appServerPortRegister; - - public IAppController AppController { get; private set; } - - public ServiceGrpcClient(ILogger logger, - IGrpcChannelWrapperFactory grpcChannelWrapperFactory, - IAppServerPortRegister appServerPortRegister) - : base(logger, grpcChannelWrapperFactory) - { - _appServerPortRegister = appServerPortRegister; - } - - public async Task CreateAsync(int serverPort) - { - _appServerPortRegister.Write(serverPort); - await CreateWithPortAsync(serverPort); - } - - protected override void RegisterServices(IGrpcChannelWrapper channel) - { - AppController = channel.CreateService(); - } - - public async Task RecreateAsync() - { - int? serverPort = ServerPort; - if (serverPort.HasValue) - { - Logger.Info($"Request to recreate a gRPC Client to Server Port {serverPort}."); - await CreateAsync(serverPort.Value); - } - else - { - Logger.Warn($"Cannot recreate gRPC Client because there is no previous Server Port."); - } - } - - public bool IsRecreatable() - { - return ServerPort.HasValue; - } - } -} \ No newline at end of file diff --git a/src/ProtonDrive.Downloader/ProtonDrive.Downloader.csproj b/src/ProtonDrive.Downloader/ProtonDrive.Downloader.csproj index 25ff448a6..dd509b802 100644 --- a/src/ProtonDrive.Downloader/ProtonDrive.Downloader.csproj +++ b/src/ProtonDrive.Downloader/ProtonDrive.Downloader.csproj @@ -1,7 +1,7 @@  - net6.0-windows10.0.17763.0 + net8.0-windows10.0.17763.0 WinExe ProtonDrive.Downloader ProtonDrive.Downloader @@ -10,6 +10,7 @@ ..\bin\ false Assets\ProtonDrive.ico + AnyCPU;ARM64 diff --git a/src/ProtonInstaller/CertificateHandler.cs b/src/ProtonInstaller/CertificateHandler.cs new file mode 100644 index 000000000..406cb5c1b --- /dev/null +++ b/src/ProtonInstaller/CertificateHandler.cs @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.Net.Security; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Formats.Asn1; + +namespace ProtonInstaller +{ + public class CertificateHandler : HttpClientHandler + { + private const string TLS_PIN = "CT56BhOTmj5ZIPgb/xD5mH8rY3BLo/MlhP7oPyJUEDo="; + + public CertificateHandler() + { + ServerCertificateCustomValidationCallback = CertificateCustomValidationCallback; + } + + protected bool CertificateCustomValidationCallback( + HttpRequestMessage request, + X509Certificate2 certificate, + X509Chain chain, + SslPolicyErrors sslPolicyErrors) + { + return sslPolicyErrors == SslPolicyErrors.None && GetTlsPin(certificate) == TLS_PIN; + } + + private string GetTlsPin(X509Certificate2 certificate) + { + byte[] digest; + using (SHA256 sha256 = SHA256.Create()) + { + digest = sha256.ComputeHash(GetSubjectPublicKeyInfo(certificate)); + } + + return Convert.ToBase64String(digest); + } + + private byte[] GetSubjectPublicKeyInfo(X509Certificate2 certificate) + { + byte[] rawCert = certificate.GetRawCertData(); + + // Parse the certificate + AsnReader reader = new AsnReader(rawCert, AsnEncodingRules.DER); + AsnReader certificateReader = reader.ReadSequence(); + + // Parse TBSCertificate + AsnReader tbsCertificateReader = certificateReader.ReadSequence(); + + // Parse version + Asn1Tag versionTag = new Asn1Tag(TagClass.ContextSpecific, 0); + if (tbsCertificateReader.PeekTag().HasSameClassAndValue(versionTag)) + { + tbsCertificateReader.ReadSequence(versionTag); + } + + // Parse serial number + tbsCertificateReader.ReadIntegerBytes(); + + // Parse signature algorithm + AsnReader signatureAlgorithmReader = tbsCertificateReader.ReadSequence(); + signatureAlgorithmReader.ReadObjectIdentifier(); + + // Parse issuer + tbsCertificateReader.ReadEncodedValue(); + + // Parse validity + tbsCertificateReader.ReadSequence(); + + // Parse subject + tbsCertificateReader.ReadEncodedValue(); + + // Parse subject public key info + byte[] subjectPublicKeyInfo = tbsCertificateReader.ReadEncodedValue().ToArray(); + + return subjectPublicKeyInfo; + } + } +} \ No newline at end of file diff --git a/src/ProtonInstaller/CommandLineOption.cs b/src/ProtonInstaller/CommandLineOption.cs new file mode 100644 index 000000000..d218410bc --- /dev/null +++ b/src/ProtonInstaller/CommandLineOption.cs @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller; + +public class CommandLineOption +{ + private readonly string _name; + private readonly string[] _args; + + public CommandLineOption(string name, string[] args) + { + _name = name; + _args = args; + } + + public bool Exists() + { + return _args + .SkipWhile(a => !IsOptionWithName(a, _name)) + .Any(); + } + + public IReadOnlyList Params() + { + return _args + .SkipWhile(a => !IsOptionWithName(a, _name)) + .Skip(1) + .TakeWhile(a => !IsOption(a)) + .ToList(); + } + + private bool IsOptionWithName(string arg, string name) + { + arg = arg.ToLower(); + name = name.ToLower(); + + return arg.Equals($"/{name}") || + arg.Equals($"-{name}") || + arg.Equals($"--{name}"); + } + + private bool IsOption(string arg) + { + return arg.StartsWith("-") || arg.StartsWith("/"); + } +} \ No newline at end of file diff --git a/src/ProtonInstaller/Contracts/ProtonDrive/ProtonDriveFileResponse.cs b/src/ProtonInstaller/Contracts/ProtonDrive/ProtonDriveFileResponse.cs new file mode 100644 index 000000000..419a3436f --- /dev/null +++ b/src/ProtonInstaller/Contracts/ProtonDrive/ProtonDriveFileResponse.cs @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller.Contracts.ProtonDrive; + +public class ProtonDriveFileResponse +{ + public required string Url { get; set; } + public required string Sha512Checksum { get; set; } + public required string SilentArguments { get; set; } +} \ No newline at end of file diff --git a/src/ProtonInstaller/Contracts/ProtonDrive/ProtonDriveReleaseResponse.cs b/src/ProtonInstaller/Contracts/ProtonDrive/ProtonDriveReleaseResponse.cs new file mode 100644 index 000000000..09205883b --- /dev/null +++ b/src/ProtonInstaller/Contracts/ProtonDrive/ProtonDriveReleaseResponse.cs @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller.Contracts.ProtonDrive; + +public class ProtonDriveReleaseResponse +{ + public required string CategoryName { get; set; } + public required string Version { get; set; } + public double? RolloutRatio { get; set; } + public required ProtonDriveFileResponse File { get; set; } +} \ No newline at end of file diff --git a/src/ProtonInstaller/Contracts/ProtonDrive/ProtonDriveReleasesResponse.cs b/src/ProtonInstaller/Contracts/ProtonDrive/ProtonDriveReleasesResponse.cs new file mode 100644 index 000000000..c7887ee80 --- /dev/null +++ b/src/ProtonInstaller/Contracts/ProtonDrive/ProtonDriveReleasesResponse.cs @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller.Contracts.ProtonDrive; + +public class ProtonDriveReleasesResponse +{ + public List? Releases { get; set; } +} \ No newline at end of file diff --git a/src/ProtonInstaller/Contracts/ProtonMail/ProtonMailFileResponse.cs b/src/ProtonInstaller/Contracts/ProtonMail/ProtonMailFileResponse.cs new file mode 100644 index 000000000..7c55c12ea --- /dev/null +++ b/src/ProtonInstaller/Contracts/ProtonMail/ProtonMailFileResponse.cs @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller.Contracts.ProtonMail; + +public class ProtonMailFileResponse +{ + public required string Url { get; set; } + public required string Sha512CheckSum { get; set; } +} \ No newline at end of file diff --git a/src/ProtonInstaller/Contracts/ProtonMail/ProtonMailReleaseResponse.cs b/src/ProtonInstaller/Contracts/ProtonMail/ProtonMailReleaseResponse.cs new file mode 100644 index 000000000..4604e0db4 --- /dev/null +++ b/src/ProtonInstaller/Contracts/ProtonMail/ProtonMailReleaseResponse.cs @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller.Contracts.ProtonMail; + +public class ProtonMailReleaseResponse +{ + public required string CategoryName { get; set; } + public required string Version { get; set; } + public double? RolloutProportion { get; set; } + public required List File { get; set; } +} \ No newline at end of file diff --git a/src/ProtonInstaller/Contracts/ProtonMail/ProtonMailReleasesResponse.cs b/src/ProtonInstaller/Contracts/ProtonMail/ProtonMailReleasesResponse.cs new file mode 100644 index 000000000..1f93dedad --- /dev/null +++ b/src/ProtonInstaller/Contracts/ProtonMail/ProtonMailReleasesResponse.cs @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller.Contracts.ProtonMail; + +public class ProtonMailReleasesResponse +{ + public List? Releases { get; set; } +} \ No newline at end of file diff --git a/src/ProtonInstaller/Contracts/ProtonPass/ProtonPassFileResponse.cs b/src/ProtonInstaller/Contracts/ProtonPass/ProtonPassFileResponse.cs new file mode 100644 index 000000000..e3605f5cd --- /dev/null +++ b/src/ProtonInstaller/Contracts/ProtonPass/ProtonPassFileResponse.cs @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller.Contracts.ProtonPass; + +public class ProtonPassFileResponse +{ + public required string Url { get; set; } + public required string Sha512CheckSum { get; set; } + public required string Args { get; set; } +} \ No newline at end of file diff --git a/src/ProtonInstaller/Contracts/ProtonPass/ProtonPassReleaseResponse.cs b/src/ProtonInstaller/Contracts/ProtonPass/ProtonPassReleaseResponse.cs new file mode 100644 index 000000000..8a9c0d816 --- /dev/null +++ b/src/ProtonInstaller/Contracts/ProtonPass/ProtonPassReleaseResponse.cs @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller.Contracts.ProtonPass; + +public class ProtonPassReleaseResponse +{ + public required string CategoryName { get; set; } + public required string Version { get; set; } + public double? RolloutPercentage { get; set; } + public required List File { get; set; } +} \ No newline at end of file diff --git a/src/ProtonInstaller/Contracts/ProtonPass/ProtonPassReleasesResponse.cs b/src/ProtonInstaller/Contracts/ProtonPass/ProtonPassReleasesResponse.cs new file mode 100644 index 000000000..d180603f6 --- /dev/null +++ b/src/ProtonInstaller/Contracts/ProtonPass/ProtonPassReleasesResponse.cs @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller.Contracts.ProtonPass; + +public class ProtonPassReleasesResponse +{ + public List? Releases { get; set; } +} \ No newline at end of file diff --git a/src/ProtonInstaller/ILatestRelease.cs b/src/ProtonInstaller/ILatestRelease.cs new file mode 100644 index 000000000..e2abb23ac --- /dev/null +++ b/src/ProtonInstaller/ILatestRelease.cs @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller; + +public interface ILatestRelease +{ + string BinaryUrl { get; } + string Sha512Checksum { get; } + string SilentArgument { get; } + string NoAutoLaunchArgument { get; } + string NoDesktopShortcutArgument { get; } +} \ No newline at end of file diff --git a/src/ProtonInstaller/IProtonProduct.cs b/src/ProtonInstaller/IProtonProduct.cs new file mode 100644 index 000000000..7cb515aad --- /dev/null +++ b/src/ProtonInstaller/IProtonProduct.cs @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller; + +public interface IProtonProduct +{ + Task InstallAsync(bool isToCreateDesktopShortcut); +} \ No newline at end of file diff --git a/src/ProtonInstaller/JsonContext.cs b/src/ProtonInstaller/JsonContext.cs new file mode 100644 index 000000000..088d112c7 --- /dev/null +++ b/src/ProtonInstaller/JsonContext.cs @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.Text.Json.Serialization; +using ProtonInstaller.Contracts.ProtonDrive; +using ProtonInstaller.Contracts.ProtonMail; +using ProtonInstaller.Contracts.ProtonPass; + +namespace ProtonInstaller; + +[JsonSerializable(typeof(ProtonDriveReleasesResponse))] +[JsonSerializable(typeof(ProtonDriveReleaseResponse))] +[JsonSerializable(typeof(ProtonDriveFileResponse))] +[JsonSerializable(typeof(ProtonMailReleasesResponse))] +[JsonSerializable(typeof(ProtonMailReleaseResponse))] +[JsonSerializable(typeof(ProtonMailFileResponse))] +[JsonSerializable(typeof(ProtonPassReleasesResponse))] +[JsonSerializable(typeof(ProtonPassReleaseResponse))] +[JsonSerializable(typeof(ProtonPassFileResponse))] +public partial class JsonContext : JsonSerializerContext; \ No newline at end of file diff --git a/src/ProtonInstaller/LatestRelease.cs b/src/ProtonInstaller/LatestRelease.cs new file mode 100644 index 000000000..e7a80e14d --- /dev/null +++ b/src/ProtonInstaller/LatestRelease.cs @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonInstaller; + +public class LatestRelease : ILatestRelease +{ + public required string BinaryUrl { get; init; } + public required string Sha512Checksum { get; init; } + public required string SilentArgument { get; init; } + public required string NoAutoLaunchArgument { get; init; } + public required string NoDesktopShortcutArgument { get; init; } +} \ No newline at end of file diff --git a/src/ProtonInstaller/Program.cs b/src/ProtonInstaller/Program.cs new file mode 100644 index 000000000..55dc16089 --- /dev/null +++ b/src/ProtonInstaller/Program.cs @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.Reflection; + +namespace ProtonInstaller; + +public class Program +{ + private static readonly HttpClient _downloadHttpClient = new(); + + static async Task Main(string[] args) + { + HttpClient versionHttpClient = GetHttpClient(); + IEnumerable products = GetProducts(versionHttpClient, args); + CommandLineOption shortcutOption = new("CreateDesktopShortcut", args); + + foreach (IProtonProduct product in products) + { + await product.InstallAsync(shortcutOption.Exists()); + } + } + + private static IEnumerable GetProducts(HttpClient verionHttpClient, string[] args) + { + CommandLineOption protonDriveOption = new("Drive", args); + if (protonDriveOption.Exists()) + { + yield return new ProtonDriveProduct(_downloadHttpClient, verionHttpClient); + } + + CommandLineOption protonPassOption = new("Pass", args); + if (protonPassOption.Exists()) + { + yield return new ProtonPassProduct(_downloadHttpClient, verionHttpClient); + } + + CommandLineOption protonMailOption = new("Mail", args); + if (protonMailOption.Exists()) + { + yield return new ProtonMailProduct(_downloadHttpClient, verionHttpClient); + } + } + + private static HttpClient GetHttpClient() + { + string version = Assembly.GetExecutingAssembly().GetName().Version?.ToString(3); + + HttpClient httpClient = new(new CertificateHandler()); + httpClient.DefaultRequestHeaders.UserAgent.ParseAdd($"ProtonVPNInstaller/{version} ({Environment.OSVersion})"); + return httpClient; + } +} \ No newline at end of file diff --git a/src/ProtonInstaller/Properties/PublishProfiles/FolderProfile.pubxml b/src/ProtonInstaller/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 000000000..9b1173478 --- /dev/null +++ b/src/ProtonInstaller/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,18 @@ + + + + + Release + x64 + bin\Release\net8.0\publish\win-x64\ + FileSystem + <_TargetId>Folder + net8.0 + win-x64 + true + false + false + + \ No newline at end of file diff --git a/src/ProtonInstaller/Properties/Resources.Designer.cs b/src/ProtonInstaller/Properties/Resources.Designer.cs new file mode 100644 index 000000000..6565255cb --- /dev/null +++ b/src/ProtonInstaller/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ProtonInstaller.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ProtonInstaller.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/src/ProtonInstaller/Properties/Resources.resx b/src/ProtonInstaller/Properties/Resources.resx new file mode 100644 index 000000000..4fdb1b6af --- /dev/null +++ b/src/ProtonInstaller/Properties/Resources.resx @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/ProtonInstaller/ProtonDriveProduct.cs b/src/ProtonInstaller/ProtonDriveProduct.cs new file mode 100644 index 000000000..6a01f28a3 --- /dev/null +++ b/src/ProtonInstaller/ProtonDriveProduct.cs @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.Text.Json; +using ProtonInstaller.Contracts.ProtonDrive; + +namespace ProtonInstaller; + +public class ProtonDriveProduct : ProtonProductBase +{ + private const string STABLE_CHANNEL = "Stable"; + private const string FEED_URL = "https://proton.me/download/drive/windows/version.json"; + + public ProtonDriveProduct(HttpClient downloadHttpClient, HttpClient versionHttpClient) : base(downloadHttpClient, versionHttpClient, FEED_URL) + { + } + + protected override async Task GetLatestReleaseAsync() + { + HttpResponseMessage response = await VersionHttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, FeedUrl)); + Stream stream = await response.Content.ReadAsStreamAsync(); + ProtonDriveReleasesResponse? releasesResponse = await JsonSerializer.DeserializeAsync(stream, JsonContext.Default.ProtonDriveReleasesResponse); + ProtonDriveReleaseResponse? release = releasesResponse?.Releases? + .Where(r => r.CategoryName == STABLE_CHANNEL && (r.RolloutRatio is null || r.RolloutRatio > 0.00)) + .MaxBy(r => GetVersion(r.Version)); + + return release is not null + ? new LatestRelease + { + BinaryUrl = release.File.Url, + Sha512Checksum = release.File.Sha512Checksum, + SilentArgument = release.File.SilentArguments, + NoAutoLaunchArgument = "NoAutoLaunch=1", + NoDesktopShortcutArgument = "NoDesktopShortcut=1", + } + : null; + } + + protected override string GetSourceArgument() + { + return "Source=vpn"; + } +} \ No newline at end of file diff --git a/src/ProtonInstaller/ProtonInstaller.csproj b/src/ProtonInstaller/ProtonInstaller.csproj new file mode 100644 index 000000000..b61ebd6a2 --- /dev/null +++ b/src/ProtonInstaller/ProtonInstaller.csproj @@ -0,0 +1,27 @@ + + + + WinExe + net8.0 + enable + enable + true + true + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/src/ProtonInstaller/ProtonMailProduct.cs b/src/ProtonInstaller/ProtonMailProduct.cs new file mode 100644 index 000000000..2b642ee1c --- /dev/null +++ b/src/ProtonInstaller/ProtonMailProduct.cs @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.Text.Json; +using ProtonInstaller.Contracts.ProtonMail; + +namespace ProtonInstaller; + +public class ProtonMailProduct : ProtonProductBase +{ + private const string STABLE_CHANNEL = "Stable"; + private const string FEED_URL = "https://proton.me/download/mail/windows/version.json"; + + public ProtonMailProduct(HttpClient downloadHttpClient, HttpClient versionHttpClient) : base(downloadHttpClient, versionHttpClient, FEED_URL) + { + } + + protected override async Task GetLatestReleaseAsync() + { + HttpResponseMessage response = await VersionHttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, FeedUrl)); + Stream stream = await response.Content.ReadAsStreamAsync(); + ProtonMailReleasesResponse? releasesResponse = await JsonSerializer.DeserializeAsync(stream, JsonContext.Default.ProtonMailReleasesResponse); + ProtonMailReleaseResponse? release = releasesResponse?.Releases? + .Where(r => r.CategoryName == STABLE_CHANNEL && r.RolloutProportion is not null && r.RolloutProportion > 0.00) + .MaxBy(r => GetVersion(r.Version)); + + ProtonMailFileResponse? file = release?.File.FirstOrDefault(); + + return file is not null + ? new LatestRelease + { + BinaryUrl = file.Url, + Sha512Checksum = file.Sha512CheckSum, + SilentArgument = "--silent=1", + NoAutoLaunchArgument = "--auto-launch=0", + NoDesktopShortcutArgument = "--desktop-shortcut=0", + } + : null; + } + + protected override string GetSourceArgument() + { + return "--source=vpn"; + } +} \ No newline at end of file diff --git a/src/ProtonInstaller/ProtonPassProduct.cs b/src/ProtonInstaller/ProtonPassProduct.cs new file mode 100644 index 000000000..7eba3d603 --- /dev/null +++ b/src/ProtonInstaller/ProtonPassProduct.cs @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.Text.Json; +using ProtonInstaller.Contracts.ProtonPass; + +namespace ProtonInstaller; + +public class ProtonPassProduct : ProtonProductBase +{ + private const string STABLE_CHANNEL = "Stable"; + private const string FEED_URL = "https://proton.me/download/PassDesktop/win32/x64/version.json"; + + public ProtonPassProduct(HttpClient downloadHttpClient, HttpClient versionHttpClient) : base(downloadHttpClient, versionHttpClient, FEED_URL) + { + } + + protected override async Task GetLatestReleaseAsync() + { + HttpResponseMessage response = await VersionHttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, FeedUrl)); + Stream stream = await response.Content.ReadAsStreamAsync(); + ProtonPassReleasesResponse? releasesResponse = await JsonSerializer.DeserializeAsync(stream, JsonContext.Default.ProtonPassReleasesResponse); + ProtonPassReleaseResponse? release = releasesResponse?.Releases? + .Where(r => r.CategoryName == STABLE_CHANNEL && r.RolloutPercentage is not null && r.RolloutPercentage > 0.00) + .MaxBy(r => GetVersion(r.Version)); + + ProtonPassFileResponse? file = release?.File.FirstOrDefault(); + + return file is not null + ? new LatestRelease + { + BinaryUrl = file.Url, + Sha512Checksum = file.Sha512CheckSum, + SilentArgument = "--silent=1", + NoAutoLaunchArgument = "--auto-launch=0", + NoDesktopShortcutArgument = "--desktop-shortcut=0", + } + : null; + } + + protected override string GetSourceArgument() + { + return "--source=vpn"; + } +} \ No newline at end of file diff --git a/src/ProtonInstaller/ProtonProductBase.cs b/src/ProtonInstaller/ProtonProductBase.cs new file mode 100644 index 000000000..db0bfafeb --- /dev/null +++ b/src/ProtonInstaller/ProtonProductBase.cs @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System.Diagnostics; +using System.Security.Cryptography; + +namespace ProtonInstaller; + +public abstract class ProtonProductBase : IProtonProduct +{ + private const int MAX_RETRIES = 3; + + private readonly HttpClient _downloadHttpClient; + protected readonly HttpClient VersionHttpClient; + private readonly TimeSpan _maxInstallDuration = TimeSpan.FromMinutes(5); + + public string FeedUrl { get; } + + protected ProtonProductBase(HttpClient downloadHttpClient, HttpClient versionHttpClient, string feedUrl) + { + _downloadHttpClient = versionHttpClient; + VersionHttpClient = versionHttpClient; + FeedUrl = feedUrl; + } + + public async Task InstallAsync(bool isToCreateDesktopShortcut) + { + try + { + ILatestRelease? release = await GetLatestReleaseAsync(); + if (release != null) + { + string pathToSave = GetPathToSave(release); + await DownloadWithRetryAsync(release.BinaryUrl, pathToSave); + if (File.Exists(pathToSave)) + { + string hash = GetSha512(pathToSave); + if (hash == release.Sha512Checksum) + { + StartProcess(pathToSave, GetCommandLineArguments(release, isToCreateDesktopShortcut)); + } + else + { + File.Delete(pathToSave); + } + } + } + } + catch (Exception e) + { + } + } + + protected abstract Task GetLatestReleaseAsync(); + + protected abstract string GetSourceArgument(); + + protected Version GetVersion(string releaseVersion) + { + return Version.TryParse(releaseVersion, out Version version) ? version : new(); + } + + private string GetPathToSave(ILatestRelease release) + { + Uri fileUri = new(release.BinaryUrl); + return Path.Combine(Path.GetTempPath(), Path.GetFileName(fileUri.AbsolutePath)); + } + + private async Task DownloadWithRetryAsync(string url, string filename) + { + TimeSpan delay = TimeSpan.FromSeconds(2); + + for (int retryCount = 0; retryCount <= MAX_RETRIES; retryCount++) + { + try + { + await DownloadAsync(url, filename); + if (File.Exists(filename)) + { + return; + } + } + catch (Exception) when (retryCount < MAX_RETRIES) + { + await Task.Delay(delay); + delay += delay; + } + } + } + + private async Task DownloadAsync(string url, string filename) + { + HttpResponseMessage response = await _downloadHttpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); + response.EnsureSuccessStatusCode(); + + await using Stream contentStream = await response.Content.ReadAsStreamAsync(); + await using FileStream fileStream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true); + byte[] buffer = new byte[8192]; + + while (true) + { + int bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length); + if (bytesRead <= 0) + { + break; + } + + await fileStream.WriteAsync(buffer, 0, bytesRead); + } + } + + private string GetSha512(string filePath) + { + using FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read); + using SHA512 sha512 = SHA512.Create(); + byte[] hashBytes = sha512.ComputeHash(stream); + return BitConverter.ToString(hashBytes).Replace("-", "").ToLower(); + } + + private void StartProcess(string path, string arguments) + { + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = path, + Arguments = arguments, + UseShellExecute = false, + }; + + Process process = new Process + { + StartInfo = startInfo + }; + + process.Start(); + + if (!process.WaitForExit(_maxInstallDuration)) + { + process.Kill(); + } + } + + private string GetCommandLineArguments(ILatestRelease release, bool isToCreateDesktopShortcut) + { + List arguments = [GetSourceArgument(), release.SilentArgument, release.NoAutoLaunchArgument]; + if (!isToCreateDesktopShortcut) + { + arguments.Add(release.NoDesktopShortcutArgument); + } + + return string.Join(' ', arguments); + } +} \ No newline at end of file diff --git a/src/ProtonVPN.App/AccountPlan/PlanChangeHandler.cs b/src/ProtonVPN.App/AccountPlan/PlanChangeHandler.cs index fcb20509c..378cea53b 100644 --- a/src/ProtonVPN.App/AccountPlan/PlanChangeHandler.cs +++ b/src/ProtonVPN.App/AccountPlan/PlanChangeHandler.cs @@ -130,7 +130,6 @@ private void DisablePaidFeatures(User user) _appSettings.SecureCore = false; _appSettings.PortForwardingEnabled = false; _appSettings.NetShieldEnabled = false; - _appSettings.AllowNonStandardPorts = false; _appSettings.ModerateNat = false; if (_appSettings.FeatureFreeRescopeEnabled) { diff --git a/src/ProtonVPN.App/App.config b/src/ProtonVPN.App/App.config index 8a3ae4b87..23f1c06e1 100644 --- a/src/ProtonVPN.App/App.config +++ b/src/ProtonVPN.App/App.config @@ -355,15 +355,6 @@ - - - - - False - - - False - @@ -433,6 +424,9 @@ + + + @@ -445,6 +439,9 @@ + + + diff --git a/src/ProtonVPN.App/BugReporting/ReportFieldProvider.cs b/src/ProtonVPN.App/BugReporting/ReportFieldProvider.cs index 5db451e35..bfbc83f46 100644 --- a/src/ProtonVPN.App/BugReporting/ReportFieldProvider.cs +++ b/src/ProtonVPN.App/BugReporting/ReportFieldProvider.cs @@ -24,6 +24,7 @@ using ProtonVPN.BugReporting.FormElements; using ProtonVPN.Common.Configuration; using ProtonVPN.Common.Extensions; +using ProtonVPN.Common.OS.Architecture; using ProtonVPN.Common.OS.DeviceIds; using ProtonVPN.Core.Auth; using ProtonVPN.Core.Models; @@ -65,6 +66,7 @@ public KeyValuePair[] GetFields(SendReportAction message) { new KeyValuePair("OS", "Windows"), new KeyValuePair("OSVersion", Environment.OSVersion.ToString()), + new KeyValuePair("Platform", OsArchitecture.Value), new KeyValuePair("Client", "Windows app"), new KeyValuePair("ClientVersion", _config.AppVersion), new KeyValuePair("Title", "Windows app form"), diff --git a/src/ProtonVPN.App/Config/Url/ActiveUrls.cs b/src/ProtonVPN.App/Config/Url/ActiveUrls.cs index 10d731ee1..a65ac262b 100644 --- a/src/ProtonVPN.App/Config/Url/ActiveUrls.cs +++ b/src/ProtonVPN.App/Config/Url/ActiveUrls.cs @@ -64,7 +64,6 @@ public ActiveUrls(IConfiguration config, IOsProcesses processes) public IActiveUrl AboutSmartProtocolUrl => Url(_config.AboutSmartProtocolUrl); public IActiveUrl IncorrectSystemTimeArticleUrl => Url(_config.IncorrectSystemTimeArticleUrl); public IActiveUrl AssignVpnConnectionsUrl => Url(_config.AssignVpnConnectionsUrl); - public IActiveUrl NonStandardPortsUrl => Url(_config.NonStandardPortsUrl); public IActiveUrl LoginProblemsUrl => Url(_config.LoginProblemsUrl); public IActiveUrl RebrandingUrl => Url(_config.RebrandingUrl); public IActiveUrl RpcServerProblemUrl => Url(_config.RpcServerProblemUrl); diff --git a/src/ProtonVPN.App/Config/Url/IActiveUrls.cs b/src/ProtonVPN.App/Config/Url/IActiveUrls.cs index 1336aae54..175e64d73 100644 --- a/src/ProtonVPN.App/Config/Url/IActiveUrls.cs +++ b/src/ProtonVPN.App/Config/Url/IActiveUrls.cs @@ -52,7 +52,6 @@ public interface IActiveUrls IActiveUrl AboutSmartProtocolUrl { get; } IActiveUrl IncorrectSystemTimeArticleUrl { get; } IActiveUrl AssignVpnConnectionsUrl { get; } - IActiveUrl NonStandardPortsUrl { get; } IActiveUrl LoginProblemsUrl { get; } IActiveUrl RebrandingUrl { get; } IActiveUrl RpcServerProblemUrl { get; } diff --git a/src/ProtonVPN.App/Core/AppSettings.cs b/src/ProtonVPN.App/Core/AppSettings.cs index 0ac2ead78..b5de29cf0 100644 --- a/src/ProtonVPN.App/Core/AppSettings.cs +++ b/src/ProtonVPN.App/Core/AppSettings.cs @@ -486,12 +486,6 @@ public bool FeatureSmartReconnectEnabled set => Set(value); } - public bool ShowNonStandardPortsToFreeUsers - { - get => Get(); - set => Set(value); - } - public bool ConnectOnAppStart { get => Get(); @@ -513,12 +507,6 @@ public bool SmartReconnectNotificationsEnabled set => Set(value); } - public bool AllowNonStandardPorts - { - get => GetPerUser(); - set => SetPerUser(value); - } - public string AuthenticationPublicKey { get => GetPerUserDecrypted(); @@ -645,12 +633,24 @@ public string StatisticalEvents set => SetPerUserEncrypted(value); } + public string UnauthStatisticalEvents + { + get => GetDecrypted(); + set => SetEncrypted(value); + } + public DateTimeOffset LogicalsLastModifiedDate { get => Get().FromJsonDateTimeOffset() ?? DateTimeOffset.UnixEpoch; set => Set(value.ToJsonDateTimeOffset()); } + public VpnProtocol[] DisabledSmartProtocols + { + get => Get() ?? new List().ToArray(); + set => Set(value); + } + public TimeSpan MaintenanceCheckInterval { get diff --git a/src/ProtonVPN.App/Core/Bootstraper.cs b/src/ProtonVPN.App/Core/Bootstraper.cs index 25743bcd7..ea1e18086 100644 --- a/src/ProtonVPN.App/Core/Bootstraper.cs +++ b/src/ProtonVPN.App/Core/Bootstraper.cs @@ -34,7 +34,6 @@ using ProtonVPN.Api.Contracts; using ProtonVPN.Api.Contracts.Auth; using ProtonVPN.Api.Contracts.Servers; -using ProtonVPN.Api.Handlers; using ProtonVPN.Api.Installers; using ProtonVPN.BugReporting; using ProtonVPN.Common.Abstract; @@ -42,6 +41,7 @@ using ProtonVPN.Common.Configuration; using ProtonVPN.Common.Extensions; using ProtonVPN.Common.Installers.Extensions; +using ProtonVPN.Common.OS.Architecture; using ProtonVPN.Common.OS.Services; using ProtonVPN.Common.Vpn; using ProtonVPN.Core.Abstract; @@ -72,7 +72,6 @@ using ProtonVPN.Logging.Contracts; using ProtonVPN.Logging.Contracts.Events.AppLogs; using ProtonVPN.Logging.Contracts.Events.AppServiceLogs; -using ProtonVPN.Logging.Contracts.Events.ProcessCommunicationLogs; using ProtonVPN.Logging.Installers; using ProtonVPN.Login; using ProtonVPN.Login.ViewModels; @@ -83,16 +82,19 @@ using ProtonVPN.Modals.Welcome; using ProtonVPN.Notifications; using ProtonVPN.Onboarding; +using ProtonVPN.OperatingSystems.Processes.Installers; +using ProtonVPN.OperatingSystems.Registries.Installers; using ProtonVPN.P2PDetection; -using ProtonVPN.ProcessCommunication.App.Installers; +using ProtonVPN.ProcessCommunication.Client.Installers; using ProtonVPN.ProcessCommunication.Contracts; -using ProtonVPN.ProcessCommunication.Contracts.Controllers; using ProtonVPN.ProcessCommunication.Installers; using ProtonVPN.QuickLaunch; using ProtonVPN.Settings; using ProtonVPN.Settings.Migrations; using ProtonVPN.Sidebar; using ProtonVPN.Sidebar.Announcements; +using ProtonVPN.StatisticalEvents.Contracts; +using ProtonVPN.StatisticalEvents.Installers; using ProtonVPN.Streaming; using ProtonVPN.Translations; using ProtonVPN.Update; @@ -132,8 +134,10 @@ protected override void Configure() .RegisterAssemblyModule() .RegisterAssemblyModule() .RegisterAssemblyModule() + .RegisterAssemblyModule() + .RegisterAssemblyModule() .RegisterAssemblyModule() - .RegisterAssemblyModule() + .RegisterAssemblyModule() .RegisterAssemblyModule(); _container = builder.Build(); @@ -145,7 +149,7 @@ protected override async void OnStartup(object sender, StartupEventArgs e) IConfiguration appConfig = Resolve(); - Resolve().Info($"= Booting ProtonVPN version: {appConfig.AppVersion} os: {Environment.OSVersion.VersionString} {appConfig.OsBits} bit ="); + Resolve().Info($"= Booting ProtonVPN version: {appConfig.AppVersion} os: {Environment.OSVersion.VersionString} {OsArchitecture.Value} ="); Resolve().Clean(appConfig.AppLogFolder, 10); @@ -161,6 +165,7 @@ protected override async void OnStartup(object sender, StartupEventArgs e) RegisterEvents(); Resolve().Initialize(e.Args); InitializeUpdates(e.Args); + HandleProtonInstallerArguments(e.Args); if (Resolve().StartMinimized == StartMinimizedMode.Disabled) { @@ -170,7 +175,7 @@ protected override async void OnStartup(object sender, StartupEventArgs e) Resolve().FetchDataAsync(); StartVpnServiceAsync(); - StartGrpcServerAsync(); + StartProcessCommunication(); if (Resolve().GetUser().Empty() || !await IsUserValid() || await SessionExpired()) { @@ -192,15 +197,26 @@ private void InitializeUpdates(string[] args) Resolve().Initialize(); } - private async Task StartGrpcServerAsync() + private void HandleProtonInstallerArguments(string[] args) + { + bool isCleanInstall = new CommandLineOption("CleanInstall", args).Exists(); + if (isCleanInstall) + { + bool isMailInstalled = new CommandLineOption("MailInstalled", args).Exists(); + bool isDriveInstalled = new CommandLineOption("DriveInstalled", args).Exists(); + bool isPassInstalled = new CommandLineOption("PassInstalled", args).Exists(); + + IClientInstallsStatisticalEventSender statisticalEventSender = Resolve(); + statisticalEventSender.Send(isMailInstalled, isDriveInstalled, isPassInstalled); + } + } + + private async Task StartProcessCommunication() { try { - IGrpcServer grpcServer = Resolve(); - grpcServer.CreateAndStart(); - int appServerPort = grpcServer.Port.Value; - Resolve().Info($"Sending app gRPC server port {appServerPort} to service."); - await Resolve().RegisterVpnClient(appServerPort); + IProcessCommunicationStarter processCommunicationStarter = Resolve(); + processCommunicationStarter.Start(); } catch (Exception e) { @@ -211,12 +227,13 @@ private async Task StartGrpcServerAsync() public void OnExit() { - Resolve().KillAsync(); + Resolve().Stop(); + Resolve().Stop(); Resolve().Info("The app is exiting. Requesting services to stop."); Resolve().Hide(); Resolve().StopAsync(); } - + private async Task SessionExpired() { if (string.IsNullOrEmpty(Resolve().AccessToken)) @@ -440,7 +457,7 @@ private void RegisterEvents() } }); - Resolve().OnOpenWindowInvoked += (_, _) => + Resolve().OnOpenWindowInvoked += (_, _) => { IEnumerable instances = Resolve>(); foreach (IOpenMainWindowAware instance in instances) diff --git a/src/ProtonVPN.App/Core/Ioc/AppModule.cs b/src/ProtonVPN.App/Core/Ioc/AppModule.cs index f028a66ac..3628bb250 100644 --- a/src/ProtonVPN.App/Core/Ioc/AppModule.cs +++ b/src/ProtonVPN.App/Core/Ioc/AppModule.cs @@ -24,6 +24,7 @@ using ProtonVPN.Account; using ProtonVPN.AccountPlan; using ProtonVPN.Api; +using ProtonVPN.Client.Logic.Connection; using ProtonVPN.Common.Configuration; using ProtonVPN.Common.OS.DeviceIds; using ProtonVPN.Common.OS.Processes; @@ -125,7 +126,6 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType().AsSelf().AsImplementedInterfaces().SingleInstance(); builder.RegisterType().AsSelf().AsImplementedInterfaces().SingleInstance(); builder.RegisterType().AsSelf().AsImplementedInterfaces().SingleInstance(); - builder.RegisterType().AsImplementedInterfaces().SingleInstance(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); @@ -302,6 +302,10 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType().AsImplementedInterfaces().SingleInstance(); builder.RegisterType().AsImplementedInterfaces().SingleInstance(); builder.RegisterType().AsImplementedInterfaces().SingleInstance(); + + builder.RegisterType().AsImplementedInterfaces().SingleInstance(); + builder.RegisterType().AsImplementedInterfaces().SingleInstance(); + builder.RegisterType().AsImplementedInterfaces().SingleInstance(); } } } \ No newline at end of file diff --git a/src/ProtonVPN.App/Core/Service/IMonitoredVpnService.cs b/src/ProtonVPN.App/Core/Service/IMonitoredVpnService.cs index a031f54bb..db7eee675 100644 --- a/src/ProtonVPN.App/Core/Service/IMonitoredVpnService.cs +++ b/src/ProtonVPN.App/Core/Service/IMonitoredVpnService.cs @@ -32,5 +32,7 @@ public interface IMonitoredVpnService bool IsRunning(); Task StartAsync(); Task StopAsync(); + + Task StartIfNotRunningAsync(); } } \ No newline at end of file diff --git a/src/ProtonVPN.App/Core/Service/MonitoredVpnService.cs b/src/ProtonVPN.App/Core/Service/MonitoredVpnService.cs index 2580e73a0..dffbde385 100644 --- a/src/ProtonVPN.App/Core/Service/MonitoredVpnService.cs +++ b/src/ProtonVPN.App/Core/Service/MonitoredVpnService.cs @@ -22,18 +22,15 @@ using System.Windows.Threading; using ProtonVPN.Common.Abstract; using ProtonVPN.Common.Configuration; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.Logging.Contracts.Events.AppServiceLogs; using ProtonVPN.Common.OS.Services; -using ProtonVPN.Common.Vpn; using ProtonVPN.Core.Service.Vpn; -using ProtonVPN.Core.Vpn; +using ProtonVPN.Logging.Contracts; +using ProtonVPN.Logging.Contracts.Events.AppServiceLogs; namespace ProtonVPN.Core.Service { - public class MonitoredVpnService : IMonitoredVpnService, IVpnStateAware, IConcurrentService + public class MonitoredVpnService : IMonitoredVpnService, IConcurrentService { - private VpnStatus _vpnStatus; private readonly DispatcherTimer _timer = new(); private readonly VpnSystemService _service; private readonly IVpnManager _vpnManager; @@ -50,6 +47,7 @@ public MonitoredVpnService( _logger = logger; _timer.Interval = appConfig.ServiceCheckInterval; _timer.Tick += OnTimerTick; + _timer.Start(); } public string Name => _service.Name; @@ -67,31 +65,22 @@ public Task StartAsync() public Task StopAsync() => _service.StopAsync(); - public async Task OnVpnStateChanged(VpnStateChangedEventArgs e) + private void OnTimerTick(object sender, EventArgs e) { - _vpnStatus = e.State.Status; - - if (!_timer.IsEnabled && _vpnStatus != VpnStatus.Disconnected) - { - _timer.Start(); - } - - if (_timer.IsEnabled && _vpnStatus == VpnStatus.Disconnected) - { - _timer.Stop(); - } + StartIfNotRunningAsync().Wait(); } - private void OnTimerTick(object sender, EventArgs e) + public async Task StartIfNotRunningAsync() { - if (_vpnStatus == VpnStatus.Disconnected || _vpnStatus == VpnStatus.Disconnecting || IsRunning()) + if (IsRunning()) { return; } - _logger.Warn($"The service is not running and the VPN status is '{_vpnStatus}'. " + + _logger.Warn($"The service is not running. " + "Starting the service and reconnecting."); StartAsync(); + _vpnManager.GetStateAsync(); _vpnManager.ReconnectAsync(); } } diff --git a/src/ProtonVPN.App/Core/Service/ServiceControllerCaller.cs b/src/ProtonVPN.App/Core/Service/ServiceControllerCaller.cs index 570d72cae..b3d9447e9 100644 --- a/src/ProtonVPN.App/Core/Service/ServiceControllerCaller.cs +++ b/src/ProtonVPN.App/Core/Service/ServiceControllerCaller.cs @@ -19,6 +19,7 @@ using System; using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; using ProtonVPN.Common.Abstract; using ProtonVPN.Common.Extensions; @@ -31,18 +32,20 @@ namespace ProtonVPN.Core.Service { public abstract class ServiceControllerCaller where Controller : IServiceController { + private readonly TimeSpan _callTimeout = TimeSpan.FromSeconds(3); + private readonly ILogger _logger; - private readonly IAppGrpcClient _grpcClient; - private readonly VpnSystemService _vpnSystemService; + private readonly IGrpcClient _grpcClient; + private readonly Lazy _monitoredVpnService; - protected ServiceControllerCaller(ILogger logger, IAppGrpcClient grpcClient, VpnSystemService vpnSystemService) + protected ServiceControllerCaller(ILogger logger, IGrpcClient grpcClient, Lazy monitoredVpnService) { _logger = logger; _grpcClient = grpcClient; - _vpnSystemService = vpnSystemService; + _monitoredVpnService = monitoredVpnService; } - protected async Task> Invoke(Func> serviceCall, + protected async Task> Invoke(Func> serviceCall, [CallerMemberName] string memberName = "") { int retryCount = 5; @@ -52,7 +55,8 @@ protected async Task> Invoke(Func> serviceCall, { Controller serviceController = await _grpcClient.GetServiceControllerOrThrowAsync(TimeSpan.FromSeconds(1)); - T result = await serviceCall(serviceController); + CancellationTokenSource cancellationTokenSource = new(_callTimeout); + T result = await serviceCall(serviceController, cancellationTokenSource.Token); if (result is Task task) { await task; @@ -62,14 +66,13 @@ protected async Task> Invoke(Func> serviceCall, } catch (Exception e) { - await StartServiceIfStoppedAsync(); + await CheckForIssuesAsync(); if (retryCount <= 0) { LogError(e, memberName, isToRetry: false); return Result.Fail(e.CombinedMessage()); } - await _grpcClient.RecreateAsync(); LogError(e, memberName, isToRetry: true); } @@ -77,9 +80,20 @@ protected async Task> Invoke(Func> serviceCall, } } + private async Task CheckForIssuesAsync() + { + await StartServiceIfStoppedAsync(); + RecreateGrpcChannelIfPipeNameChanged(); + } + private async Task StartServiceIfStoppedAsync() { - await _vpnSystemService.StartIfStoppedAsync(); + await _monitoredVpnService.Value.StartIfNotRunningAsync(); + } + + private void RecreateGrpcChannelIfPipeNameChanged() + { + _grpcClient.CreateIfPipeNameChanged(); } private void LogError(Exception exception, string callerMemberName, bool isToRetry) diff --git a/src/ProtonVPN.App/Core/Service/Settings/MainSettingsProvider.cs b/src/ProtonVPN.App/Core/Service/Settings/MainSettingsProvider.cs index 7b7766a28..bb4135a91 100644 --- a/src/ProtonVPN.App/Core/Service/Settings/MainSettingsProvider.cs +++ b/src/ProtonVPN.App/Core/Service/Settings/MainSettingsProvider.cs @@ -30,6 +30,8 @@ namespace ProtonVPN.Core.Service.Settings { public class MainSettingsProvider { + private const bool DEFAULT_SPLIT_TCP_VALUE = true; + private readonly IAppSettings _appSettings; private readonly IUserStorage _userStorage; private readonly IEntityMapper _entityMapper; @@ -59,8 +61,7 @@ public MainSettingsIpcEntity Create(OpenVpnAdapter? openVpnAdapter = null) }, ModerateNat = !_userStorage.GetUser().Empty() && _appSettings.ModerateNat && isPaidFeatureAllowed, NetShieldMode = _appSettings.IsNetShieldEnabled() ? _appSettings.NetShieldMode : 0, - SplitTcp = isPaidFeatureAllowed ? _appSettings.IsVpnAcceleratorEnabled() : null, - AllowNonStandardPorts = _appSettings.ShowNonStandardPortsToFreeUsers ? _appSettings.AllowNonStandardPorts : null, + SplitTcp = isPaidFeatureAllowed ? _appSettings.IsVpnAcceleratorEnabled() : DEFAULT_SPLIT_TCP_VALUE, Ipv6LeakProtection = _appSettings.Ipv6LeakProtection, VpnProtocol = _entityMapper.Map(_appSettings.GetProtocol()), OpenVpnAdapter = _entityMapper.MapNullableStruct(openVpnAdapter) ?? diff --git a/src/ProtonVPN.App/Core/Service/Settings/SettingsServiceClientManager.cs b/src/ProtonVPN.App/Core/Service/Settings/SettingsServiceClientManager.cs index 74a76a0c9..79d725b80 100644 --- a/src/ProtonVPN.App/Core/Service/Settings/SettingsServiceClientManager.cs +++ b/src/ProtonVPN.App/Core/Service/Settings/SettingsServiceClientManager.cs @@ -19,11 +19,10 @@ using System.ComponentModel; using System.Threading.Tasks; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.Logging.Contracts.Events.AppServiceLogs; using ProtonVPN.Core.Service.Vpn; using ProtonVPN.Core.Settings; -using ProtonVPN.ProcessCommunication.Contracts; +using ProtonVPN.Logging.Contracts; +using ProtonVPN.Logging.Contracts.Events.AppServiceLogs; using ProtonVPN.ProcessCommunication.Contracts.Entities.Settings; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; @@ -34,19 +33,15 @@ public class SettingsServiceClientManager : ISettingsServiceClientManager, ISett private readonly ILogger _logger; private readonly VpnServiceCaller _vpnServiceCaller; private readonly MainSettingsProvider _settingsContractProvider; - private readonly IAppGrpcClient _grpcClient; public SettingsServiceClientManager( ILogger logger, VpnServiceCaller vpnServiceCaller, - MainSettingsProvider settingsContractProvider, - IAppGrpcClient grpcClient) + MainSettingsProvider settingsContractProvider) { _logger = logger; _vpnServiceCaller = vpnServiceCaller; _settingsContractProvider = settingsContractProvider; - _grpcClient = grpcClient; - _grpcClient.CreateAsync(); } public async Task UpdateServiceSettings() @@ -79,7 +74,6 @@ public async void OnAppSettingsChanged(PropertyChangedEventArgs e) e.PropertyName == nameof(IAppSettings.VpnAcceleratorEnabled) || e.PropertyName == nameof(IAppSettings.FeatureVpnAcceleratorEnabled) || e.PropertyName == nameof(IAppSettings.ModerateNat) || - e.PropertyName == nameof(IAppSettings.AllowNonStandardPorts) || e.PropertyName == nameof(IAppSettings.OvpnProtocol) || e.PropertyName == nameof(IAppSettings.NetworkAdapterType) || e.PropertyName == nameof(IAppSettings.NetShieldMode) || diff --git a/src/ProtonVPN.App/Core/Service/Update/UpdateServiceCaller.cs b/src/ProtonVPN.App/Core/Service/Update/UpdateServiceCaller.cs index 8e48ab18d..aa369f419 100644 --- a/src/ProtonVPN.App/Core/Service/Update/UpdateServiceCaller.cs +++ b/src/ProtonVPN.App/Core/Service/Update/UpdateServiceCaller.cs @@ -17,6 +17,7 @@ * along with ProtonVPN. If not, see . */ +using System; using System.Threading.Tasks; using ProtonVPN.Common.Extensions; using ProtonVPN.Logging.Contracts; @@ -28,19 +29,23 @@ namespace ProtonVPN.Core.Service.Update { public class UpdateServiceCaller : ServiceControllerCaller { - public UpdateServiceCaller(ILogger logger, IAppGrpcClient grpcClient, VpnSystemService vpnSystemService) - : base(logger, grpcClient, vpnSystemService) + public UpdateServiceCaller(ILogger logger, IGrpcClient grpcClient, Lazy monitoredVpnService) + : base(logger, grpcClient, monitoredVpnService) { } public Task CheckForUpdates(UpdateSettingsIpcEntity updateSettingsIpcEntity) { - return Invoke(c => c.CheckForUpdate(updateSettingsIpcEntity).Wrap()); + return Invoke((c, ct) => c.CheckForUpdate(updateSettingsIpcEntity, ct).Wrap()); } public Task StartAutoUpdate() { - return Invoke(c => c.StartAutoUpdate().Wrap()); + StartAutoUpdateIpcEntity startAutoUpdateIpcEntity = new() + { + RetryId = Guid.NewGuid() + }; + return Invoke((c, ct) => c.StartAutoUpdate(startAutoUpdateIpcEntity, ct).Wrap()); } } } \ No newline at end of file diff --git a/src/ProtonVPN.App/Core/Service/Vpn/AppController.cs b/src/ProtonVPN.App/Core/Service/Vpn/AppController.cs deleted file mode 100644 index 61e61ab65..000000000 --- a/src/ProtonVPN.App/Core/Service/Vpn/AppController.cs +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2023 Proton AG - * - * This file is part of ProtonVPN. - * - * ProtonVPN is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ProtonVPN is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with ProtonVPN. If not, see . - */ - -using System; -using System.Collections.Specialized; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using System.Windows; -using ProtonVPN.Account; -using ProtonVPN.Announcements.Contracts; -using ProtonVPN.Common.Extensions; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.Logging.Contracts.Events.ProcessCommunicationLogs; -using ProtonVPN.ProcessCommunication.Contracts.Controllers; -using ProtonVPN.ProcessCommunication.Contracts.Entities.NetShield; -using ProtonVPN.ProcessCommunication.Contracts.Entities.PortForwarding; -using ProtonVPN.ProcessCommunication.Contracts.Entities.Update; -using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; - -namespace ProtonVPN.Core.Service.Vpn -{ - public class AppController : IAppController - { - private readonly ILogger _logger; - private readonly IUpgradeModalManager _upgradeModalManager; - private readonly IAnnouncementService _announcementService; - - public event EventHandler OnVpnStateChanged; - public event EventHandler OnPortForwardingStateChanged; - public event EventHandler OnConnectionDetailsChanged; - public event EventHandler OnNetShieldStatisticChanged; - public event EventHandler OnUpdateStateChanged; - public event EventHandler OnOpenWindowInvoked; - - public AppController(ILogger logger, IUpgradeModalManager upgradeModalManager, IAnnouncementService announcementService) - { - _logger = logger; - _upgradeModalManager = upgradeModalManager; - _announcementService = announcementService; - } - - public async Task VpnStateChange(VpnStateIpcEntity state) - { - _logger.Info($"Received VPN Status '{state.Status}', NetworkBlocked: {state.NetworkBlocked} " + - $"Error: '{state.Error}', EndpointIp: '{state.EndpointIp}', Label: '{state.Label}', " + - $"VpnProtocol: '{state.VpnProtocol}', OpenVpnAdapter: '{state.OpenVpnAdapterType}'"); - InvokeOnUiThread(() => OnVpnStateChanged?.Invoke(this, state)); - } - - private void InvokeOnUiThread(Action action) - { - Application.Current?.Dispatcher?.Invoke(action); - } - - public async Task PortForwardingStateChange(PortForwardingStateIpcEntity state) - { - StringBuilder logMessage = new StringBuilder().Append("Received PortForwarding " + - $"Status '{state.Status}' triggered at '{state.TimestampUtc}'"); - if (state.MappedPort is not null) - { - TemporaryMappedPortIpcEntity mappedPort = state.MappedPort; - logMessage.Append($", Port pair {mappedPort.InternalPort}->{mappedPort.ExternalPort}, expiring in " + - $"{mappedPort.Lifetime} at {mappedPort.ExpirationDateUtc}"); - } - _logger.Info(logMessage.ToString()); - InvokeOnUiThread(() => OnPortForwardingStateChanged?.Invoke(this, state)); - } - - public async Task ConnectionDetailsChange(ConnectionDetailsIpcEntity connectionDetails) - { - _logger.Info($"Received connection details change while " + - $"connected to server with IP '{connectionDetails.ServerIpAddress}'"); - InvokeOnUiThread(() => OnConnectionDetailsChanged?.Invoke(this, connectionDetails)); - } - - public async Task UpdateStateChange(UpdateStateIpcEntity updateStateDetails) - { - _logger.Info( - $"Received update state change with status {updateStateDetails.Status}."); - InvokeOnUiThread(() => OnUpdateStateChanged?.Invoke(this, updateStateDetails)); - } - - public async Task NetShieldStatisticChange(NetShieldStatisticIpcEntity netShieldStatistic) - { - _logger.Info( - $"Received NetShield statistic change with timestamp '{netShieldStatistic.TimestampUtc}' " + - $"[Ads: '{netShieldStatistic.NumOfAdvertisementUrlsBlocked}']" + - $"[Malware: '{netShieldStatistic.NumOfMaliciousUrlsBlocked}']" + - $"[Trackers: '{netShieldStatistic.NumOfTrackingUrlsBlocked}']"); - InvokeOnUiThread(() => OnNetShieldStatisticChanged?.Invoke(this, netShieldStatistic)); - } - - public async Task OpenWindow(string args) - { - _logger.Debug("Another process requested to open the main window."); - await ProcessCommandArgumentsAsync(args); - InvokeOnUiThread(() => OnOpenWindowInvoked?.Invoke(this, null)); - } - - private async Task ProcessCommandArgumentsAsync(string args) - { - if (Uri.TryCreate(args, UriKind.Absolute, out Uri uri)) - { - await ProcessCommandUriArgumentAsync(uri); - } - } - - private async Task ProcessCommandUriArgumentAsync(Uri uri) - { - string modalSource = null; - string notificationReference = null; - - NameValueCollection uriQuery = HttpUtility.ParseQueryString(uri.Query); - foreach (string queryKey in uriQuery.AllKeys) - { - if (queryKey.EqualsIgnoringCase("delete-notification-id")) - { - _announcementService.Delete(uriQuery[queryKey]); - } - else if (queryKey.EqualsIgnoringCase("notification-reference")) - { - _announcementService.DeleteByReference(uriQuery[queryKey]); - notificationReference = uriQuery[queryKey]; - } - else if (queryKey.EqualsIgnoringCase("modal-source")) - { - modalSource = uriQuery[queryKey]; - } - } - - if (uri.Host.EqualsIgnoringCase(SubscriptionManager.REFRESH_ACCOUNT_COMMAND)) - { - await _upgradeModalManager.CheckForVpnPlanUpgradeAsync(modalSource, notificationReference); - await _announcementService.UpdateAsync(); - } - } - } -} \ No newline at end of file diff --git a/src/ProtonVPN.App/Core/Service/Vpn/ClientControllerEventHandler.cs b/src/ProtonVPN.App/Core/Service/Vpn/ClientControllerEventHandler.cs new file mode 100644 index 000000000..21e9a5f7a --- /dev/null +++ b/src/ProtonVPN.App/Core/Service/Vpn/ClientControllerEventHandler.cs @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using ProtonVPN.ProcessCommunication.Contracts.Entities.NetShield; +using ProtonVPN.ProcessCommunication.Contracts.Entities.PortForwarding; +using ProtonVPN.ProcessCommunication.Contracts.Entities.Update; +using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; +using System; + +namespace ProtonVPN.Core.Service.Vpn +{ + public class ClientControllerEventHandler : IClientControllerEventHandler + { + public event EventHandler OnVpnStateChanged; + public event EventHandler OnPortForwardingStateChanged; + public event EventHandler OnConnectionDetailsChanged; + public event EventHandler OnNetShieldStatisticChanged; + public event EventHandler OnUpdateStateChanged; + public event EventHandler OnOpenWindowInvoked; + + public void InvokeVpnStateChanged(VpnStateIpcEntity entity) + { + OnVpnStateChanged?.Invoke(this, entity); + } + + public void InvokePortForwardingStateChanged(PortForwardingStateIpcEntity entity) + { + OnPortForwardingStateChanged?.Invoke(this, entity); + } + + public void InvokeConnectionDetailsChanged(ConnectionDetailsIpcEntity entity) + { + OnConnectionDetailsChanged?.Invoke(this, entity); + } + + public void InvokeNetShieldStatisticChanged(NetShieldStatisticIpcEntity entity) + { + OnNetShieldStatisticChanged?.Invoke(this, entity); + } + + public void InvokeUpdateStateChanged(UpdateStateIpcEntity entity) + { + OnUpdateStateChanged?.Invoke(this, entity); + } + + public void InvokeOpenWindowInvoked() + { + OnOpenWindowInvoked?.Invoke(this, null); + } + } +} diff --git a/src/ProtonVPN.App/Core/Service/Vpn/ClientControllerListener.cs b/src/ProtonVPN.App/Core/Service/Vpn/ClientControllerListener.cs new file mode 100644 index 000000000..099984af4 --- /dev/null +++ b/src/ProtonVPN.App/Core/Service/Vpn/ClientControllerListener.cs @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2023 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System; +using System.Collections.Specialized; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using System.Windows; +using ProtonVPN.Account; +using ProtonVPN.Announcements.Contracts; +using ProtonVPN.Common.Extensions; +using ProtonVPN.Core.Service; +using ProtonVPN.Core.Service.Vpn; +using ProtonVPN.Logging.Contracts; +using ProtonVPN.Logging.Contracts.Events.AppLogs; +using ProtonVPN.Logging.Contracts.Events.ProcessCommunicationLogs; +using ProtonVPN.ProcessCommunication.Contracts; +using ProtonVPN.ProcessCommunication.Contracts.Entities.NetShield; +using ProtonVPN.ProcessCommunication.Contracts.Entities.PortForwarding; +using ProtonVPN.ProcessCommunication.Contracts.Entities.Update; +using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; + +namespace ProtonVPN.Client.Logic.Connection; + +public class ClientControllerListener : IClientControllerListener +{ + private readonly ILogger _logger; + private readonly IGrpcClient _grpcClient; + private readonly IMonitoredVpnService _monitoredVpnService; + private readonly IAnnouncementService _announcementService; + private readonly IUpgradeModalManager _upgradeModalManager; + private readonly IClientControllerEventHandler _clientControllerEventHandler; + private readonly CancellationTokenSource _cancellationTokenSource = new(); + + public ClientControllerListener(ILogger logger, + IGrpcClient grpcClient, + IMonitoredVpnService monitoredVpnService, + IAnnouncementService announcementService, + IUpgradeModalManager upgradeModalManager, + IClientControllerEventHandler clientControllerEventHandler) + { + _logger = logger; + _grpcClient = grpcClient; + _monitoredVpnService = monitoredVpnService; + _announcementService = announcementService; + _upgradeModalManager = upgradeModalManager; + _clientControllerEventHandler = clientControllerEventHandler; + } + + public void Start() + { + KeepAliveAsync(StartVpnStateListenerAsync); + KeepAliveAsync(StartPortForwardingStateListenerAsync); + KeepAliveAsync(StartConnectionDetailsListenerAsync); + KeepAliveAsync(StartUpdateStateListenerAsync); + KeepAliveAsync(StartNetShieldStatisticListenerAsync); + KeepAliveAsync(StartOpenWindowListenerAsync); + } + + private async Task KeepAliveAsync(Func listener) + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + await listener(); + } + catch + { + _logger.Warn($"Listener stopped ({listener.Method.Name}). Restarting."); + } + await StartServiceIfStoppedAsync(); + } + } + + private async Task StartServiceIfStoppedAsync() + { + await _monitoredVpnService.StartIfNotRunningAsync(); + } + + private async Task StartVpnStateListenerAsync() + { + await foreach (VpnStateIpcEntity state in _grpcClient.ClientController.StreamVpnStateChangeAsync()) + { + + _logger.Debug($"Received VPN Status '{state.Status}', " + + $"NetworkBlocked: {state.NetworkBlocked} Error: '{state.Error}', EndpointIp: '{state.EndpointIp}', " + + $"Label: '{state.Label}', VpnProtocol: '{state.VpnProtocol}', OpenVpnAdapter: '{state.OpenVpnAdapterType}'"); + InvokeOnUiThread(() => { _clientControllerEventHandler.InvokeVpnStateChanged(state); }); + } + } + + private void InvokeOnUiThread(Action action) + { + Application.Current?.Dispatcher?.Invoke(action); + } + + private async Task StartPortForwardingStateListenerAsync() + { + await foreach (PortForwardingStateIpcEntity state in + _grpcClient.ClientController.StreamPortForwardingStateChangeAsync()) + { + StringBuilder logMessage = new StringBuilder().Append("Received PortForwarding " + + $"Status '{state.Status}' triggered at '{state.TimestampUtc}'"); + if (state.MappedPort is not null) + { + TemporaryMappedPortIpcEntity mappedPort = state.MappedPort; + logMessage.Append($", Port pair {mappedPort.InternalPort}->{mappedPort.ExternalPort}, expiring in " + + $"{mappedPort.Lifetime} at {mappedPort.ExpirationDateUtc}"); + } + _logger.Debug(logMessage.ToString()); + InvokeOnUiThread(() => _clientControllerEventHandler.InvokePortForwardingStateChanged(state)); + } + } + + private async Task StartConnectionDetailsListenerAsync() + { + await foreach (ConnectionDetailsIpcEntity connectionDetails in + _grpcClient.ClientController.StreamConnectionDetailsChangeAsync()) + { + _logger.Debug($"Received connection details change while " + + $"connected to server with IP '{connectionDetails.ServerIpAddress}'"); + InvokeOnUiThread(() => _clientControllerEventHandler.InvokeConnectionDetailsChanged(connectionDetails)); + } + } + + private async Task StartUpdateStateListenerAsync() + { + await foreach (UpdateStateIpcEntity state in + _grpcClient.ClientController.StreamUpdateStateChangeAsync()) + { + _logger.Debug( + $"Received update state change with status {state.Status}."); + InvokeOnUiThread(() => _clientControllerEventHandler.InvokeUpdateStateChanged(state)); + } + } + + private async Task StartNetShieldStatisticListenerAsync() + { + await foreach (NetShieldStatisticIpcEntity netShieldStatistic in + _grpcClient.ClientController.StreamNetShieldStatisticChangeAsync()) + { + _logger.Debug( + $"Received NetShield statistic change with timestamp '{netShieldStatistic.TimestampUtc}' " + + $"[Ads: '{netShieldStatistic.NumOfAdvertisementUrlsBlocked}']" + + $"[Malware: '{netShieldStatistic.NumOfMaliciousUrlsBlocked}']" + + $"[Trackers: '{netShieldStatistic.NumOfTrackingUrlsBlocked}']"); + InvokeOnUiThread(() => _clientControllerEventHandler.InvokeNetShieldStatisticChanged(netShieldStatistic)); + } + } + + private async Task StartOpenWindowListenerAsync() + { + await foreach (string args in _grpcClient.ClientController.StreamOpenWindowAsync()) + { + _logger.Debug("Received open window request."); + await ProcessCommandArgumentsAsync(args); + InvokeOnUiThread(() => _clientControllerEventHandler.InvokeOpenWindowInvoked()); + } + } + + private async Task ProcessCommandArgumentsAsync(string args) + { + if (Uri.TryCreate(args, UriKind.Absolute, out Uri uri)) + { + await ProcessCommandUriArgumentAsync(uri); + } + } + + private async Task ProcessCommandUriArgumentAsync(Uri uri) + { + string modalSource = null; + string notificationReference = null; + + NameValueCollection uriQuery = HttpUtility.ParseQueryString(uri.Query); + foreach (string queryKey in uriQuery.AllKeys) + { + if (queryKey.EqualsIgnoringCase("delete-notification-id")) + { + _announcementService.Delete(uriQuery[queryKey]); + } + else if (queryKey.EqualsIgnoringCase("notification-reference")) + { + _announcementService.DeleteByReference(uriQuery[queryKey]); + notificationReference = uriQuery[queryKey]; + } + else if (queryKey.EqualsIgnoringCase("modal-source")) + { + modalSource = uriQuery[queryKey]; + } + } + + if (uri.Host.EqualsIgnoringCase(SubscriptionManager.REFRESH_ACCOUNT_COMMAND)) + { + await _upgradeModalManager.CheckForVpnPlanUpgradeAsync(modalSource, notificationReference); + await _announcementService.UpdateAsync(); + } + } + + public void Stop() + { + _cancellationTokenSource.Cancel(); + } +} diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IAppController.cs b/src/ProtonVPN.App/Core/Service/Vpn/IClientControllerEventHandler.cs similarity index 69% rename from src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IAppController.cs rename to src/ProtonVPN.App/Core/Service/Vpn/IClientControllerEventHandler.cs index 1e893cf73..147662d52 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Controllers/IAppController.cs +++ b/src/ProtonVPN.App/Core/Service/Vpn/IClientControllerEventHandler.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Proton AG + * Copyright (c) 2024 Proton AG * * This file is part of ProtonVPN. * @@ -17,16 +17,15 @@ * along with ProtonVPN. If not, see . */ -using System.ServiceModel; using ProtonVPN.ProcessCommunication.Contracts.Entities.NetShield; using ProtonVPN.ProcessCommunication.Contracts.Entities.PortForwarding; using ProtonVPN.ProcessCommunication.Contracts.Entities.Update; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; +using System; -namespace ProtonVPN.ProcessCommunication.Contracts.Controllers +namespace ProtonVPN.Core.Service.Vpn { - [ServiceContract] - public interface IAppController + public interface IClientControllerEventHandler { event EventHandler OnVpnStateChanged; event EventHandler OnPortForwardingStateChanged; @@ -35,12 +34,11 @@ public interface IAppController event EventHandler OnUpdateStateChanged; event EventHandler OnOpenWindowInvoked; - Task VpnStateChange(VpnStateIpcEntity vpnState); - Task PortForwardingStateChange(PortForwardingStateIpcEntity portForwardingState); - Task ConnectionDetailsChange(ConnectionDetailsIpcEntity connectionDetails); - Task NetShieldStatisticChange(NetShieldStatisticIpcEntity netShieldStatistic); - Task UpdateStateChange(UpdateStateIpcEntity updateState); - - Task OpenWindow(string args); + void InvokeVpnStateChanged(VpnStateIpcEntity entity); + void InvokePortForwardingStateChanged(PortForwardingStateIpcEntity entity); + void InvokeConnectionDetailsChanged(ConnectionDetailsIpcEntity entity); + void InvokeNetShieldStatisticChanged(NetShieldStatisticIpcEntity entity); + void InvokeUpdateStateChanged(UpdateStateIpcEntity entity); + void InvokeOpenWindowInvoked(); } -} \ No newline at end of file +} diff --git a/src/ProtonVPN.App/Core/Service/Vpn/IClientControllerListener.cs b/src/ProtonVPN.App/Core/Service/Vpn/IClientControllerListener.cs new file mode 100644 index 000000000..d71dc5818 --- /dev/null +++ b/src/ProtonVPN.App/Core/Service/Vpn/IClientControllerListener.cs @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +namespace ProtonVPN.Core.Service.Vpn +{ + public interface IClientControllerListener + { + void Start(); + void Stop(); + } +} \ No newline at end of file diff --git a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Channels/IGrpcChannelWrapperFactory.cs b/src/ProtonVPN.App/Core/Service/Vpn/IProcessCommunicationStarter.cs similarity index 81% rename from src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Channels/IGrpcChannelWrapperFactory.cs rename to src/ProtonVPN.App/Core/Service/Vpn/IProcessCommunicationStarter.cs index e83255d46..13b806263 100644 --- a/src/ProcessCommunication/ProtonVPN.ProcessCommunication.Common/Channels/IGrpcChannelWrapperFactory.cs +++ b/src/ProtonVPN.App/Core/Service/Vpn/IProcessCommunicationStarter.cs @@ -17,10 +17,9 @@ * along with ProtonVPN. If not, see . */ -namespace ProtonVPN.ProcessCommunication.Common.Channels +namespace ProtonVPN.Core.Service.Vpn; + +public interface IProcessCommunicationStarter { - public interface IGrpcChannelWrapperFactory - { - IGrpcChannelWrapper Create(int serverPort); - } + void Start(); } \ No newline at end of file diff --git a/src/ProtonVPN.App/Core/Service/Vpn/ProcessCommunicationStarter.cs b/src/ProtonVPN.App/Core/Service/Vpn/ProcessCommunicationStarter.cs new file mode 100644 index 000000000..27c94f50e --- /dev/null +++ b/src/ProtonVPN.App/Core/Service/Vpn/ProcessCommunicationStarter.cs @@ -0,0 +1,56 @@ +/* +/* + * Copyright (c) 2023 Proton AG + * + * This file is part of ProtonVPN. + * + * ProtonVPN is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ProtonVPN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ProtonVPN. If not, see . + */ + +using System; +using ProtonVPN.Logging.Contracts; +using ProtonVPN.Logging.Contracts.Events.AppServiceLogs; +using ProtonVPN.ProcessCommunication.Contracts; + +namespace ProtonVPN.Core.Service.Vpn; + +public class ProcessCommunicationStarter : IProcessCommunicationStarter +{ + private readonly IGrpcClient _grpcClient; + private readonly ILogger _logger; + private readonly IClientControllerListener _clientControllerListener; + + public ProcessCommunicationStarter(IGrpcClient grpcClient, + ILogger logger, + IClientControllerListener clientControllerListener) + { + _grpcClient = grpcClient; + _logger = logger; + _clientControllerListener = clientControllerListener; + } + + public void Start() + { + try + { + _grpcClient.Create(); + _clientControllerListener.Start(); + } + catch (Exception e) + { + _logger.Error("An error occurred when starting the gRPC client.", e); + throw; + } + } +} diff --git a/src/ProtonVPN.App/Core/Service/Vpn/VpnReconnector.cs b/src/ProtonVPN.App/Core/Service/Vpn/VpnReconnector.cs index 49c093d06..a3e1f90ee 100644 --- a/src/ProtonVPN.App/Core/Service/Vpn/VpnReconnector.cs +++ b/src/ProtonVPN.App/Core/Service/Vpn/VpnReconnector.cs @@ -280,7 +280,7 @@ private async Task ExecuteReconnectionAsync(VpnReconnectionSteps reconnectionSte private async Task ConnectToSimilarServerOrQuickConnectAsync(bool isToTryLastServer, VpnProtocol vpnProtocol) { IList serverCandidates = _similarServerCandidatesGenerator.Generate(isToTryLastServer, _targetServer, _targetProfile); - if (!ServerFeatures.IsB2B((ulong)_targetProfile.Features)) + if (_targetProfile is null || !ServerFeatures.IsB2B((ulong)_targetProfile.Features)) { IEnumerable quickConnectServers = (await _vpnConnector.GetSortedAndValidQuickConnectServersAsync( _config.MaxQuickConnectServersOnReconnection)).Except(serverCandidates); diff --git a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceActionDecorator.cs b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceActionDecorator.cs index ac0b14745..50bdd0c06 100644 --- a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceActionDecorator.cs +++ b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceActionDecorator.cs @@ -59,11 +59,11 @@ await InvokeAction(async () => }); } - public async Task UpdateAuthCertificate(string certificate) + public async Task UpdateAuthCertificate(string certificate, DateTimeOffset? expirationDateUtc) { await InvokeAction(async () => { - await _decorated.UpdateAuthCertificate(certificate); + await _decorated.UpdateAuthCertificate(certificate, expirationDateUtc); return Result.Ok(); }); } diff --git a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceCaller.cs b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceCaller.cs index f485cda5f..ba4667717 100644 --- a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceCaller.cs +++ b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceCaller.cs @@ -17,6 +17,7 @@ * along with ProtonVPN. If not, see . */ +using System; using System.Threading.Tasks; using ProtonVPN.Common.Abstract; using ProtonVPN.Common.Extensions; @@ -24,7 +25,6 @@ using ProtonVPN.ProcessCommunication.Contracts; using ProtonVPN.ProcessCommunication.Contracts.Controllers; using ProtonVPN.ProcessCommunication.Contracts.Entities.Auth; -using ProtonVPN.ProcessCommunication.Contracts.Entities.Communication; using ProtonVPN.ProcessCommunication.Contracts.Entities.Settings; using ProtonVPN.ProcessCommunication.Contracts.Entities.Vpn; @@ -32,49 +32,44 @@ namespace ProtonVPN.Core.Service.Vpn { public class VpnServiceCaller : ServiceControllerCaller { - public VpnServiceCaller(ILogger logger, IAppGrpcClient grpcClient, VpnSystemService vpnSystemService) - : base(logger, grpcClient, vpnSystemService) + public VpnServiceCaller(ILogger logger, IGrpcClient grpcClient, Lazy monitoredVpnService) + : base(logger, grpcClient, monitoredVpnService) { } public Task ApplySettings(MainSettingsIpcEntity settings) { - return Invoke(c => c.ApplySettings(settings).Wrap()); + return Invoke((c, ct) => c.ApplySettings(settings, ct).Wrap()); } public Task Connect(ConnectionRequestIpcEntity connectionRequest) { - return Invoke(c => c.Connect(connectionRequest).Wrap()); + return Invoke((c, ct) => c.Connect(connectionRequest, ct).Wrap()); } - public Task UpdateAuthCertificate(AuthCertificateIpcEntity certificate) + public Task UpdateConnectionCertificate(ConnectionCertificateIpcEntity certificate) { - return Invoke(c => c.UpdateAuthCertificate(certificate).Wrap()); + return Invoke((c, ct) => c.UpdateConnectionCertificate(certificate, ct).Wrap()); } public Task Disconnect(DisconnectionRequestIpcEntity disconnectionRequest) { - return Invoke(c => c.Disconnect(disconnectionRequest).Wrap()); + return Invoke((c, ct) => c.Disconnect(disconnectionRequest, ct).Wrap()); } public Task RepeatState() { - return Invoke(c => c.RepeatState().Wrap()); + return Invoke((c, ct) => c.RepeatState(ct).Wrap()); } public Task> GetTrafficBytes() { - return Invoke(c => c.GetTrafficBytes()); + return Invoke((c, ct) => c.GetTrafficBytes(ct)); } public Task RequestNetShieldStats() { - return Invoke(c => c.RequestNetShieldStats().Wrap()); - } - - public Task RegisterVpnClient(int port) - { - return Invoke(c => c.RegisterStateConsumer(new StateConsumerIpcEntity { ServerPort = port }).Wrap()); + return Invoke((c, ct) => c.RequestNetShieldStats(ct).Wrap()); } } } \ No newline at end of file diff --git a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceManager.cs b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceManager.cs index 120108a84..2004ccc74 100644 --- a/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceManager.cs +++ b/src/ProtonVPN.App/Core/Service/Vpn/VpnServiceManager.cs @@ -22,15 +22,14 @@ using System.Threading.Tasks; using ProtonVPN.Common.Abstract; using ProtonVPN.Common.Helpers; -using ProtonVPN.Logging.Contracts; -using ProtonVPN.Logging.Contracts.Events.DisconnectLogs; using ProtonVPN.Common.NetShield; using ProtonVPN.Common.PortForwarding; using ProtonVPN.Common.Vpn; using ProtonVPN.Core.Service.Settings; using ProtonVPN.Core.Vpn; using ProtonVPN.EntityMapping.Contracts; -using ProtonVPN.ProcessCommunication.Contracts.Controllers; +using ProtonVPN.Logging.Contracts; +using ProtonVPN.Logging.Contracts.Events.DisconnectLogs; using ProtonVPN.ProcessCommunication.Contracts.Entities.Auth; using ProtonVPN.ProcessCommunication.Contracts.Entities.NetShield; using ProtonVPN.ProcessCommunication.Contracts.Entities.PortForwarding; @@ -43,7 +42,7 @@ public class VpnServiceManager : IVpnServiceManager private readonly VpnServiceCaller _vpnServiceCaller; private readonly MainSettingsProvider _settingsContractProvider; private readonly ILogger _logger; - private readonly IAppController _appController; + private readonly IClientControllerEventHandler _clientControllerEventHandler; private readonly IEntityMapper _entityMapper; private Action _vpnStateCallback; private Action _portForwardingStateCallback; @@ -54,18 +53,18 @@ public VpnServiceManager( VpnServiceCaller vpnServiceCaller, MainSettingsProvider settingsContractProvider, ILogger logger, - IAppController appController, + IClientControllerEventHandler clientControllerEventHandler, IEntityMapper entityMapper) { _vpnServiceCaller = vpnServiceCaller; _settingsContractProvider = settingsContractProvider; _logger = logger; - _appController = appController; + _clientControllerEventHandler = clientControllerEventHandler; _entityMapper = entityMapper; - _appController.OnVpnStateChanged += OnVpnStateChanged; - _appController.OnPortForwardingStateChanged += OnPortForwardingStateChanged; - _appController.OnConnectionDetailsChanged += OnConnectionDetailsChanged; - _appController.OnNetShieldStatisticChanged += OnNetShieldStatisticChanged; + _clientControllerEventHandler.OnVpnStateChanged += OnVpnStateChanged; + _clientControllerEventHandler.OnPortForwardingStateChanged += OnPortForwardingStateChanged; + _clientControllerEventHandler.OnConnectionDetailsChanged += OnConnectionDetailsChanged; + _clientControllerEventHandler.OnNetShieldStatisticChanged += OnNetShieldStatisticChanged; } private void OnConnectionDetailsChanged(object sender, ConnectionDetailsIpcEntity connectionDetails) @@ -113,9 +112,13 @@ public async Task Connect(VpnConnectionRequest request) await _vpnServiceCaller.Connect(connectionRequest); } - public async Task UpdateAuthCertificate(string certificate) + public async Task UpdateAuthCertificate(string certificate, DateTimeOffset? expirationDateUtc) { - await _vpnServiceCaller.UpdateAuthCertificate(new AuthCertificateIpcEntity() { Certificate = certificate }); + await _vpnServiceCaller.UpdateConnectionCertificate(new ConnectionCertificateIpcEntity() + { + Pem = certificate, + ExpirationDateUtc = expirationDateUtc?.UtcDateTime ?? DateTime.MinValue + }); } public async Task GetTrafficBytes() @@ -140,6 +143,7 @@ public Task Disconnect(VpnError vpnError = VpnError.None, sourceFilePath: sourceFilePath, sourceMemberName: sourceMemberName, sourceLineNumber: sourceLineNumber); DisconnectionRequestIpcEntity disconnectionRequest = new() { + RetryId = Guid.NewGuid(), Settings = _settingsContractProvider.Create(), ErrorType = (VpnErrorTypeIpcEntity)vpnError }; diff --git a/src/ProtonVPN.App/Core/SingleInstanceApplication.cs b/src/ProtonVPN.App/Core/SingleInstanceApplication.cs index 1ef5d7077..48588b86c 100644 --- a/src/ProtonVPN.App/Core/SingleInstanceApplication.cs +++ b/src/ProtonVPN.App/Core/SingleInstanceApplication.cs @@ -19,7 +19,7 @@ using System.Threading; using System.Threading.Tasks; -using ProtonVPN.ProcessCommunication.App.Installers; +using ProtonVPN.ProcessCommunication.Client.Installers; namespace ProtonVPN.Core { diff --git a/src/ProtonVPN.App/Modals/Upsell/NonStandardPortsUpsellModalView.xaml b/src/ProtonVPN.App/Modals/Upsell/NonStandardPortsUpsellModalView.xaml deleted file mode 100644 index 95767a691..000000000 --- a/src/ProtonVPN.App/Modals/Upsell/NonStandardPortsUpsellModalView.xaml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - -