Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ jobs:
# ================================
linux:
name: Linux
runs-on: ubuntu-latest
runs-on: ${{ matrix.runtime == 'linux-x64' && 'ubuntu-24.04' || 'ubuntu-24.04-arm' }}
strategy:
matrix:
runtime: [ linux-x64, linux-arm64, linux-arm ]
Expand All @@ -89,6 +89,13 @@ jobs:
with:
dotnet-version: 10.0.x

- name: Install cross-compilation toolchain (arm)
if: matrix.runtime == 'linux-arm'
run: |
sudo apt-get update
# Brings in cross-compilation toolchain for armhf including binutils
sudo apt-get install -y gcc-arm-linux-gnueabihf

- name: Install dependencies
run: dotnet restore

Expand Down
8 changes: 3 additions & 5 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@

<ItemGroup>
<!-- Avalonia -->
<PackageVersion Include="Avalonia" Version="11.1.3" />
<PackageVersion Include="Avalonia.Desktop" Version="11.1.3" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.1.3" />
<PackageVersion Include="Avalonia.Themes.Fluent" Version="11.1.3" />
<PackageVersion Include="Avalonia" Version="12.0.5" />
<PackageVersion Include="Avalonia.Desktop" Version="12.0.5" />
<PackageVersion Include="Avalonia.Themes.Fluent" Version="12.0.5" />

<!-- Microsoft Identity -->
<PackageVersion Include="Microsoft.Identity.Client" Version="4.65.0" />
Expand All @@ -23,7 +22,6 @@
<!-- Other -->
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageVersion Include="System.Text.Json" Version="8.0.5" />
<PackageVersion Include="Tmds.DBus.Protocol" Version="0.21.3" />
<PackageVersion Include="Tools.InnoSetup" Version="6.3.1" GeneratePathProperty="true" />

<!-- Testing -->
Expand Down
6 changes: 5 additions & 1 deletion src/linux/Packaging.Linux/install-from-source.sh
Original file line number Diff line number Diff line change
Expand Up @@ -259,5 +259,9 @@ if [ -z "$DOTNET_ROOT" ]; then
fi

