diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f9b3edea2..c2188b913 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,6 +24,11 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v3.2.0 + with: + dotnet-version: 8.0.x + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v2 diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 7562447fc..41930943b 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -21,7 +21,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 6.0.201 + dotnet-version: 8.0.x - name: Install dependencies run: dotnet restore @@ -37,9 +37,9 @@ jobs: shell: bash run: | mkdir -p artifacts/bin - mv out/windows/Installer.Windows/bin/Release/net472/win-x86 artifacts/bin/ - cp out/windows/Installer.Windows/bin/Release/net472/win-x86.sym/* artifacts/bin/win-x86/ - mv out/windows/Installer.Windows/bin/Release/net472/gcm*.exe artifacts/ + mv out/windows/Installer.Windows/bin/Release/net8.0/win-x86 artifacts/bin/ + cp out/windows/Installer.Windows/bin/Release/net8.0/win-x86.sym/* artifacts/bin/win-x86/ + mv out/windows/Installer.Windows/bin/Release/net8.0/gcm*.exe artifacts/ - name: Upload artifacts uses: actions/upload-artifact@v3 @@ -61,7 +61,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 6.0.201 + dotnet-version: 8.0.x - name: Install dependencies run: dotnet restore @@ -102,7 +102,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 6.0.201 + dotnet-version: 8.0.x - name: Install dependencies run: dotnet restore diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 82ec3b1b6..ce21cf277 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,7 +37,7 @@ jobs: - name: Set up .NET uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Build run: | @@ -152,7 +152,7 @@ jobs: - name: Set up .NET uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Build run: | @@ -192,7 +192,7 @@ jobs: - name: Set up .NET uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Build with signed payload run: | @@ -200,7 +200,7 @@ jobs: /p:PayloadPath=$env:GITHUB_WORKSPACE\payload /p:NoLayout=true ` --configuration=WindowsRelease mkdir installers - Move-Item -Path .\out\windows\Installer.Windows\bin\Release\net472\*.exe ` + Move-Item -Path .\out\windows\Installer.Windows\bin\Release\net8.0\*.exe ` -Destination $env:GITHUB_WORKSPACE\installers - name: Sign installers with Azure Code Signing @@ -238,7 +238,7 @@ jobs: - name: Set up .NET uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Build run: dotnet build --configuration=LinuxRelease @@ -316,7 +316,7 @@ jobs: - name: Set up .NET uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Build .NET tool run: | @@ -410,7 +410,7 @@ jobs: - name: Set up .NET uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Package tool run: | @@ -523,7 +523,7 @@ jobs: - name: Set up .NET uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Download artifacts uses: actions/download-artifact@v3 @@ -593,7 +593,7 @@ jobs: - name: Set up .NET uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Download artifacts uses: actions/download-artifact@v3 diff --git a/.vscode/launch.json b/.vscode/launch.json index af72a8e27..d9b004b86 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/out/shared/Git-Credential-Manager/bin/Debug/net7.0/git-credential-manager.dll", + "program": "${workspaceFolder}/out/shared/Git-Credential-Manager/bin/Debug/net8.0/git-credential-manager.dll", "args": ["get"], "cwd": "${workspaceFolder}/out/shared/Git-Credential-Manager", "console": "integratedTerminal", @@ -22,7 +22,7 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/out/shared/Git-Credential-Manager/bin/Debug/net7.0/git-credential-manager.dll", + "program": "${workspaceFolder}/out/shared/Git-Credential-Manager/bin/Debug/net8.0/git-credential-manager.dll", "args": ["store"], "cwd": "${workspaceFolder}/out/shared/Git-Credential-Manager", "console": "integratedTerminal", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e47892848..c559b17b8 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -56,7 +56,7 @@ "type": "shell", "group": "test", "args": [ - "~/.nuget/packages/reportgenerator/*/*/net7.0/ReportGenerator.dll", + "~/.nuget/packages/reportgenerator/*/*/net8.0/ReportGenerator.dll", "-reports:${workspaceFolder}/**/TestResults/**/coverage.cobertura.xml", "-targetdir:${workspaceFolder}/out/code-coverage" ], @@ -71,7 +71,7 @@ "type": "shell", "group": "test", "args": [ - "${env:USERROFILE}/.nuget/packages/reportgenerator/*/*/net7.0/ReportGenerator.dll", + "${env:USERROFILE}/.nuget/packages/reportgenerator/*/*/net8.0/ReportGenerator.dll", "-reports:${workspaceFolder}/**/TestResults/**/coverage.cobertura.xml", "-targetdir:${workspaceFolder}/out/code-coverage" ], diff --git a/Directory.Build.props b/Directory.Build.props index 8c94238ca..d8c53e0bb 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -26,10 +26,4 @@ true - - - 7.0.2 - - - diff --git a/Directory.Build.targets b/Directory.Build.targets index 72d4712e7..690a82653 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -33,4 +33,9 @@ + + + $(NoWarn);CA1416 + + diff --git a/build/GCM.MSBuild.csproj b/build/GCM.MSBuild.csproj index 02f5a8444..3df4909e6 100644 --- a/build/GCM.MSBuild.csproj +++ b/build/GCM.MSBuild.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/docs/development.md b/docs/development.md index 31350192a..75f9fd0cf 100644 --- a/docs/development.md +++ b/docs/development.md @@ -40,9 +40,9 @@ To build from the command line, run: dotnet build -c WindowsDebug ``` -You can find a copy of the installer .exe file in `out\windows\Installer.Windows\bin\Debug\net472`. +You can find a copy of the installer .exe file in `out\windows\Installer.Windows\bin\Debug\net8.0`. -The flat binaries can also be found in `out\windows\Payload.Windows\bin\Debug\net472\win-x86`. +The flat binaries can also be found in `out\windows\Payload.Windows\bin\Debug\net8.0\win-x86`. ### Linux @@ -209,13 +209,13 @@ HTML reports can be generated using ReportGenerator, this should be installed during the build process, from the command line: ```shell -dotnet ~/.nuget/packages/reportgenerator/*/*/net7.0/ReportGenerator.dll -reports:./**/TestResults/**/coverage.cobertura.xml -targetdir:./out/code-coverage +dotnet ~/.nuget/packages/reportgenerator/*/*/net8.0/ReportGenerator.dll -reports:./**/TestResults/**/coverage.cobertura.xml -targetdir:./out/code-coverage ``` or ```shell -dotnet {$env:USERPROFILE}/.nuget/packages/reportgenerator/*/*/net7.0/ReportGenerator.dll -reports:./**/TestResults/**/coverage.cobertura.xml -targetdir:./out/code-coverage +dotnet {$env:USERPROFILE}/.nuget/packages/reportgenerator/*/*/net8.0/ReportGenerator.dll -reports:./**/TestResults/**/coverage.cobertura.xml -targetdir:./out/code-coverage ``` Or via VSCode Terminal/Run Task: diff --git a/src/linux/Packaging.Linux/Packaging.Linux.csproj b/src/linux/Packaging.Linux/Packaging.Linux.csproj index 362ffc230..8b9755c78 100644 --- a/src/linux/Packaging.Linux/Packaging.Linux.csproj +++ b/src/linux/Packaging.Linux/Packaging.Linux.csproj @@ -3,7 +3,7 @@ - net7.0 + net8.0 false diff --git a/src/linux/Packaging.Linux/install-from-source.sh b/src/linux/Packaging.Linux/install-from-source.sh index 98fe7bc4d..c6a7a10fc 100755 --- a/src/linux/Packaging.Linux/install-from-source.sh +++ b/src/linux/Packaging.Linux/install-from-source.sh @@ -157,7 +157,7 @@ case "$distribution" in # Install dotnet packages and dependencies if needed. if [ -z "$(verify_existing_dotnet_installation)" ]; then # First try to use native feeds (Ubuntu 22.04 and later). - if ! apt_install dotnet7; then + if ! apt_install dotnet8; then # If the native feeds fail, we fall back to # packages.microsoft.com. We begin by adding the dotnet package # repository/signing key. diff --git a/src/linux/Packaging.Linux/layout.sh b/src/linux/Packaging.Linux/layout.sh index 5f3ba8ca8..0f174636b 100755 --- a/src/linux/Packaging.Linux/layout.sh +++ b/src/linux/Packaging.Linux/layout.sh @@ -38,7 +38,7 @@ GCM_SRC="$SRC/shared/Git-Credential-Manager" PROJ_OUT="$OUT/linux/Packaging.Linux" # Build parameters -FRAMEWORK=net7.0 +FRAMEWORK=net8.0 RUNTIME=linux-x64 # Perform pre-execution checks @@ -74,7 +74,6 @@ $DOTNET_ROOT/dotnet publish "$GCM_SRC" \ --framework="$FRAMEWORK" \ --runtime="$RUNTIME" \ --self-contained \ - -p:PublishSingleFile=true \ --output="$(make_absolute "$PAYLOAD")" || exit 1 # Collect symbols diff --git a/src/osx/Installer.Mac/Installer.Mac.csproj b/src/osx/Installer.Mac/Installer.Mac.csproj index e46022374..daabd20d4 100644 --- a/src/osx/Installer.Mac/Installer.Mac.csproj +++ b/src/osx/Installer.Mac/Installer.Mac.csproj @@ -3,7 +3,7 @@ - net7.0 + net8.0 false diff --git a/src/osx/Installer.Mac/layout.sh b/src/osx/Installer.Mac/layout.sh index 544b7e106..293c3a43a 100755 --- a/src/osx/Installer.Mac/layout.sh +++ b/src/osx/Installer.Mac/layout.sh @@ -21,10 +21,9 @@ SRC="$ROOT/src" OUT="$ROOT/out" INSTALLER_SRC="$SRC/osx/Installer.Mac" GCM_SRC="$SRC/shared/Git-Credential-Manager" -GCM_UI_SRC="$SRC/shared/Git-Credential-Manager.UI.Avalonia" # Build parameters -FRAMEWORK=net7.0 +FRAMEWORK=net8.0 # Parse script arguments for i in "$@" diff --git a/src/shared/Atlassian.Bitbucket.Tests/Atlassian.Bitbucket.Tests.csproj b/src/shared/Atlassian.Bitbucket.Tests/Atlassian.Bitbucket.Tests.csproj index 0e3c94c22..d5d08797c 100644 --- a/src/shared/Atlassian.Bitbucket.Tests/Atlassian.Bitbucket.Tests.csproj +++ b/src/shared/Atlassian.Bitbucket.Tests/Atlassian.Bitbucket.Tests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false true latest diff --git a/src/shared/Atlassian.Bitbucket/Atlassian.Bitbucket.csproj b/src/shared/Atlassian.Bitbucket/Atlassian.Bitbucket.csproj index af8285c72..d50785fa7 100644 --- a/src/shared/Atlassian.Bitbucket/Atlassian.Bitbucket.csproj +++ b/src/shared/Atlassian.Bitbucket/Atlassian.Bitbucket.csproj @@ -1,8 +1,7 @@  - net7.0 - net7.0;net472 + net8.0 Atlassian.Bitbucket Atlassian.Bitbucket false @@ -13,10 +12,6 @@ - - - - diff --git a/src/shared/Atlassian.Bitbucket/BitbucketJsonSerializerContext.cs b/src/shared/Atlassian.Bitbucket/BitbucketJsonSerializerContext.cs new file mode 100644 index 000000000..08436a42d --- /dev/null +++ b/src/shared/Atlassian.Bitbucket/BitbucketJsonSerializerContext.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace Atlassian.Bitbucket; + +[JsonSourceGenerationOptions( + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNameCaseInsensitive = true +)] +[JsonSerializable(typeof(BitbucketTokenEndpointResponseJson))] +[JsonSerializable(typeof(Cloud.UserInfo), TypeInfoPropertyName = "Cloud_UserInfo")] +[JsonSerializable(typeof(DataCenter.UserInfo), TypeInfoPropertyName = "DataCenter_UserInfo")] +[JsonSerializable(typeof(DataCenter.LoginOptions))] +internal partial class BitbucketJsonSerializerContext : JsonSerializerContext +{ +} diff --git a/src/shared/Atlassian.Bitbucket/BitbucketOAuth2Client.cs b/src/shared/Atlassian.Bitbucket/BitbucketOAuth2Client.cs index 1ca23d0f5..2311de44d 100644 --- a/src/shared/Atlassian.Bitbucket/BitbucketOAuth2Client.cs +++ b/src/shared/Atlassian.Bitbucket/BitbucketOAuth2Client.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using GitCredentialManager; @@ -42,7 +43,7 @@ protected override bool TryCreateTokenEndpointResult(string json, out OAuth2Toke // We override the token endpoint response parsing because the Bitbucket authority returns // the non-standard 'scopes' property for the list of scopes, rather than the (optional) // 'scope' (note the singular vs plural) property as outlined in the standard. - if (TryDeserializeJson(json, out BitbucketTokenEndpointResponseJson jsonObj)) + if (TryDeserializeJson(json, BitbucketJsonSerializerContext.Default, out BitbucketTokenEndpointResponseJson jsonObj)) { result = jsonObj.ToResult(); return true; diff --git a/src/shared/Atlassian.Bitbucket/Cloud/BitbucketRestApi.cs b/src/shared/Atlassian.Bitbucket/Cloud/BitbucketRestApi.cs index 94021e14d..c32f0aa9a 100644 --- a/src/shared/Atlassian.Bitbucket/Cloud/BitbucketRestApi.cs +++ b/src/shared/Atlassian.Bitbucket/Cloud/BitbucketRestApi.cs @@ -43,11 +43,7 @@ public async Task> GetUserInformationAsync(string userN if (response.IsSuccessStatusCode) { - var obj = JsonSerializer.Deserialize(json, - new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - }); + UserInfo obj = JsonSerializer.Deserialize(json, BitbucketJsonSerializerContext.Default.Cloud_UserInfo); return new RestApiResult(response.StatusCode, obj); } diff --git a/src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs b/src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs index 159229885..d6a128906 100644 --- a/src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs +++ b/src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs @@ -107,12 +107,7 @@ public async Task> GetAuthenticationMethodsAsync() if (response.IsSuccessStatusCode) { - var loginOptions = JsonSerializer.Deserialize(json, - new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - }); + LoginOptions loginOptions = JsonSerializer.Deserialize(json, BitbucketJsonSerializerContext.Default.LoginOptions); if (loginOptions.Results.Any(r => "LOGIN_FORM".Equals(r.Type))) { @@ -151,4 +146,4 @@ private Uri ApiUri } } } -} \ No newline at end of file +} diff --git a/src/shared/Atlassian.Bitbucket/UI/Views/CredentialsView.axaml b/src/shared/Atlassian.Bitbucket/UI/Views/CredentialsView.axaml index f74161a5c..126d0ebff 100644 --- a/src/shared/Atlassian.Bitbucket/UI/Views/CredentialsView.axaml +++ b/src/shared/Atlassian.Bitbucket/UI/Views/CredentialsView.axaml @@ -5,6 +5,8 @@ xmlns:vm="clr-namespace:Atlassian.Bitbucket.UI.ViewModels;assembly=Atlassian.Bitbucket" xmlns:converters="clr-namespace:GitCredentialManager.UI.Converters;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" + x:DataType="vm:CredentialsViewModel" + x:CompileBindings="True" x:Class="Atlassian.Bitbucket.UI.Views.CredentialsView"> diff --git a/src/shared/Core.Tests/Core.Tests.csproj b/src/shared/Core.Tests/Core.Tests.csproj index 4ee2d350e..db045a83b 100644 --- a/src/shared/Core.Tests/Core.Tests.csproj +++ b/src/shared/Core.Tests/Core.Tests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false true latest diff --git a/src/shared/Core/Authentication/AuthenticationBase.cs b/src/shared/Core/Authentication/AuthenticationBase.cs index 03e4d8ca6..ca3be4173 100644 --- a/src/shared/Core/Authentication/AuthenticationBase.cs +++ b/src/shared/Core/Authentication/AuthenticationBase.cs @@ -60,11 +60,7 @@ protected internal virtual async Task> InvokeHelperA // Write the standard input to the process if we have any to write if (standardInput is not null) { -#if NETFRAMEWORK - await standardInput.BaseStream.CopyToAsync(process.StandardInput.BaseStream); -#else await standardInput.BaseStream.CopyToAsync(process.StandardInput.BaseStream, ct); -#endif process.StandardInput.Close(); } diff --git a/src/shared/Core/Authentication/MicrosoftAuthentication.cs b/src/shared/Core/Authentication/MicrosoftAuthentication.cs index b39cc1a73..da6a979be 100644 --- a/src/shared/Core/Authentication/MicrosoftAuthentication.cs +++ b/src/shared/Core/Authentication/MicrosoftAuthentication.cs @@ -15,10 +15,7 @@ using GitCredentialManager.UI.ViewModels; using GitCredentialManager.UI.Views; using Microsoft.Identity.Client.AppConfig; - -#if NETFRAMEWORK using Microsoft.Identity.Client.Broker; -#endif namespace GitCredentialManager.Authentication { @@ -501,7 +498,6 @@ private async Task CreatePublicClientApplicationAsync( // to save on the distribution size of the .NET builds (no need for MSALRuntime bits). if (enableBroker) { -#if NETFRAMEWORK appBuilder.WithBroker( new BrokerOptions(BrokerOptions.OperatingSystems.Windows) { @@ -509,7 +505,6 @@ private async Task CreatePublicClientApplicationAsync( MsaPassthrough = msaPt, } ); -#endif } IPublicClientApplication app = appBuilder.Build(); @@ -801,7 +796,6 @@ public HttpClient GetHttpClient() public bool CanUseBroker() { -#if NETFRAMEWORK // We only support the broker on Windows 10+ and in an interactive session if (!Context.SessionManager.IsDesktopSession || !PlatformUtils.IsWindowsBrokerSupported()) { @@ -820,34 +814,27 @@ public bool CanUseBroker() } return defaultValue; -#else - // OS broker requires .NET Framework right now until we migrate to .NET 5.0 (net5.0-windows10.x.y.z) - return false; -#endif } private bool CanUseEmbeddedWebView() { - // If we're in an interactive session and on .NET Framework then MSAL can show the WinForms-based embedded UI -#if NETFRAMEWORK - return Context.SessionManager.IsDesktopSession; -#else - return false; -#endif + // If we're in an interactive session and on Windows then MSAL can show the WinForms-based embedded UI + return PlatformUtils.IsWindows() && Context.SessionManager.IsDesktopSession; } private void EnsureCanUseEmbeddedWebView() { -#if NETFRAMEWORK if (!Context.SessionManager.IsDesktopSession) { throw new Trace2InvalidOperationException(Context.Trace2, "Embedded web view is not available without a desktop session."); } -#else - throw new Trace2InvalidOperationException(Context.Trace2, - "Embedded web view is not available on .NET Core."); -#endif + + if (!PlatformUtils.IsWindows()) + { + throw new Trace2InvalidOperationException(Context.Trace2, + "Embedded web view is only available on Windows."); + } } private bool CanUseSystemWebView(IPublicClientApplication app, Uri redirectUri) diff --git a/src/shared/Core/Authentication/OAuth/Json/OAuthJsonSerializerContext.cs b/src/shared/Core/Authentication/OAuth/Json/OAuthJsonSerializerContext.cs new file mode 100644 index 000000000..13ac886c8 --- /dev/null +++ b/src/shared/Core/Authentication/OAuth/Json/OAuthJsonSerializerContext.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace GitCredentialManager.Authentication.OAuth.Json; + +[JsonSourceGenerationOptions( + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNameCaseInsensitive = true +)] +[JsonSerializable(typeof(DeviceAuthorizationEndpointResponseJson))] +[JsonSerializable(typeof(ErrorResponseJson))] +[JsonSerializable(typeof(TokenEndpointResponseJson))] +public partial class OAuthJsonSerializerContext : JsonSerializerContext +{ +} diff --git a/src/shared/Core/Authentication/OAuth/OAuth2Client.cs b/src/shared/Core/Authentication/OAuth/OAuth2Client.cs index 27834d2aa..8549d5abb 100644 --- a/src/shared/Core/Authentication/OAuth/OAuth2Client.cs +++ b/src/shared/Core/Authentication/OAuth/OAuth2Client.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using GitCredentialManager.Authentication.OAuth.Json; using System.Text.Json; +using System.Text.Json.Serialization; namespace GitCredentialManager.Authentication.OAuth { @@ -213,7 +214,8 @@ public async Task GetDeviceCodeAsync(IEnumerable { string json = await response.Content.ReadAsStringAsync(); - if (response.IsSuccessStatusCode && TryDeserializeJson(json, out DeviceAuthorizationEndpointResponseJson jsonObj)) + if (response.IsSuccessStatusCode && TryDeserializeJson(json, OAuthJsonSerializerContext.Default, + out DeviceAuthorizationEndpointResponseJson jsonObj)) { return jsonObj.ToResult(); } @@ -321,12 +323,9 @@ public async Task GetTokenByDeviceCodeAsync(OAuth2DeviceCodeR return result; } - var error = JsonSerializer.Deserialize(json, new JsonSerializerOptions - { - PropertyNameCaseInsensitive = true - }); + TryDeserializeJson(json, OAuthJsonSerializerContext.Default, out ErrorResponseJson error); - switch (error.Error) + switch (error?.Error) { case OAuth2Constants.DeviceAuthorization.Errors.AuthorizationPending: // Retry with the current polling interval value @@ -358,7 +357,7 @@ public async Task GetTokenByDeviceCodeAsync(OAuth2DeviceCodeR protected virtual bool TryCreateTokenEndpointResult(string json, out OAuth2TokenResult result) { - if (TryDeserializeJson(json, out TokenEndpointResponseJson jsonObj)) + if (TryDeserializeJson(json, OAuthJsonSerializerContext.Default, out TokenEndpointResponseJson jsonObj)) { result = jsonObj.ToResult(); return true; @@ -368,9 +367,9 @@ protected virtual bool TryCreateTokenEndpointResult(string json, out OAuth2Token return false; } - protected virtual bool TryCreateExceptionFromResponse(string json, out OAuth2Exception exception) + private static bool TryCreateExceptionFromResponse(string json, out OAuth2Exception exception) { - if (TryDeserializeJson(json, out ErrorResponseJson obj)) + if (TryDeserializeJson(json, OAuthJsonSerializerContext.Default, out ErrorResponseJson obj)) { exception = obj.ToException(); return true; @@ -397,7 +396,7 @@ private HttpRequestMessage CreateRequestMessage(HttpMethod method, Uri requestUr return request; } - protected Exception CreateExceptionFromResponse(string json) + private Exception CreateExceptionFromResponse(string json) { if (TryCreateExceptionFromResponse(json, out OAuth2Exception exception)) { @@ -410,11 +409,11 @@ protected Exception CreateExceptionFromResponse(string json) return new Trace2OAuth2Exception(_trace2, message, format); } - protected static bool TryDeserializeJson(string json, out T obj) + protected static bool TryDeserializeJson(string json, JsonSerializerContext context, out T obj) { try { - obj = JsonSerializer.Deserialize(json); + obj = (T)JsonSerializer.Deserialize(json, typeof(T), context); return true; } catch diff --git a/src/shared/Core/Constants.cs b/src/shared/Core/Constants.cs index 03f41647a..e41bfb64f 100644 --- a/src/shared/Core/Constants.cs +++ b/src/shared/Core/Constants.cs @@ -16,6 +16,10 @@ public static class Constants public const string GcmDataDirectoryName = ".gcm"; + public const string WindowsPlatformName = "windows"; + public const string LinuxPlatformName = "linux"; + public const string MacOSPlatformName = "osx"; + public static readonly Guid DevBoxPartnerId = new("e3171dd9-9a5f-e5be-b36c-cc7c4f3f3bcf"); /// diff --git a/src/shared/Core/Core.csproj b/src/shared/Core/Core.csproj index 644d07e4e..b344ccf91 100644 --- a/src/shared/Core/Core.csproj +++ b/src/shared/Core/Core.csproj @@ -1,8 +1,7 @@  - net7.0 - net7.0;net472 + net8.0 gcmcore GitCredentialManager false @@ -10,22 +9,13 @@ true - - - - - - - - - - - + + diff --git a/src/shared/Core/CurlCookie.cs b/src/shared/Core/CurlCookie.cs index e3a5fa140..c9ba2b7bd 100644 --- a/src/shared/Core/CurlCookie.cs +++ b/src/shared/Core/CurlCookie.cs @@ -66,18 +66,12 @@ public IList Parse(string content) private static DateTime ParseExpires(string expires) { -#if NETFRAMEWORK - DateTime epoch = new DateTime(1970, 01, 01, 0, 0, 0, DateTimeKind.Utc); -#else - DateTime epoch = DateTime.UnixEpoch; -#endif - if (long.TryParse(expires, out long i)) { - return epoch.AddSeconds(i); + return DateTime.UnixEpoch.AddSeconds(i); } - return epoch; + return DateTime.UnixEpoch; } } -} \ No newline at end of file +} diff --git a/src/shared/Core/HttpClientFactory.cs b/src/shared/Core/HttpClientFactory.cs index c48e277e5..dc8f29f7c 100644 --- a/src/shared/Core/HttpClientFactory.cs +++ b/src/shared/Core/HttpClientFactory.cs @@ -99,11 +99,7 @@ public HttpClient CreateClient() _streams.Error.WriteLine("warning: ---------------------------------------------------"); _streams.Error.WriteLine($"warning: HTTPS connections may not be secure. See {Constants.HelpUrls.GcmTlsVerification} for more information."); -#if NETFRAMEWORK - ServicePointManager.ServerCertificateValidationCallback = (req, cert, chain, errors) => true; -#else handler.ServerCertificateCustomValidationCallback = (req, cert, chain, errors) => true; -#endif } // If schannel is the TLS backend, custom certificate usage must be explicitly enabled else if (!string.IsNullOrWhiteSpace(_settings.CustomCertificateBundlePath) && @@ -178,23 +174,7 @@ public HttpClient CreateClient() // Set the custom server certificate validation callback. // NOTE: this is executed after the default platform server certificate validation is performed -#if NETFRAMEWORK - ServicePointManager.ServerCertificateValidationCallback = (_, cert, chain, errors) => - { - // Fail immediately if the cert or chain isn't present - if (cert is null || chain is null) - { - return false; - } - - using (X509Certificate2 cert2 = new X509Certificate2(cert)) - { - return validationCallback(cert2, chain, errors); - } - }; -#else handler.ServerCertificateCustomValidationCallback = (_, cert, chain, errors) => validationCallback(cert, chain, errors); -#endif } // If CustomCookieFilePath is set, set Cookie header from cookie file, which is written by libcurl diff --git a/src/shared/Core/Interop/Linux/LinuxFileSystem.cs b/src/shared/Core/Interop/Linux/LinuxFileSystem.cs index aa064886d..fb76641a3 100644 --- a/src/shared/Core/Interop/Linux/LinuxFileSystem.cs +++ b/src/shared/Core/Interop/Linux/LinuxFileSystem.cs @@ -1,9 +1,11 @@ using System; using System.IO; +using System.Runtime.Versioning; using GitCredentialManager.Interop.Posix; namespace GitCredentialManager.Interop.Linux { + [SupportedOSPlatform(Constants.LinuxPlatformName)] public class LinuxFileSystem : PosixFileSystem { public override bool IsSamePath(string a, string b) diff --git a/src/shared/Core/Interop/Linux/LinuxSessionManager.cs b/src/shared/Core/Interop/Linux/LinuxSessionManager.cs index 2147289ac..6e7f12c61 100644 --- a/src/shared/Core/Interop/Linux/LinuxSessionManager.cs +++ b/src/shared/Core/Interop/Linux/LinuxSessionManager.cs @@ -1,7 +1,9 @@ +using System.Runtime.Versioning; using GitCredentialManager.Interop.Posix; namespace GitCredentialManager.Interop.Linux; +[SupportedOSPlatform(Constants.LinuxPlatformName)] public class LinuxSessionManager : PosixSessionManager { private bool? _isWebBrowserAvailable; diff --git a/src/shared/Core/Interop/Linux/LinuxTerminal.cs b/src/shared/Core/Interop/Linux/LinuxTerminal.cs index f7ea6f89a..1697ae7e2 100644 --- a/src/shared/Core/Interop/Linux/LinuxTerminal.cs +++ b/src/shared/Core/Interop/Linux/LinuxTerminal.cs @@ -1,10 +1,12 @@ using System; +using System.Runtime.Versioning; using GitCredentialManager.Interop.Linux.Native; using GitCredentialManager.Interop.Posix; using GitCredentialManager.Interop.Posix.Native; namespace GitCredentialManager.Interop.Linux { + [SupportedOSPlatform(Constants.LinuxPlatformName)] public class LinuxTerminal : PosixTerminal { public LinuxTerminal(ITrace trace, ITrace2 trace2) diff --git a/src/shared/Core/Interop/MacOS/MacOSEnvironment.cs b/src/shared/Core/Interop/MacOS/MacOSEnvironment.cs index 256e81cb9..4e88e4b55 100644 --- a/src/shared/Core/Interop/MacOS/MacOSEnvironment.cs +++ b/src/shared/Core/Interop/MacOS/MacOSEnvironment.cs @@ -2,11 +2,13 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Runtime.Versioning; using System.Threading; using GitCredentialManager.Interop.Posix; namespace GitCredentialManager.Interop.MacOS { + [SupportedOSPlatform(Constants.MacOSPlatformName)] public class MacOSEnvironment : PosixEnvironment { private ICollection _pathsToIgnore; diff --git a/src/shared/Core/Interop/MacOS/MacOSFileSystem.cs b/src/shared/Core/Interop/MacOS/MacOSFileSystem.cs index 1f2e1e666..af80fcacf 100644 --- a/src/shared/Core/Interop/MacOS/MacOSFileSystem.cs +++ b/src/shared/Core/Interop/MacOS/MacOSFileSystem.cs @@ -1,9 +1,11 @@ using System; using System.IO; +using System.Runtime.Versioning; using GitCredentialManager.Interop.Posix; namespace GitCredentialManager.Interop.MacOS { + [SupportedOSPlatform(Constants.MacOSPlatformName)] public class MacOSFileSystem : PosixFileSystem { public override bool IsSamePath(string a, string b) diff --git a/src/shared/Core/Interop/MacOS/MacOSSessionManager.cs b/src/shared/Core/Interop/MacOS/MacOSSessionManager.cs index 584965ca1..cffcdd6c0 100644 --- a/src/shared/Core/Interop/MacOS/MacOSSessionManager.cs +++ b/src/shared/Core/Interop/MacOS/MacOSSessionManager.cs @@ -1,8 +1,10 @@ +using System.Runtime.Versioning; using GitCredentialManager.Interop.MacOS.Native; using GitCredentialManager.Interop.Posix; namespace GitCredentialManager.Interop.MacOS { + [SupportedOSPlatform(Constants.MacOSPlatformName)] public class MacOSSessionManager : PosixSessionManager { public MacOSSessionManager(IEnvironment env, IFileSystem fs) : base(env, fs) diff --git a/src/shared/Core/Interop/MacOS/MacOSTerminal.cs b/src/shared/Core/Interop/MacOS/MacOSTerminal.cs index a4c9d2120..1357d3b16 100644 --- a/src/shared/Core/Interop/MacOS/MacOSTerminal.cs +++ b/src/shared/Core/Interop/MacOS/MacOSTerminal.cs @@ -1,10 +1,12 @@ using System; +using System.Runtime.Versioning; using GitCredentialManager.Interop.MacOS.Native; using GitCredentialManager.Interop.Posix; using GitCredentialManager.Interop.Posix.Native; namespace GitCredentialManager.Interop.MacOS { + [SupportedOSPlatform(Constants.MacOSPlatformName)] public class MacOSTerminal : PosixTerminal { public MacOSTerminal(ITrace trace, ITrace2 trace2) diff --git a/src/shared/Core/Interop/Posix/PosixEnvironment.cs b/src/shared/Core/Interop/Posix/PosixEnvironment.cs index ec3d91c92..e3140daf4 100644 --- a/src/shared/Core/Interop/Posix/PosixEnvironment.cs +++ b/src/shared/Core/Interop/Posix/PosixEnvironment.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Versioning; namespace GitCredentialManager.Interop.Posix { + [SupportedOSPlatform(Constants.LinuxPlatformName)] + [SupportedOSPlatform(Constants.MacOSPlatformName)] public class PosixEnvironment : EnvironmentBase { public PosixEnvironment(IFileSystem fileSystem) diff --git a/src/shared/Core/Interop/Posix/PosixFileSystem.cs b/src/shared/Core/Interop/Posix/PosixFileSystem.cs index ec7ff8d50..06660bc2f 100644 --- a/src/shared/Core/Interop/Posix/PosixFileSystem.cs +++ b/src/shared/Core/Interop/Posix/PosixFileSystem.cs @@ -13,13 +13,6 @@ public abstract class PosixFileSystem : FileSystem /// Path is not absolute. protected internal static string ResolveSymbolicLinks(string path) { -#if NETFRAMEWORK - // Support for symlinks only exists in .NET 6+. - // Since we're still targeting .NET Framework on Windows it - // doesn't matter if we don't resolve symlinks for POSIX here - // (unless we're running on Mono.. but why do that?) - return path; -#else if (!Path.IsPathRooted(path)) { throw new ArgumentException("Path must be absolute", nameof(path)); @@ -54,10 +47,8 @@ protected internal static string ResolveSymbolicLinks(string path) } return Path.Combine("/", partialPath); -#endif } -#if !NETFRAMEWORK private static bool TryResolveFileLink(string path, out string target) { FileSystemInfo fsi = File.ResolveLinkTarget(path, true); @@ -71,6 +62,5 @@ private static bool TryResolveDirectoryLink(string path, out string target) target = fsi?.FullName; return fsi != null; } -#endif } } diff --git a/src/shared/Core/Interop/Windows/WindowsEnvironment.cs b/src/shared/Core/Interop/Windows/WindowsEnvironment.cs index 6c3450a38..246a44250 100644 --- a/src/shared/Core/Interop/Windows/WindowsEnvironment.cs +++ b/src/shared/Core/Interop/Windows/WindowsEnvironment.cs @@ -3,10 +3,12 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.Versioning; using System.Text; namespace GitCredentialManager.Interop.Windows { + [SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsEnvironment : EnvironmentBase { public WindowsEnvironment(IFileSystem fileSystem) diff --git a/src/shared/Core/Interop/Windows/WindowsFileSystem.cs b/src/shared/Core/Interop/Windows/WindowsFileSystem.cs index c1a64631c..6de36c718 100644 --- a/src/shared/Core/Interop/Windows/WindowsFileSystem.cs +++ b/src/shared/Core/Interop/Windows/WindowsFileSystem.cs @@ -1,8 +1,10 @@ using System; using System.IO; +using System.Runtime.Versioning; namespace GitCredentialManager.Interop.Windows { + [SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsFileSystem : FileSystem { public override bool IsSamePath(string a, string b) diff --git a/src/shared/Core/Interop/Windows/WindowsProcessManager.cs b/src/shared/Core/Interop/Windows/WindowsProcessManager.cs index 85d47b0de..4b55e8e92 100644 --- a/src/shared/Core/Interop/Windows/WindowsProcessManager.cs +++ b/src/shared/Core/Interop/Windows/WindowsProcessManager.cs @@ -1,5 +1,8 @@ +using System.Runtime.Versioning; + namespace GitCredentialManager.Interop.Windows; +[SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsProcessManager : ProcessManager { public WindowsProcessManager(ITrace2 trace2) : base(trace2) diff --git a/src/shared/Core/Interop/Windows/WindowsSessionManager.cs b/src/shared/Core/Interop/Windows/WindowsSessionManager.cs index d87d76347..4bb1a2dd3 100644 --- a/src/shared/Core/Interop/Windows/WindowsSessionManager.cs +++ b/src/shared/Core/Interop/Windows/WindowsSessionManager.cs @@ -1,8 +1,10 @@ using System; +using System.Runtime.Versioning; using GitCredentialManager.Interop.Windows.Native; namespace GitCredentialManager.Interop.Windows { + [SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsSessionManager : SessionManager { public WindowsSessionManager(IEnvironment env, IFileSystem fs) : base(env, fs) diff --git a/src/shared/Core/Interop/Windows/WindowsSettings.cs b/src/shared/Core/Interop/Windows/WindowsSettings.cs index abdd9ee0e..8566726bd 100644 --- a/src/shared/Core/Interop/Windows/WindowsSettings.cs +++ b/src/shared/Core/Interop/Windows/WindowsSettings.cs @@ -1,9 +1,12 @@ +using System.Runtime.Versioning; + namespace GitCredentialManager.Interop.Windows { /// /// Reads settings from Git configuration, environment variables, and defaults from the Windows Registry. /// + [SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsSettings : Settings { private readonly ITrace _trace; @@ -21,7 +24,6 @@ protected override bool TryGetExternalDefault(string section, string scope, stri { value = null; -#if NETFRAMEWORK // Check for machine (HKLM) registry keys that match the Git configuration name. // These can be set by system administrators via Group Policy, so make useful defaults. using (Microsoft.Win32.RegistryKey configKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(Constants.WindowsRegistry.HKConfigurationPath)) @@ -48,9 +50,6 @@ protected override bool TryGetExternalDefault(string section, string scope, stri return true; } -#else - return base.TryGetExternalDefault(section, scope, property, out value); -#endif } } } diff --git a/src/shared/Core/Interop/Windows/WindowsTerminal.cs b/src/shared/Core/Interop/Windows/WindowsTerminal.cs index b8f5f3475..09da26275 100644 --- a/src/shared/Core/Interop/Windows/WindowsTerminal.cs +++ b/src/shared/Core/Interop/Windows/WindowsTerminal.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Text; using GitCredentialManager.Interop.Windows.Native; using Microsoft.Win32.SafeHandles; @@ -9,6 +10,7 @@ namespace GitCredentialManager.Interop.Windows /// /// Represents a thin wrapper around the Windows console device. /// + [SupportedOSPlatform(Constants.WindowsPlatformName)] public class WindowsTerminal : ITerminal { // ReadConsole 32768 fail, 32767 OK @linquize [https://github.com/Microsoft/Git-Credential-Manager-for-Windows/commit/a62b9a19f430d038dcd85a610d97e5f763980f85] diff --git a/src/shared/Core/PlatformUtils.cs b/src/shared/Core/PlatformUtils.cs index 212c13219..5bae4aa8d 100644 --- a/src/shared/Core/PlatformUtils.cs +++ b/src/shared/Core/PlatformUtils.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using GitCredentialManager.Interop.Posix.Native; namespace GitCredentialManager @@ -24,6 +26,7 @@ public static PlatformInformation GetPlatformInformation(ITrace2 trace2) return new PlatformInformation(osType, osVersion, cpuArch, clrVersion); } + [SupportedOSPlatformGuard(Constants.WindowsPlatformName)] public static bool IsDevBox() { if (!IsWindows()) @@ -31,7 +34,6 @@ public static bool IsDevBox() return false; } -#if NETFRAMEWORK // Check for machine (HKLM) registry keys for Cloud PC indicators // Note that the keys are only found in the 64-bit registry view using (Microsoft.Win32.RegistryKey hklm64 = Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, Microsoft.Win32.RegistryView.Registry64)) @@ -48,11 +50,9 @@ public static bool IsDevBox() return w365Value is not null && Guid.TryParse(partnerValue, out Guid partnerId) && partnerId == Constants.DevBoxPartnerId; } -#else - return false; -#endif } + [SupportedOSPlatformGuard(Constants.WindowsPlatformName)] public static bool IsWindowsBrokerSupported() { if (!IsWindows()) @@ -97,45 +97,38 @@ public static bool IsWindowsBrokerSupported() /// Check if the current Operating System is macOS. /// /// True if running on macOS, false otherwise. + [SupportedOSPlatformGuard(Constants.MacOSPlatformName)] public static bool IsMacOS() { -#if NETFRAMEWORK - return Environment.OSVersion.Platform == PlatformID.MacOSX; -#else - return RuntimeInformation.IsOSPlatform(OSPlatform.OSX); -#endif + return OperatingSystem.IsMacOS(); } /// /// Check if the current Operating System is Windows. /// /// True if running on Windows, false otherwise. + [SupportedOSPlatformGuard(Constants.WindowsPlatformName)] public static bool IsWindows() { -#if NETFRAMEWORK - return Environment.OSVersion.Platform == PlatformID.Win32NT; -#else - return RuntimeInformation.IsOSPlatform(OSPlatform.Windows); -#endif + return OperatingSystem.IsWindows(); } /// /// Check if the current Operating System is Linux-based. /// /// True if running on a Linux distribution, false otherwise. + [SupportedOSPlatformGuard(Constants.LinuxPlatformName)] public static bool IsLinux() { -#if NETFRAMEWORK - return Environment.OSVersion.Platform == PlatformID.Unix; -#else - return RuntimeInformation.IsOSPlatform(OSPlatform.Linux); -#endif + return OperatingSystem.IsLinux(); } /// /// Check if the current Operating System is POSIX-compliant. /// /// True if running on a POSIX-compliant Operating System, false otherwise. + [SupportedOSPlatformGuard(Constants.LinuxPlatformName)] + [SupportedOSPlatformGuard(Constants.MacOSPlatformName)] public static bool IsPosix() { return IsMacOS() || IsLinux(); @@ -145,6 +138,7 @@ public static bool IsPosix() /// Ensure the current Operating System is macOS, fail otherwise. /// /// Thrown if the current OS is not macOS. + [SupportedOSPlatformGuard(Constants.MacOSPlatformName)] public static void EnsureMacOS() { if (!IsMacOS()) @@ -157,6 +151,7 @@ public static void EnsureMacOS() /// Ensure the current Operating System is Windows, fail otherwise. /// /// Thrown if the current OS is not Windows. + [SupportedOSPlatformGuard(Constants.WindowsPlatformName)] public static void EnsureWindows() { if (!IsWindows()) @@ -169,6 +164,7 @@ public static void EnsureWindows() /// Ensure the current Operating System is Linux-based, fail otherwise. /// /// Thrown if the current OS is not Linux-based. + [SupportedOSPlatformGuard(Constants.LinuxPlatformName)] public static void EnsureLinux() { if (!IsLinux()) @@ -181,6 +177,8 @@ public static void EnsureLinux() /// Ensure the current Operating System is POSIX-compliant, fail otherwise. /// /// Thrown if the current OS is not POSIX-compliant. + [SupportedOSPlatformGuard(Constants.LinuxPlatformName)] + [SupportedOSPlatformGuard(Constants.MacOSPlatformName)] public static void EnsurePosix() { if (!IsPosix()) @@ -193,11 +191,9 @@ public static bool IsElevatedUser() { if (IsWindows()) { -#if NETFRAMEWORK var identity = System.Security.Principal.WindowsIdentity.GetCurrent(); var principal = new System.Security.Principal.WindowsPrincipal(identity); return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator); -#endif } else if (IsPosix()) { @@ -283,9 +279,6 @@ private static string GetLinuxEntryPath() } } -#if NETFRAMEWORK - return null; -#else // // We cannot determine the absolute file path from argv[0] // (how we were launched), so let's now try to extract the @@ -295,7 +288,6 @@ private static string GetLinuxEntryPath() // FileSystemInfo fsi = File.ResolveLinkTarget("/proc/self/exe", returnFinalTarget: false); return fsi?.FullName; -#endif } private static string GetMacOSEntryPath() @@ -364,12 +356,11 @@ private static string GetOSVersion(ITrace2 trace2) // However, we still need to use the old method for Windows on .NET Framework // and call into the Win32 API to get the correct version (regardless of app // compatibility settings). -#if NETFRAMEWORK if (IsWindows() && RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi) == 0) { return $"{osvi.dwMajorVersion}.{osvi.dwMinorVersion} (build {osvi.dwBuildNumber})"; } -#endif + if (IsWindows() || IsMacOS()) { return Environment.OSVersion.Version.ToString(); @@ -459,9 +450,6 @@ string GetLinuxDistroVersion() private static string GetCpuArchitecture() { -#if NETFRAMEWORK - return Environment.Is64BitOperatingSystem ? "x86-64" : "x86"; -#else switch (RuntimeInformation.OSArchitecture) { case Architecture.Arm: @@ -475,16 +463,11 @@ private static string GetCpuArchitecture() default: return RuntimeInformation.OSArchitecture.ToString(); } -#endif } private static string GetClrVersion() { -#if NETFRAMEWORK - return $".NET Framework {Environment.Version}"; -#else return RuntimeInformation.FrameworkDescription; -#endif } #endregion diff --git a/src/shared/Core/Trace2Message.cs b/src/shared/Core/Trace2Message.cs index cbbe48288..75d8e2ed1 100644 --- a/src/shared/Core/Trace2Message.cs +++ b/src/shared/Core/Trace2Message.cs @@ -6,17 +6,46 @@ namespace GitCredentialManager; +public class Trace2EventEnumConverter : JsonStringEnumConverter +{ + public Trace2EventEnumConverter() + : base(JsonNamingPolicy.SnakeCaseLower, false) { } +} + +public class Trace2ProcessClassEnumConverter : JsonStringEnumConverter +{ + public Trace2ProcessClassEnumConverter() + : base(JsonNamingPolicy.SnakeCaseLower, false) { } +} + +[JsonSourceGenerationOptions( + PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower, + PropertyNameCaseInsensitive = true, + Converters = new[] + { + typeof(Trace2EventEnumConverter), + typeof(Trace2ProcessClassEnumConverter) + } +)] +[JsonSerializable(typeof(VersionMessage))] +[JsonSerializable(typeof(StartMessage))] +[JsonSerializable(typeof(ExitMessage))] +[JsonSerializable(typeof(ExitMessage))] +[JsonSerializable(typeof(ChildStartMessage))] +[JsonSerializable(typeof(ChildExitMessage))] +[JsonSerializable(typeof(ErrorMessage))] +[JsonSerializable(typeof(RegionEnterMessage))] +[JsonSerializable(typeof(RegionLeaveMessage))] +internal partial class Trace2JsonSerializerContext : JsonSerializerContext +{ +} + public abstract class Trace2Message { private const int SourceColumnMaxWidth = 23; private const string NormalPerfTimeFormat = "HH:mm:ss.ffffff"; protected const string EmptyPerformanceSpan = "| | | | "; - protected static readonly JsonSerializerOptions JsonSerializerOptions = new() - { - PropertyNameCaseInsensitive = true, - Converters = { new JsonStringEnumConverter(new SnakeCaseNamingPolicy()) } - }; [JsonPropertyName("event")] [JsonPropertyOrder(1)] @@ -194,7 +223,7 @@ public class VersionMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.VersionMessage); } public override string ToNormalString() @@ -230,7 +259,7 @@ public class StartMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.StartMessage); } public override string ToNormalString() @@ -266,7 +295,7 @@ public class ExitMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ExitMessage); } public override string ToNormalString() @@ -314,7 +343,7 @@ public class ChildStartMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ChildStartMessage); } public override string ToNormalString() @@ -371,7 +400,7 @@ public class ChildExitMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ChildExitMessage); } public override string ToNormalString() @@ -415,7 +444,7 @@ public class ErrorMessage : Trace2Message public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.ErrorMessage); } public override string ToNormalString() @@ -473,7 +502,7 @@ public class RegionEnterMessage : RegionMessage { public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.RegionEnterMessage); } public override string ToNormalString() @@ -504,7 +533,7 @@ public class RegionLeaveMessage : RegionMessage public override string ToJson() { - return JsonSerializer.Serialize(this, JsonSerializerOptions); + return JsonSerializer.Serialize(this, Trace2JsonSerializerContext.Default.RegionLeaveMessage); } public override string ToNormalString() @@ -527,9 +556,3 @@ protected override string GetEventMessage(Trace2FormatTarget formatTarget) return Message; } } - -public class SnakeCaseNamingPolicy : JsonNamingPolicy -{ - public override string ConvertName(string name) => - name.ToSnakeCase(); -} diff --git a/src/shared/Core/UI/AvaloniaUi.cs b/src/shared/Core/UI/AvaloniaUi.cs index 65b681884..7b23644fe 100644 --- a/src/shared/Core/UI/AvaloniaUi.cs +++ b/src/shared/Core/UI/AvaloniaUi.cs @@ -47,12 +47,7 @@ public static Task ShowWindowAsync(Func windowFunc, object dataContext, Dispatcher.MainThread.Post(appCancelToken => { AppBuilder.Configure() -#if NETFRAMEWORK - .UseWin32() - .UseSkia() -#else .UsePlatformDetect() -#endif .LogToTrace() // Workaround https://github.com/AvaloniaUI/Avalonia/issues/10296 // by always setting a application lifetime. diff --git a/src/shared/Core/UI/Controls/AboutWindow.axaml b/src/shared/Core/UI/Controls/AboutWindow.axaml index bccc1217d..8d7e63f17 100644 --- a/src/shared/Core/UI/Controls/AboutWindow.axaml +++ b/src/shared/Core/UI/Controls/AboutWindow.axaml @@ -3,11 +3,14 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:gcm="clr-namespace:GitCredentialManager" + xmlns:controls="clr-namespace:GitCredentialManager.UI.Controls" mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="450" x:Class="GitCredentialManager.UI.Controls.AboutWindow" Title="About Git Credential Manager" CanResize="False" Width="300" SizeToContent="Height" x:Name="window" + x:DataType="controls:AboutWindow" + x:CompileBindings="True" Background="{DynamicResource WindowBackgroundBrush}"> + KeyUp="Window_KeyUp" + x:DataType="vm:WindowViewModel" + x:CompileBindings="True"> diff --git a/src/shared/Core/UI/Controls/ProgressWindow.axaml b/src/shared/Core/UI/Controls/ProgressWindow.axaml index 3bfc20f5c..962c0b73c 100644 --- a/src/shared/Core/UI/Controls/ProgressWindow.axaml +++ b/src/shared/Core/UI/Controls/ProgressWindow.axaml @@ -6,6 +6,7 @@ SizeToContent="WidthAndHeight" CanResize="False" Topmost="True" ExtendClientAreaChromeHints="NoChrome" ExtendClientAreaToDecorationsHint="True" ShowInTaskbar="False" Title="Git Credential Manager" WindowStartupLocation="CenterScreen" + x:CompileBindings="True" x:Class="GitCredentialManager.UI.Controls.ProgressWindow"> diff --git a/src/shared/Core/UI/Views/DefaultAccountView.axaml b/src/shared/Core/UI/Views/DefaultAccountView.axaml index 83a677220..39b9133aa 100644 --- a/src/shared/Core/UI/Views/DefaultAccountView.axaml +++ b/src/shared/Core/UI/Views/DefaultAccountView.axaml @@ -5,6 +5,8 @@ xmlns:vm="clr-namespace:GitCredentialManager.UI.ViewModels;assembly=gcmcore" xmlns:converters="clr-namespace:GitCredentialManager.UI.Converters;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:DefaultAccountViewModel" + x:CompileBindings="True" x:Class="GitCredentialManager.UI.Views.DefaultAccountView"> diff --git a/src/shared/Core/UI/Views/DeviceCodeView.axaml b/src/shared/Core/UI/Views/DeviceCodeView.axaml index ea14072cf..79e02abab 100644 --- a/src/shared/Core/UI/Views/DeviceCodeView.axaml +++ b/src/shared/Core/UI/Views/DeviceCodeView.axaml @@ -2,11 +2,13 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:sharedVms="clr-namespace:GitCredentialManager.UI.ViewModels;assembly=gcmcore" + xmlns:vm="clr-namespace:GitCredentialManager.UI.ViewModels;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:DeviceCodeViewModel" + x:CompileBindings="True" x:Class="GitCredentialManager.UI.Views.DeviceCodeView"> - + diff --git a/src/shared/Core/UI/Views/OAuthView.axaml b/src/shared/Core/UI/Views/OAuthView.axaml index abf9afc5e..465e860cd 100644 --- a/src/shared/Core/UI/Views/OAuthView.axaml +++ b/src/shared/Core/UI/Views/OAuthView.axaml @@ -4,6 +4,8 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:GitCredentialManager.UI.ViewModels;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:OAuthViewModel" + x:CompileBindings="True" x:Class="GitCredentialManager.UI.Views.OAuthView"> diff --git a/src/shared/DotnetTool/DotnetTool.csproj b/src/shared/DotnetTool/DotnetTool.csproj index a951303bb..a1107a4b6 100644 --- a/src/shared/DotnetTool/DotnetTool.csproj +++ b/src/shared/DotnetTool/DotnetTool.csproj @@ -1,6 +1,6 @@ - net7.0 + net8.0 true dotnet-tool.nuspec diff --git a/src/shared/DotnetTool/dotnet-tool.nuspec b/src/shared/DotnetTool/dotnet-tool.nuspec index e707ba27e..cf9ba7444 100644 --- a/src/shared/DotnetTool/dotnet-tool.nuspec +++ b/src/shared/DotnetTool/dotnet-tool.nuspec @@ -12,7 +12,7 @@ - + diff --git a/src/shared/DotnetTool/layout.sh b/src/shared/DotnetTool/layout.sh index 44c712650..f5244dbbd 100755 --- a/src/shared/DotnetTool/layout.sh +++ b/src/shared/DotnetTool/layout.sh @@ -39,7 +39,7 @@ PROJ_OUT="$OUT/$DOTNET_TOOL" CONFIGURATION="${CONFIGURATION:=Debug}" # Build parameters -FRAMEWORK=net7.0 +FRAMEWORK=net8.0 # Outputs OUTDIR="$PROJ_OUT/nupkg/$CONFIGURATION" diff --git a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj index bc6dcb061..fb2735a8f 100644 --- a/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj +++ b/src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj @@ -2,16 +2,44 @@ Exe - net7.0 - net472;net7.0 + net8.0 win-x86;osx-x64;linux-x64;osx-arm64 - x86 git-credential-manager GitCredentialManager $(RepoAssetsPath)gcmicon.ico false latest true + true + true + true + + + + + true + + + true diff --git a/src/shared/Git-Credential-Manager/Program.cs b/src/shared/Git-Credential-Manager/Program.cs index 59f579b9f..b8aa0eb7c 100644 --- a/src/shared/Git-Credential-Manager/Program.cs +++ b/src/shared/Git-Credential-Manager/Program.cs @@ -76,12 +76,7 @@ private static void AppMain(object o) // Required for Avalonia designer static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() -#if NETFRAMEWORK - .UseWin32() - .UseSkia() -#else .UsePlatformDetect() -#endif .LogToTrace(); } } diff --git a/src/shared/GitHub.Tests/GitHub.Tests.csproj b/src/shared/GitHub.Tests/GitHub.Tests.csproj index a5cda349e..1b892075e 100644 --- a/src/shared/GitHub.Tests/GitHub.Tests.csproj +++ b/src/shared/GitHub.Tests/GitHub.Tests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false true latest diff --git a/src/shared/GitHub/GitHub.csproj b/src/shared/GitHub/GitHub.csproj index 1de18e7a5..2d550fef1 100644 --- a/src/shared/GitHub/GitHub.csproj +++ b/src/shared/GitHub/GitHub.csproj @@ -1,8 +1,7 @@  - net7.0 - net7.0;net472 + net8.0 GitHub GitHub false @@ -13,8 +12,4 @@ - - - - diff --git a/src/shared/GitHub/GitHubJsonSerializerContext.cs b/src/shared/GitHub/GitHubJsonSerializerContext.cs new file mode 100644 index 000000000..4ef75602e --- /dev/null +++ b/src/shared/GitHub/GitHubJsonSerializerContext.cs @@ -0,0 +1,13 @@ +namespace GitHub; + +using System.Text.Json.Serialization; + +[JsonSourceGenerationOptions( + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNameCaseInsensitive = true +)] +[JsonSerializable(typeof(GitHubUserInfo))] +[JsonSerializable(typeof(GitHubMetaInfo))] +internal partial class GitHubJsonSerializerContext : JsonSerializerContext +{ +} diff --git a/src/shared/GitHub/GitHubRestApi.cs b/src/shared/GitHub/GitHubRestApi.cs index 5051ed2bb..8baac581f 100644 --- a/src/shared/GitHub/GitHubRestApi.cs +++ b/src/shared/GitHub/GitHubRestApi.cs @@ -106,7 +106,7 @@ public async Task GetUserInfoAsync(Uri targetUri, string accessT string json = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(json); + return JsonSerializer.Deserialize(json, GitHubJsonSerializerContext.Default.GitHubUserInfo); } } } @@ -125,7 +125,7 @@ public async Task GetMetaInfoAsync(Uri targetUri) string json = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(json); + return JsonSerializer.Deserialize(json, GitHubJsonSerializerContext.Default.GitHubMetaInfo); } } diff --git a/src/shared/GitHub/UI/Views/CredentialsView.axaml b/src/shared/GitHub/UI/Views/CredentialsView.axaml index ccf96bf7b..ba2449d10 100644 --- a/src/shared/GitHub/UI/Views/CredentialsView.axaml +++ b/src/shared/GitHub/UI/Views/CredentialsView.axaml @@ -6,6 +6,8 @@ xmlns:vm="clr-namespace:GitHub.UI.ViewModels" xmlns:converters="clr-namespace:GitCredentialManager.UI.Converters;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:CredentialsViewModel" + x:CompileBindings="True" x:Class="GitHub.UI.Views.CredentialsView"> diff --git a/src/shared/GitHub/UI/Views/DeviceCodeView.axaml b/src/shared/GitHub/UI/Views/DeviceCodeView.axaml index c4f320411..afd0a0327 100644 --- a/src/shared/GitHub/UI/Views/DeviceCodeView.axaml +++ b/src/shared/GitHub/UI/Views/DeviceCodeView.axaml @@ -5,6 +5,8 @@ xmlns:controls="clr-namespace:GitHub.UI.Controls" xmlns:vm="clr-namespace:GitHub.UI.ViewModels" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:DeviceCodeViewModel" + x:CompileBindings="True" x:Class="GitHub.UI.Views.DeviceCodeView"> diff --git a/src/shared/GitHub/UI/Views/SelectAccountView.axaml b/src/shared/GitHub/UI/Views/SelectAccountView.axaml index 417d58387..d7e728b56 100644 --- a/src/shared/GitHub/UI/Views/SelectAccountView.axaml +++ b/src/shared/GitHub/UI/Views/SelectAccountView.axaml @@ -5,6 +5,8 @@ xmlns:controls="clr-namespace:GitHub.UI.Controls" xmlns:vm="clr-namespace:GitHub.UI.ViewModels" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:SelectAccountViewModel" + x:CompileBindings="True" x:Class="GitHub.UI.Views.SelectAccountView"> diff --git a/src/shared/GitHub/UI/Views/TwoFactorView.axaml b/src/shared/GitHub/UI/Views/TwoFactorView.axaml index d02598855..be4eec7ab 100644 --- a/src/shared/GitHub/UI/Views/TwoFactorView.axaml +++ b/src/shared/GitHub/UI/Views/TwoFactorView.axaml @@ -5,6 +5,8 @@ xmlns:controls="clr-namespace:GitHub.UI.Controls" xmlns:vm="clr-namespace:GitHub.UI.ViewModels" mc:Ignorable="d" d:DesignWidth="420" + x:DataType="vm:TwoFactorViewModel" + x:CompileBindings="True" x:Class="GitHub.UI.Views.TwoFactorView"> diff --git a/src/shared/GitLab.Tests/GitLab.Tests.csproj b/src/shared/GitLab.Tests/GitLab.Tests.csproj index bcd5fe7e8..253c36db4 100644 --- a/src/shared/GitLab.Tests/GitLab.Tests.csproj +++ b/src/shared/GitLab.Tests/GitLab.Tests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false true latest diff --git a/src/shared/GitLab/GitLab.csproj b/src/shared/GitLab/GitLab.csproj index 66017d55e..23086c8ee 100644 --- a/src/shared/GitLab/GitLab.csproj +++ b/src/shared/GitLab/GitLab.csproj @@ -1,8 +1,7 @@  - net7.0 - net7.0;net472 + net8.0 GitLab GitLab false @@ -13,8 +12,4 @@ - - - - diff --git a/src/shared/GitLab/UI/Views/CredentialsView.axaml b/src/shared/GitLab/UI/Views/CredentialsView.axaml index eac9318be..a1ce5ce45 100644 --- a/src/shared/GitLab/UI/Views/CredentialsView.axaml +++ b/src/shared/GitLab/UI/Views/CredentialsView.axaml @@ -6,6 +6,8 @@ xmlns:converters="clr-namespace:GitCredentialManager.UI.Converters;assembly=gcmcore" mc:Ignorable="d" d:DesignWidth="420" x:Class="GitLab.UI.Views.CredentialsView" + x:DataType="vm:CredentialsViewModel" + x:CompileBindings="True" x:Name="view"> diff --git a/src/shared/Microsoft.AzureRepos.Tests/Microsoft.AzureRepos.Tests.csproj b/src/shared/Microsoft.AzureRepos.Tests/Microsoft.AzureRepos.Tests.csproj index 8a475c370..01ec9d411 100644 --- a/src/shared/Microsoft.AzureRepos.Tests/Microsoft.AzureRepos.Tests.csproj +++ b/src/shared/Microsoft.AzureRepos.Tests/Microsoft.AzureRepos.Tests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false true latest diff --git a/src/shared/Microsoft.AzureRepos/Microsoft.AzureRepos.csproj b/src/shared/Microsoft.AzureRepos/Microsoft.AzureRepos.csproj index c99f102b3..1408d63db 100644 --- a/src/shared/Microsoft.AzureRepos/Microsoft.AzureRepos.csproj +++ b/src/shared/Microsoft.AzureRepos/Microsoft.AzureRepos.csproj @@ -1,8 +1,7 @@  - net7.0 - net7.0;net472 + net8.0 Microsoft.AzureRepos Microsoft.AzureRepos false @@ -13,8 +12,4 @@ - - - - diff --git a/src/shared/TestInfrastructure/TestInfrastructure.csproj b/src/shared/TestInfrastructure/TestInfrastructure.csproj index 467df5c3c..569b64cd5 100644 --- a/src/shared/TestInfrastructure/TestInfrastructure.csproj +++ b/src/shared/TestInfrastructure/TestInfrastructure.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 GitCredentialManager.Tests false false diff --git a/src/windows/Installer.Windows/Installer.Windows.csproj b/src/windows/Installer.Windows/Installer.Windows.csproj index 99253c445..312866484 100644 --- a/src/windows/Installer.Windows/Installer.Windows.csproj +++ b/src/windows/Installer.Windows/Installer.Windows.csproj @@ -3,10 +3,10 @@ - net472 + net8.0 false false - $(PlatformOutPath)Installer.Windows\bin\$(Configuration)\net472\win-x86 + $(PlatformOutPath)Installer.Windows\bin\$(Configuration)\net8.0\win-x86 diff --git a/src/windows/Installer.Windows/layout.ps1 b/src/windows/Installer.Windows/layout.ps1 index 070c9bf49..940194e27 100644 --- a/src/windows/Installer.Windows/layout.ps1 +++ b/src/windows/Installer.Windows/layout.ps1 @@ -37,7 +37,8 @@ mkdir -p "$PAYLOAD","$SYMBOLS" # Publish core application executables Write-Output "Publishing core application..." dotnet publish "$GCM_SRC" ` - --framework net472 ` + --framework net8.0 ` + --self-contained ` --configuration "$CONFIGURATION" ` --runtime win-x86 ` --output "$PAYLOAD" @@ -46,21 +47,6 @@ dotnet publish "$GCM_SRC" ` # into the publish output. Remove-Item -Path "$PAYLOAD/*.dylib" -Force -# Delete extraneous files that get included for other architectures -# We only care about x86 as the core GCM executable is only targeting x86 -Remove-Item -Path "$PAYLOAD/arm/" -Recurse -Force -Remove-Item -Path "$PAYLOAD/arm64/" -Recurse -Force -Remove-Item -Path "$PAYLOAD/x64/" -Recurse -Force -Remove-Item -Path "$PAYLOAD/musl-x64/" -Recurse -Force -Remove-Item -Path "$PAYLOAD/runtimes/win-arm64/" -Recurse -Force -Remove-Item -Path "$PAYLOAD/runtimes/win-x64/" -Recurse -Force - -# The Avalonia and MSAL binaries in these directories are already included in -# the $PAYLOAD directory directly, so we can delete these extra copies. -Remove-Item -Path "$PAYLOAD/x86/libSkiaSharp.dll" -Recurse -Force -Remove-Item -Path "$PAYLOAD/x86/libHarfBuzzSharp.dll" -Recurse -Force -Remove-Item -Path "$PAYLOAD/runtimes/win-x86/native/msalruntime_x86.dll" -Recurse -Force - # Delete localized resource assemblies - we don't localize the core GCM assembly anyway Get-ChildItem "$PAYLOAD" -Recurse -Include "*.resources.dll" | Remove-Item -Force