342 строки
10 KiB
C#
342 строки
10 KiB
C#
/**** Git Credential Manager for Windows ****
|
|
*
|
|
* Copyright (c) Microsoft Corporation
|
|
* All rights reserved.
|
|
*
|
|
* MIT License
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the """"Software""""), to deal
|
|
* in the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
|
|
**/
|
|
|
|
using System;
|
|
using System.Windows;
|
|
using System.Windows.Input;
|
|
using System.Windows.Interop;
|
|
|
|
namespace Microsoft.Alm.Gui
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for PassphraseWindow.xaml
|
|
/// </summary>
|
|
[System.Runtime.InteropServices.ComVisible(false)]
|
|
public partial class UserPromptDialog : Window
|
|
{
|
|
public const string HintTextPassphrase = "SSH Passphrase";
|
|
public const string HintTextPassword = "Password";
|
|
public const string HintTextUsername = "Username";
|
|
public const double WindowDefaultHeight = 150.0d;
|
|
public const double WindowDefaultWidth = 420.0d;
|
|
public const double WindowLargerHeight = 170.0d;
|
|
public const double WindowLargerWidth = 480.0d;
|
|
|
|
private const string AdornerStyleName = "FadedLabelStyle";
|
|
private readonly Size DefaultSize = new Size(WindowDefaultWidth, WindowDefaultHeight);
|
|
private readonly Size LargerSize = new Size(WindowLargerWidth, WindowLargerHeight);
|
|
|
|
internal UserPromptDialog(UserPromptKind kind, string resource, IntPtr parentHwnd)
|
|
: this(parentHwnd)
|
|
{
|
|
if ((kind & ~(UserPromptKind.AuthenticateHost | UserPromptKind.CredentialsPassword | UserPromptKind.CredentialsUsername | UserPromptKind.SshPassphrase)) != 0)
|
|
throw new ArgumentOutOfRangeException(nameof(kind));
|
|
if (string.IsNullOrWhiteSpace(resource))
|
|
throw new ArgumentNullException(nameof(resource));
|
|
|
|
_kind = kind;
|
|
_resource = resource;
|
|
|
|
var text = new System.Text.StringBuilder("Enter ");
|
|
|
|
switch (kind)
|
|
{
|
|
case UserPromptKind.CredentialsPassword:
|
|
{
|
|
text.Append("Password");
|
|
|
|
_title = text.ToString();
|
|
|
|
text.Append(" for ");
|
|
}
|
|
break;
|
|
|
|
case UserPromptKind.CredentialsUsername:
|
|
{
|
|
text.Append("Username");
|
|
|
|
_title = text.ToString();
|
|
|
|
text.Append(" for ");
|
|
}
|
|
break;
|
|
|
|
case UserPromptKind.SshPassphrase:
|
|
{
|
|
text.Append("Passphrase");
|
|
|
|
_title = text.ToString();
|
|
|
|
text.Append(" for key ");
|
|
}
|
|
break;
|
|
}
|
|
|
|
_isLarger = false;
|
|
|
|
text.Append('\'')
|
|
.Append(_resource)
|
|
.Append('\'');
|
|
|
|
_promptText = text.ToString(); ;
|
|
|
|
InitializeComponent();
|
|
|
|
Loaded += OnLoaded;
|
|
|
|
DataContext = this;
|
|
}
|
|
|
|
internal UserPromptDialog(string hostName, string fingerprint, IntPtr parentHwnd)
|
|
: this(parentHwnd)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(hostName))
|
|
throw new ArgumentNullException(nameof(hostName));
|
|
if (string.IsNullOrWhiteSpace(fingerprint))
|
|
throw new ArgumentNullException(nameof(fingerprint));
|
|
|
|
_fingerprint = fingerprint;
|
|
_kind = UserPromptKind.AuthenticateHost;
|
|
_title = "Validate Host Fingerprint";
|
|
_isLarger = true;
|
|
|
|
_promptText = "Continue connecting to '" + hostName + "'?";
|
|
_additionInfoText = "RSA key fingerprint:";
|
|
|
|
InitializeComponent();
|
|
|
|
Loaded += OnLoaded;
|
|
|
|
DataContext = this;
|
|
}
|
|
|
|
private UserPromptDialog(IntPtr parentHwnd)
|
|
{
|
|
new WindowInteropHelper(this).Owner = parentHwnd;
|
|
}
|
|
|
|
private readonly string _additionInfoText;
|
|
private readonly string _fingerprint;
|
|
private readonly bool _isLarger;
|
|
private readonly string _promptText;
|
|
private bool _failed;
|
|
private readonly UserPromptKind _kind;
|
|
private string _response;
|
|
private string _resource;
|
|
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
|
|
private PasswordBoxHintAdorner _textboxAdorner;
|
|
|
|
private readonly string _title;
|
|
|
|
public string AdditionalInfoText
|
|
{
|
|
get { return _additionInfoText; }
|
|
}
|
|
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value")]
|
|
public double DesiredHeight
|
|
{
|
|
get
|
|
{
|
|
return _isLarger
|
|
? LargerSize.Height
|
|
: DefaultSize.Height;
|
|
}
|
|
set { /* nope */ }
|
|
}
|
|
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value")]
|
|
public double DesiredWidth
|
|
{
|
|
get
|
|
{
|
|
return _isLarger
|
|
? LargerSize.Width
|
|
: DefaultSize.Width;
|
|
}
|
|
set { /* nope */ }
|
|
}
|
|
|
|
public bool Failed
|
|
{
|
|
get { return _failed; }
|
|
}
|
|
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value")]
|
|
public string Fingerprint
|
|
{
|
|
get { return _fingerprint; }
|
|
set { /* nope */ }
|
|
}
|
|
|
|
public UserPromptKind Kind
|
|
{
|
|
get { return _kind; }
|
|
}
|
|
|
|
public string PromptText
|
|
{
|
|
get { return _promptText; }
|
|
}
|
|
|
|
public string Response
|
|
{
|
|
get { return _response; }
|
|
}
|
|
|
|
protected void OnLoaded(object sender, RoutedEventArgs args)
|
|
{
|
|
string hintText = null;
|
|
|
|
Title = _title;
|
|
|
|
switch (_kind)
|
|
{
|
|
case UserPromptKind.AuthenticateHost:
|
|
PositiveButton.Content = "_Yes";
|
|
NegativeButton.Content = "_No";
|
|
AdditionalInfoLabel.Visibility = Visibility.Visible;
|
|
break;
|
|
|
|
case UserPromptKind.CredentialsPassword:
|
|
hintText = HintTextPassword;
|
|
break;
|
|
|
|
case UserPromptKind.CredentialsUsername:
|
|
hintText = HintTextUsername;
|
|
break;
|
|
|
|
case UserPromptKind.SshPassphrase:
|
|
hintText = HintTextPassphrase;
|
|
break;
|
|
}
|
|
|
|
LearnMoreLink.Visibility = _kind == UserPromptKind.SshPassphrase
|
|
? Visibility.Visible
|
|
: Visibility.Collapsed;
|
|
|
|
Topmost = true;
|
|
BringIntoView();
|
|
Activate();
|
|
|
|
if (hintText != null)
|
|
{
|
|
UserInput.Visibility = Visibility.Visible;
|
|
|
|
var style = Resources[AdornerStyleName] as Style;
|
|
if (style != null)
|
|
{
|
|
_textboxAdorner = new PasswordBoxHintAdorner(PassphrasePasswordBox, hintText, style, IsAdornerVisible);
|
|
}
|
|
|
|
PassphrasePasswordBox.Focus();
|
|
}
|
|
else
|
|
{
|
|
UserInput.Visibility = Visibility.Collapsed;
|
|
}
|
|
}
|
|
|
|
protected override void OnKeyUp(KeyEventArgs e)
|
|
{
|
|
if (e is null)
|
|
return;
|
|
|
|
switch (e.Key)
|
|
{
|
|
case Key.Enter:
|
|
Success();
|
|
break;
|
|
|
|
case Key.Escape:
|
|
Failure();
|
|
break;
|
|
|
|
default:
|
|
base.OnKeyUp(e);
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected override void OnGotFocus(RoutedEventArgs e)
|
|
{
|
|
base.OnGotFocus(e);
|
|
|
|
Keyboard.Focus(PassphrasePasswordBox);
|
|
}
|
|
|
|
protected void MoreInfoLabel_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo()
|
|
{
|
|
FileName = Cli.Program.DefinitionUrlPassphrase,
|
|
UseShellExecute = true,
|
|
});
|
|
}
|
|
|
|
protected void NegativeButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
Failure();
|
|
Close();
|
|
}
|
|
|
|
protected void PositiveButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
Success();
|
|
Close();
|
|
}
|
|
|
|
private void Failure()
|
|
{
|
|
_failed = true;
|
|
_response = null;
|
|
}
|
|
|
|
private Visibility IsAdornerVisible()
|
|
{
|
|
return (PassphrasePasswordBox.IsFocused || PassphrasePasswordBox.Password.Length > 0)
|
|
? Visibility.Collapsed
|
|
: Visibility.Visible;
|
|
}
|
|
|
|
private void Success()
|
|
{
|
|
string passphrase = PassphrasePasswordBox.Password;
|
|
|
|
if (string.IsNullOrWhiteSpace(passphrase))
|
|
{
|
|
_failed = false;
|
|
_response = null;
|
|
}
|
|
else
|
|
{
|
|
_failed = false;
|
|
_response = passphrase;
|
|
}
|
|
}
|
|
}
|
|
}
|