cd "$toplevel_path"
$sudo_cmd env "PATH=$PATH" $DOTNET_ROOT/dotnet build ./src/linux/Packaging.Linux/Packaging.Linux.csproj -c Release -p:InstallFromSource=true -p:installPrefix=$installPrefix
# Build a non-AOT binary so installing from source needs only the .NET SDK,
# not a C toolchain (clang + zlib) to link a native build. PublishAot is read
# from the environment by Git-Credential-Manager.csproj and inherited by the
# nested publish.
$sudo_cmd env "PATH=$PATH" PublishAot=false $DOTNET_ROOT/dotnet build ./src/linux/Packaging.Linux/Packaging.Linux.csproj -c Release -p:InstallFromSource=true -p:installPrefix=$installPrefix
add_to_PATH "$installPrefix/bin"
4 changes: 3 additions & 1 deletion src/shared/Atlassian.Bitbucket/BitbucketOAuth2Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ 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,
BitbucketOAuthJsonContext.Default.BitbucketTokenEndpointResponseJson,
out BitbucketTokenEndpointResponseJson jsonObj))
{
result = jsonObj.ToResult();
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

namespace Atlassian.Bitbucket
{
[JsonSerializable(typeof(BitbucketTokenEndpointResponseJson))]
public partial class BitbucketOAuthJsonContext : JsonSerializerContext;

[JsonConverter(typeof(BitbucketCustomTokenEndpointResponseJsonConverter))]
public class BitbucketTokenEndpointResponseJson : TokenEndpointResponseJson
{
Expand Down
13 changes: 8 additions & 5 deletions src/shared/Atlassian.Bitbucket/Cloud/BitbucketRestApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@

namespace Atlassian.Bitbucket.Cloud
{
[JsonSerializable(typeof(UserInfo))]
[JsonSourceGenerationOptions(
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
)]
public partial class BitbucketCloudRestApiJsonContext : JsonSerializerContext;

public class BitbucketRestApi : IBitbucketRestApi
{
private readonly ICommandContext _context;
Expand Down Expand Up @@ -43,11 +50,7 @@ public async Task<RestApiResult<IUserInfo>> GetUserInformationAsync(string userN

if (response.IsSuccessStatusCode)
{
var obj = JsonSerializer.Deserialize<UserInfo>(json,
new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
});
UserInfo obj = JsonSerializer.Deserialize(json, BitbucketCloudRestApiJsonContext.Default.UserInfo);

return new RestApiResult<IUserInfo>(response.StatusCode, obj);
}
Expand Down
19 changes: 12 additions & 7 deletions src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@

namespace Atlassian.Bitbucket.DataCenter
{
[JsonSerializable(typeof(UserInfo))]
[JsonSerializable(typeof(LoginOption))]
[JsonSerializable(typeof(LoginOptions))]
[JsonSourceGenerationOptions(
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
)]
public partial class BitbucketDataCenterRestApiJsonContext : JsonSerializerContext;

public class BitbucketRestApi : IBitbucketRestApi
{
private readonly ICommandContext _context;
Expand Down Expand Up @@ -107,12 +116,8 @@ public async Task<List<AuthenticationMethod>> GetAuthenticationMethodsAsync()

if (response.IsSuccessStatusCode)
{
var loginOptions = JsonSerializer.Deserialize<LoginOptions>(json,
new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
});
LoginOptions loginOptions = JsonSerializer.Deserialize(
json, BitbucketDataCenterRestApiJsonContext.Default.LoginOptions);

if (loginOptions.Results.Any(r => "LOGIN_FORM".Equals(r.Type)))
{
Expand Down Expand Up @@ -151,4 +156,4 @@ private Uri ApiUri
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
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:Class="Atlassian.Bitbucket.UI.Views.CredentialsView">
<Design.DataContext>
<vm:CredentialsViewModel/>
Expand Down Expand Up @@ -63,11 +64,11 @@
<StackPanel Margin="0,15">
<TextBox x:Name="_userNameTextBox" Margin="0,0,0,10"
HorizontalAlignment="Stretch"
Watermark="Email or username"
PlaceholderText="Email or username"
Text="{Binding UserName}" />
<TextBox x:Name="_passwordTextBox" Margin="0,0,0,10"
HorizontalAlignment="Stretch"
Watermark="Password or token" PasswordChar="●"
PlaceholderText="Password or token" PasswordChar="●"
Text="{Binding Password}" />
<Button IsDefault="True"
HorizontalAlignment="Center" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Text.Json.Serialization;

namespace GitCredentialManager.Authentication.OAuth.Json;

[JsonSerializable(typeof(DeviceAuthorizationEndpointResponseJson))]
[JsonSerializable(typeof(TokenEndpointResponseJson))]
[JsonSerializable(typeof(ErrorResponseJson))]
[JsonSourceGenerationOptions(PropertyNameCaseInsensitive = true)]
public partial class OAuthJsonContext : JsonSerializerContext;
20 changes: 10 additions & 10 deletions src/shared/Core/Authentication/OAuth/OAuth2Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Threading.Tasks;
using GitCredentialManager.Authentication.OAuth.Json;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;

namespace GitCredentialManager.Authentication.OAuth
{
Expand Down Expand Up @@ -213,7 +214,7 @@ public async Task<OAuth2DeviceCodeResult> GetDeviceCodeAsync(IEnumerable<string>
{
string json = await response.Content.ReadAsStringAsync();

if (response.IsSuccessStatusCode && TryDeserializeJson(json, out DeviceAuthorizationEndpointResponseJson jsonObj))
if (response.IsSuccessStatusCode && TryDeserializeJson(json, OAuthJsonContext.Default.DeviceAuthorizationEndpointResponseJson, out DeviceAuthorizationEndpointResponseJson jsonObj))
{
return jsonObj.ToResult();
}
Expand Down Expand Up @@ -321,12 +322,9 @@ public async Task<OAuth2TokenResult> GetTokenByDeviceCodeAsync(OAuth2DeviceCodeR
return result;
}

var error = JsonSerializer.Deserialize<ErrorResponseJson>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
TryDeserializeJson(json, OAuthJsonContext.Default.ErrorResponseJson, out ErrorResponseJson error);

switch (error.Error)
switch (error?.Error)
{
case OAuth2Constants.DeviceAuthorization.Errors.AuthorizationPending:
// Retry with the current polling interval value
Expand Down Expand Up @@ -358,7 +356,9 @@ public async Task<OAuth2TokenResult> GetTokenByDeviceCodeAsync(OAuth2DeviceCodeR

protected virtual bool TryCreateTokenEndpointResult(string json, out OAuth2TokenResult result)
{
if (TryDeserializeJson(json, out TokenEndpointResponseJson jsonObj))
if (TryDeserializeJson(json,
OAuthJsonContext.Default.TokenEndpointResponseJson,
out TokenEndpointResponseJson jsonObj))
{
result = jsonObj.ToResult();
return true;
Expand All @@ -370,7 +370,7 @@ protected virtual bool TryCreateTokenEndpointResult(string json, out OAuth2Token

protected virtual bool TryCreateExceptionFromResponse(string json, out OAuth2Exception exception)
{
if (TryDeserializeJson(json, out ErrorResponseJson obj))
if (TryDeserializeJson(json, OAuthJsonContext.Default.ErrorResponseJson, out ErrorResponseJson obj))
{
exception = obj.ToException();
return true;
Expand Down Expand Up @@ -410,11 +410,11 @@ protected Exception CreateExceptionFromResponse(string json)
return new Trace2OAuth2Exception(_trace2, message, format);
}

protected static bool TryDeserializeJson<T>(string json, out T obj)
protected static bool TryDeserializeJson<T>(string json, JsonTypeInfo<T> typeInfo, out T obj)
{
try
{
obj = JsonSerializer.Deserialize<T>(json);
obj = JsonSerializer.Deserialize(json, typeInfo);
return true;
}
catch
Expand Down
5 changes: 0 additions & 5 deletions src/shared/Core/Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,4 @@
<PackageReference Include="Avalonia.Themes.Fluent" />
</ItemGroup>

<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<PackageReference Include="Avalonia.Diagnostics" />
<PackageReference Include="Tmds.DBus.Protocol" />
</ItemGroup>

</Project>
13 changes: 13 additions & 0 deletions src/shared/Core/Trace2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading;

namespace GitCredentialManager;
Expand All @@ -13,13 +14,21 @@ namespace GitCredentialManager;
/// </summary>
public enum Trace2Event
{
[JsonStringEnumMemberName("version")]
Version = 0,
[JsonStringEnumMemberName("start")]
Start = 1,
[JsonStringEnumMemberName("exit")]
Exit = 2,
[JsonStringEnumMemberName("child_start")]
ChildStart = 3,
[JsonStringEnumMemberName("child_exit")]
ChildExit = 4,
[JsonStringEnumMemberName("error")]
Error = 5,
[JsonStringEnumMemberName("region_enter")]
RegionEnter = 6,
[JsonStringEnumMemberName("region_leave")]
RegionLeave = 7,
}

Expand All @@ -28,9 +37,13 @@ public enum Trace2Event
/// </summary>
public enum Trace2ProcessClass
{
[JsonStringEnumMemberName("none")]
None = 0,
[JsonStringEnumMemberName("ui_helper")]
UIHelper = 1,
[JsonStringEnumMemberName("git")]
Git = 2,
[JsonStringEnumMemberName("other")]
Other = 3
}

Expand Down
Loading
Loading