Skip to content

Commit

Permalink
Set parent window handle based on GCM_MODAL_PARENTHWD
Browse files Browse the repository at this point in the history
Wire up the parent window handle to system prompts and UI helpers.
  • Loading branch information
mjcheetham committed Feb 12, 2020
1 parent 0b9bde1 commit 64f206f
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/shared/Microsoft.Git.CredentialManager/CommandContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ public CommandContext()
Settings = new Settings(Environment, Git, repoPath);
HttpClientFactory = new HttpClientFactory(Trace, Settings, Streams);
IsDesktopSession = PlatformUtils.IsDesktopSession();

// Set the parent window handle/ID
SystemPrompts.ParentWindowId = Settings.ParentWindowId;
}

#region ICommandContext
Expand Down
1 change: 1 addition & 0 deletions src/shared/Microsoft.Git.CredentialManager/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public static class EnvironmentVariables
public const string GcmHttpProxy = "GCM_HTTP_PROXY";
public const string GitSslNoVerify = "GIT_SSL_NO_VERIFY";
public const string GcmInteractive = "GCM_INTERACTIVE";
public const string GcmParentWindow = "GCM_MODAL_PARENTHWND";
}

public static class Http
Expand Down
28 changes: 28 additions & 0 deletions src/shared/Microsoft.Git.CredentialManager/ConvertUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;

namespace Microsoft.Git.CredentialManager
{
public static class ConvertUtils
{
public static bool TryToInt32(object value, out int i)
{
return TryConvert(Convert.ToInt32, value, out i);
}

public static bool TryConvert<T>(Func<object, T> convert, object value, out T @out)
{
try
{
@out = convert(value);
return true;
}
catch
{
@out = default(T);
return false;
}
}
}
}
16 changes: 16 additions & 0 deletions src/shared/Microsoft.Git.CredentialManager/ISystemPrompts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,24 @@

namespace Microsoft.Git.CredentialManager
{
/// <summary>
/// Represents native system UI prompts.
/// </summary>
public interface ISystemPrompts
{
/// <summary>
/// The parent window handle or ID. Used for correctly positioning and parenting system dialogs.
/// </summary>
/// <remarks>This value is platform specific.</remarks>
object ParentWindowId { get; set; }

/// <summary>
/// Show a basic credential prompt using native system UI.
/// </summary>
/// <param name="resource">The name or URL of the resource to collect credentials for.</param>
/// <param name="userName">Optional pre-filled username.</param>
/// <param name="credential">The captured basic credential.</param>
/// <returns>True if the user completes the dialog, false otherwise.</returns>
bool ShowCredentialPrompt(string resource, string userName, out ICredential credential);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ namespace Microsoft.Git.CredentialManager.Interop.MacOS
{
public class MacOSSystemPrompts : ISystemPrompts
{
public object ParentWindowId { get; set; }

public bool ShowCredentialPrompt(string resource, string userName, out ICredential credential)
{
throw new System.NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ namespace Microsoft.Git.CredentialManager.Interop.Windows
{
public class WindowsSystemPrompts : ISystemPrompts
{
private IntPtr _parentHwd = IntPtr.Zero;

public object ParentWindowId
{
get => _parentHwd.ToString();
set => _parentHwd = ConvertUtils.TryToInt32(value, out int ptr) ? new IntPtr(ptr) : IntPtr.Zero;
}

public bool ShowCredentialPrompt(string resource, string userName, out ICredential credential)
{
EnsureArgument.NotNullOrWhiteSpace(resource, nameof(resource));
Expand All @@ -19,7 +27,7 @@ public bool ShowCredentialPrompt(string resource, string userName, out ICredenti
{
BannerArt = IntPtr.Zero,
CaptionText = "Git Credential Manager", // TODO: make this a parameter?
Parent = IntPtr.Zero, // TODO: get the parent window handle
Parent = _parentHwd,
MessageText = message,
Size = Marshal.SizeOf(typeof(CredUi.CredentialUiInfo))
};
Expand Down
8 changes: 8 additions & 0 deletions src/shared/Microsoft.Git.CredentialManager/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ public interface ISettings : IDisposable
/// <param name="isDeprecatedConfiguration">True if the proxy configuration method is deprecated, false otherwise.</param>
/// <returns>Proxy setting, or null if not configured.</returns>
Uri GetProxyConfiguration(out bool isDeprecatedConfiguration);

/// <summary>
/// The parent window handle/ID. Used to correctly position and parent dialogs generated by GCM.
/// </summary>
/// <remarks>This value is platform specific.</remarks>
string ParentWindowId { get; }
}

public class Settings : ISettings
Expand Down Expand Up @@ -271,6 +277,8 @@ bool TryGetUriSetting(string envarName, string section, string property, out Uri
return null;
}

public string ParentWindowId => _environment.Variables.TryGetValue(Constants.EnvironmentVariables.GcmParentWindow, out string parentWindowId) ? parentWindowId : null;

/// <summary>
/// Try and get the value of a specified setting as specified in the environment and Git configuration,
/// with the environment taking precedence over Git.
Expand Down
4 changes: 4 additions & 0 deletions src/shared/TestInfrastructure/Objects/TestSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public class TestSettings : ISettings

public bool IsDeprecatedProxyConfiguration { get; set; }

public string ParentWindowId { get; set; }

#region ISettings

public string RepositoryPath { get; set; }
Expand Down Expand Up @@ -66,6 +68,8 @@ Uri ISettings.GetProxyConfiguration(out bool isDeprecatedConfiguration)
return ProxyConfiguration;
}

string ISettings.ParentWindowId => ParentWindowId;

#endregion

#region IDisposable
Expand Down
2 changes: 2 additions & 0 deletions src/shared/TestInfrastructure/Objects/TestSystemPrompts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public class TestSystemPrompts : ISystemPrompts
{
public Func<string, string, ICredential> CredentialPrompt { get; set; } = (resource, user) => null;

public object ParentWindowId { get; set; }

public bool ShowCredentialPrompt(string resource, string userName, out ICredential credential)
{
credential = CredentialPrompt(resource, userName);
Expand Down
9 changes: 8 additions & 1 deletion src/windows/GitHub.Authentication.Helper.Windows/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ public static void Main(string[] args)
}
else
{
var prompts = new AuthenticationPrompts(gui);
IntPtr parentHwnd = GetParentWindowHandle();
var prompts = new AuthenticationPrompts(gui, parentHwnd);
var resultDict = new Dictionary<string, string>();

if (!TryGetArgument(args, "--prompt", out string promptType))
Expand Down Expand Up @@ -66,6 +67,12 @@ public static void Main(string[] args)
}
}

private static IntPtr GetParentWindowHandle()
{
string hwndStr = Environment.GetEnvironmentVariable(Constants.EnvironmentVariables.GcmParentWindow);
return ConvertUtils.TryToInt32(hwndStr, out int ptr) ? new IntPtr(ptr) : IntPtr.Zero;
}

private static bool TryGetArgument(string[] args, string name, out string value)
{
for (var i = 0; i < args.Length; i++)
Expand Down

0 comments on commit 64f206f

Please sign in to comment.