Skip to content

Commit 1e904d1

Browse files
committed
msauth: replace WPF progress window with Avalonia
1 parent 8a098a4 commit 1e904d1

File tree

3 files changed

+61
-86
lines changed

3 files changed

+61
-86
lines changed

src/shared/Core/Authentication/MicrosoftAuthentication.cs

Lines changed: 10 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@
1111
using System.Text;
1212
using System.Threading;
1313
using GitCredentialManager.UI;
14+
using GitCredentialManager.UI.Controls;
1415
using GitCredentialManager.UI.ViewModels;
1516
using GitCredentialManager.UI.Views;
1617
using Microsoft.Identity.Client.AppConfig;
1718

1819
#if NETFRAMEWORK
19-
using System.Drawing;
20-
using System.Windows.Forms;
2120
using Microsoft.Identity.Client.Broker;
2221
#endif
2322

@@ -118,10 +117,6 @@ public class MicrosoftAuthentication : AuthenticationBase, IMicrosoftAuthenticat
118117
"live", "liveconnect", "liveid",
119118
};
120119

121-
#if NETFRAMEWORK
122-
private DummyWindow _dummyWindow;
123-
#endif
124-
125120
public MicrosoftAuthentication(ICommandContext context)
126121
: base(context) { }
127122

@@ -130,6 +125,8 @@ public MicrosoftAuthentication(ICommandContext context)
130125
public async Task<IMicrosoftAuthenticationResult> GetTokenForUserAsync(
131126
string authority, string clientId, Uri redirectUri, string[] scopes, string userName, bool msaPt)
132127
{
128+
var uiCts = new CancellationTokenSource();
129+
133130
// Check if we can and should use OS broker authentication
134131
bool useBroker = CanUseBroker();
135132
Context.Trace.WriteLine(useBroker
@@ -144,7 +141,7 @@ public async Task<IMicrosoftAuthenticationResult> GetTokenForUserAsync(
144141
try
145142
{
146143
// Create the public client application for authentication
147-
IPublicClientApplication app = await CreatePublicClientApplicationAsync(authority, clientId, redirectUri, useBroker, msaPt);
144+
IPublicClientApplication app = await CreatePublicClientApplicationAsync(authority, clientId, redirectUri, useBroker, msaPt, uiCts);
148145

149146
AuthenticationResult result = null;
150147

@@ -261,10 +258,8 @@ public async Task<IMicrosoftAuthenticationResult> GetTokenForUserAsync(
261258
}
262259
finally
263260
{
264-
#if NETFRAMEWORK
265-
// If we created a dummy window during authentication we should dispose of it now that we're done
266-
_dummyWindow?.Dispose();
267-
#endif
261+
// If we created some global UI (e.g. progress) during authentication we should dismiss them now that we're done
262+
uiCts.Cancel();
268263
}
269264
}
270265

@@ -451,8 +446,8 @@ private async Task<AuthenticationResult> GetAccessTokenSilentlyAsync(
451446
}
452447
}
453448

454-
private async Task<IPublicClientApplication> CreatePublicClientApplicationAsync(
455-
string authority, string clientId, Uri redirectUri, bool enableBroker, bool msaPt)
449+
private async Task<IPublicClientApplication> CreatePublicClientApplicationAsync(string authority,
450+
string clientId, Uri redirectUri, bool enableBroker, bool msaPt, CancellationTokenSource uiCts)
456451
{
457452
var httpFactoryAdaptor = new MsalHttpClientFactoryAdaptor(Context.HttpClientFactory);
458453

@@ -495,11 +490,8 @@ private async Task<IPublicClientApplication> CreatePublicClientApplicationAsync(
495490
}
496491
else if (enableBroker) // Only actually need to set a parent window when using the Windows broker
497492
{
498-
#if NETFRAMEWORK
499-
Context.Trace.WriteLine($"Using dummy parent window for MSAL authentication dialogs.");
500-
_dummyWindow = new DummyWindow();
501-
appBuilder.WithParentActivityOrWindow(_dummyWindow.ShowAndGetHandle);
502-
#endif
493+
Context.Trace.WriteLine("Using progress parent window for MSAL authentication dialogs.");
494+
appBuilder.WithParentActivityOrWindow(() => ProgressWindow.ShowAndGetHandle(uiCts.Token));
503495
}
504496
}
505497
}
@@ -899,73 +891,5 @@ public MsalResult(AuthenticationResult msalResult)
899891
public string AccessToken => _msalResult.AccessToken;
900892
public string AccountUpn => _msalResult.Account?.Username;
901893
}
902-
903-
#if NETFRAMEWORK
904-
private class DummyWindow : IDisposable
905-
{
906-
private readonly Thread _staThread;
907-
private readonly ManualResetEventSlim _readyEvent;
908-
private Form _window;
909-
private IntPtr _handle;
910-
911-
public DummyWindow()
912-
{
913-
_staThread = new Thread(ThreadProc);
914-
_staThread.SetApartmentState(ApartmentState.STA);
915-
_readyEvent = new ManualResetEventSlim();
916-
}
917-
918-
public IntPtr ShowAndGetHandle()
919-
{
920-
_staThread.Start();
921-
_readyEvent.Wait();
922-
return _handle;
923-
}
924-
925-
public void Dispose()
926-
{
927-
_window?.Invoke(() => _window.Close());
928-
929-
if (_staThread.IsAlive)
930-
{
931-
_staThread.Join();
932-
}
933-
}
934-
935-
private void ThreadProc()
936-
{
937-
System.Windows.Forms.Application.EnableVisualStyles();
938-
_window = new Form
939-
{
940-
TopMost = true,
941-
ControlBox = false,
942-
MaximizeBox = false,
943-
MinimizeBox = false,
944-
ClientSize = new Size(182, 46),
945-
FormBorderStyle = FormBorderStyle.None,
946-
StartPosition = FormStartPosition.CenterScreen,
947-
};
948-
949-
var progress = new ProgressBar
950-
{
951-
Style = ProgressBarStyle.Marquee,
952-
Location = new Point(12, 12),
953-
Size = new Size(158, 23),
954-
MarqueeAnimationSpeed = 30,
955-
};
956-
957-
_window.Controls.Add(progress);
958-
_window.Shown += (s, e) =>
959-
{
960-
_handle = _window.Handle;
961-
_readyEvent.Set();
962-
};
963-
964-
_window.ShowDialog();
965-
_window.Dispose();
966-
_window = null;
967-
}
968-
}
969-
#endif
970894
}
971895
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Window xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
mc:Ignorable="d" d:DesignWidth="182" d:DesignHeight="46"
6+
SizeToContent="WidthAndHeight" CanResize="False" Topmost="True"
7+
ExtendClientAreaChromeHints="NoChrome" ExtendClientAreaToDecorationsHint="True"
8+
ShowInTaskbar="False" Title="Git Credential Manager" WindowStartupLocation="CenterScreen"
9+
x:Class="GitCredentialManager.UI.Controls.ProgressWindow">
10+
<ProgressBar Orientation="Horizontal"
11+
IsIndeterminate="True"
12+
Margin="20"
13+
Width="158" Height="23" />
14+
</Window>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using Avalonia;
5+
using Avalonia.Controls;
6+
using Avalonia.Markup.Xaml;
7+
8+
namespace GitCredentialManager.UI.Controls;
9+
10+
public partial class ProgressWindow : Window
11+
{
12+
public ProgressWindow()
13+
{
14+
InitializeComponent();
15+
}
16+
17+
private void InitializeComponent()
18+
{
19+
AvaloniaXamlLoader.Load(this);
20+
}
21+
22+
public static IntPtr ShowAndGetHandle(CancellationToken ct)
23+
{
24+
var tsc = new TaskCompletionSource<IntPtr>();
25+
26+
Window CreateWindow()
27+
{
28+
var window = new ProgressWindow();
29+
window.Loaded += (s, e) => tsc.SetResult(window.TryGetPlatformHandle()?.Handle ?? IntPtr.Zero);
30+
return window;
31+
}
32+
33+
Task _ = AvaloniaUi.ShowWindowAsync(CreateWindow, IntPtr.Zero, ct);
34+
35+
return tsc.Task.GetAwaiter().GetResult();
36+
}
37+
}

0 commit comments

Comments
 (0)