Files
desktop-edge-win/DesktopEdge/Views/Screens/MFAScreen.xaml.cs
T

316 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Windows.Media.Animation;
using ZitiDesktopEdge.Models;
using ZitiDesktopEdge.ServiceClient;
using ZitiDesktopEdge.DataStructures;
using NLog;
using QRCoder;
using System.Text.RegularExpressions;
namespace ZitiDesktopEdge {
/// <summary>
/// Interaction logic for MFA.xaml
/// </summary>
public partial class MFAScreen : UserControl {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public delegate void LoadEvent(bool isComplete, string title, string message);
public event LoadEvent OnLoad;
public delegate void CloseAction(bool isComplete);
public event CloseAction OnClose;
private string _url = "";
public delegate void ErrorOccurred(string message);
public event ErrorOccurred OnError;
private string[] _codes = new string[0];
private ZitiIdentity _identity;
private bool _executing = false;
public int Type { get; set; }
public ZitiIdentity Identity {
get {
return this._identity;
}
set {
this._identity = value;
}
}
public MFAScreen() {
InitializeComponent();
}
private void ExecuteClose(object sender, MouseButtonEventArgs e) {
this.OnClose?.Invoke(false);
}
private void ShowError(string message) {
this.OnError?.Invoke(message);
}
private BitmapImage CreateQRFromUrl(string url) {
QRCodeGenerator qrGenerator = new QRCodeGenerator();
QRCodeData qrCodeData = qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
QRCode qrCode = new QRCode(qrCodeData);
System.Drawing.Bitmap qrCodeImage = qrCode.GetGraphic(20);
MemoryStream ms = new MemoryStream();
((System.Drawing.Bitmap)qrCodeImage).Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
BitmapImage image = new BitmapImage();
image.BeginInit();
ms.Seek(0, SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();
return image;
}
public void ShowSetup(ZitiIdentity identity, string url, string secret) {
SetupCode.Text = "";
this._identity = identity;
MFAImage.Visibility = Visibility.Visible;
SecretCode.Visibility = Visibility.Collapsed;
CloseBlack.Visibility = Visibility.Visible;
CloseWhite.Visibility = Visibility.Collapsed;
SecretButton.Content = "Show Secret";
IdName.Content = identity.Name;
Logger.Debug($"MFA Url: {url}");
AuthBrush.Visibility = Visibility.Collapsed;
MainBrush.Visibility = Visibility.Visible;
MFAImage.Source = CreateQRFromUrl(url);
SecretCode.Text = secret;
_url = url;
MFAArea.Height = 515;
MFAAuthArea.Visibility = Visibility.Collapsed;
MFASetupArea.Visibility = Visibility.Visible;
MFARecoveryArea.Visibility = Visibility.Collapsed;
SeperationColor.Visibility = Visibility.Visible;
SetupCode.Focus();
}
public void ShowRecovery(string[] codes, ZitiIdentity identity) {
this._identity = identity;
MFASetupArea.Visibility = Visibility.Collapsed;
MFAAuthArea.Visibility = Visibility.Collapsed;
SeperationColor.Visibility = Visibility.Collapsed;
MFARecoveryArea.Visibility = Visibility.Visible;
RecoveryList.Children.Clear();
_codes = codes;
AuthBrush.Visibility = Visibility.Collapsed;
MainBrush.Visibility = Visibility.Visible;
CloseBlack.Visibility = Visibility.Visible;
CloseWhite.Visibility = Visibility.Collapsed;
MFAArea.Height = 380;
if (codes.Length>0) {
for (int i = 0; i < codes.Length; i++) {
TextBox label = new TextBox();
label.Text = codes[i];
label.BorderThickness = new Thickness(0);
label.Background = new SolidColorBrush();
label.Background.Opacity = 0;
label.HorizontalAlignment = HorizontalAlignment.Center;
label.HorizontalContentAlignment = HorizontalAlignment.Center;
label.VerticalAlignment = VerticalAlignment.Center;
label.VerticalContentAlignment = VerticalAlignment.Center;
RecoveryList.Children.Add(label);
}
RecoveryList.Visibility = Visibility.Visible;
NoRecovery.Visibility = Visibility.Collapsed;
} else {
RecoveryList.Visibility = Visibility.Collapsed;
NoRecovery.Visibility = Visibility.Visible;
}
}
public void ShowMFA(ZitiIdentity identity, int type) {
this.Type = type;
AuthCode.Text = "";
AuthBrush.Visibility = Visibility.Visible;
MainBrush.Visibility = Visibility.Collapsed;
CloseBlack.Visibility = Visibility.Collapsed;
CloseWhite.Visibility = Visibility.Visible;
this._identity = identity;
MFASetupArea.Visibility = Visibility.Collapsed;
MFARecoveryArea.Visibility = Visibility.Collapsed;
SeperationColor.Visibility = Visibility.Collapsed;
MFAAuthArea.Visibility = Visibility.Visible;
MFAArea.Height = 220;
AuthCode.Focus();
}
private BitmapImage LoadImage(string url) {
var imgUrl = new Uri(url);
var imageData = new WebClient().DownloadData(imgUrl);
var bitmapImage = new BitmapImage { CacheOption = BitmapCacheOption.OnLoad };
bitmapImage.BeginInit();
bitmapImage.StreamSource = new MemoryStream(imageData);
bitmapImage.EndInit();
return bitmapImage;
}
private void GoTo(object sender, MouseButtonEventArgs e) {
if (_url!=null&&_url.Length>0) {
Process.Start(new ProcessStartInfo(_url) { UseShellExecute = true });
} else {
this.OnError?.Invoke("Invalid MFA Url");
}
}
async private void ReturnMFACodes(object sender, MouseButtonEventArgs e) {
DataClient serviceClient = serviceClient = (DataClient)Application.Current.Properties["ServiceClient"];
string code = AuthCode.Text;
Logger.Debug("AuthMFA successful.");
MfaRecoveryCodesResponse getcodes = await serviceClient.ReturnMFACodes(this._identity.Fingerprint, code);
if (getcodes.Code != 0) {
Logger.Error("AuthMFA failed. " + getcodes.Message);
}
Logger.Error("PAYLOAD: {0}", getcodes.Payload);
}
async private void GenerateMFACodes(object sender, MouseButtonEventArgs e) {
DataClient serviceClient = serviceClient = (DataClient)Application.Current.Properties["ServiceClient"];
string code = AuthCode.Text;
MfaRecoveryCodesResponse gencodes = await serviceClient.GenerateMFACodes(this._identity.Fingerprint, code);
if (gencodes.Code != 0) {
Logger.Error("AuthMFA failed. " + gencodes.Message);
}
Logger.Error("PAYLOAD: {0}", gencodes.Payload);
}
private void SaveCodes() {
string fileText = string.Join("\n", _codes);
string name = Regex.Replace(this._identity.Name, "[^a-zA-Z0-9]", String.Empty);
System.Windows.Forms.SaveFileDialog dialog = new System.Windows.Forms.SaveFileDialog();
dialog.Filter = "Text Files(*.txt)|*.txt|All(*.*)|*";
dialog.Title = "Save Recovery Codes";
dialog.FileName = name+"RecoveryCodes.txt";
dialog.ShowDialog();
if (dialog.FileName != "") {
File.WriteAllText(dialog.FileName, fileText);
}
}
async private void DoSetupAuthenticate() {
string code = SetupCode.Text;
DataClient serviceClient = serviceClient = (DataClient)Application.Current.Properties["ServiceClient"];
SvcResponse resp = await serviceClient.VerifyMFA(this._identity.Fingerprint, code);
if (resp.Code != 0) {
this.OnClose?.Invoke(false);
} else {
this.OnClose?.Invoke(false);
}
}
async private void DoAuthenticate() {
if (!this._executing) {
this._executing = true;
string code = AuthCode.Text;
DataClient serviceClient = (DataClient)Application.Current.Properties["ServiceClient"];
this.OnLoad?.Invoke(false, "Authentication", "One Moment Please...");
if (this.Type == 1) {
SvcResponse authResult = await serviceClient.AuthMFA(this._identity.Fingerprint, code);
if (authResult?.Code != 0) {
Logger.Error("AuthMFA failed. " + authResult.Message);
this.OnError?.Invoke("Authentication Failed");
this._executing = false;
} else {
MfaRecoveryCodesResponse codeResponse = await serviceClient.ReturnMFACodes(this._identity.Fingerprint, code);
this._identity.MFAInfo.RecoveryCodes = codeResponse.Payload;
this._identity.MFAInfo.IsAuthenticated = true;
this.OnClose?.Invoke(true);
this._executing = false;
}
this.OnLoad?.Invoke(true, "", "");
} else if (this.Type == 2) {
MfaRecoveryCodesResponse codeResponse = await serviceClient.ReturnMFACodes(this._identity.Fingerprint, code);
if (codeResponse?.Code != 0) {
Logger.Error("AuthMFA failed. " + codeResponse.Message);
AuthCode.Text = "";
this.OnError?.Invoke("Authentication Failed");
this._executing = false;
} else {
this._identity.MFAInfo.RecoveryCodes = codeResponse.Payload;
this.OnClose?.Invoke(true);
this._executing = false;
}
this.OnLoad?.Invoke(true, "", "");
} else if (this.Type == 3) {
SvcResponse authResult = await serviceClient.RemoveMFA(this._identity.Fingerprint, code);
if (authResult?.Code != 0) {
Logger.Error("AuthMFA failed. " + authResult.Message);
AuthCode.Text = "";
this.OnError?.Invoke("Authentication Failed");
this._executing = false;
} else {
this.OnClose?.Invoke(true);
this._executing = false;
}
this.OnLoad?.Invoke(true, "", "");
} else if (this.Type == 4) {
MfaRecoveryCodesResponse codeResponse = await serviceClient.GenerateMFACodes(this._identity.Fingerprint, code);
if (codeResponse?.Code != 0) {
Logger.Error("AuthMFA failed. " + codeResponse.Message);
AuthCode.Text = "";
this.OnError?.Invoke("Authentication Failed");
this._executing = false;
} else {
this._identity.MFAInfo.RecoveryCodes = codeResponse.Payload;
this.OnClose?.Invoke(true);
this._executing = false;
}
this.OnLoad?.Invoke(true, "", "");
}
}
}
private void RegenerateCodes(object sender, MouseButtonEventArgs e) {
ShowMFA(this._identity, 4);
}
private void ShowSecret(object sender, MouseButtonEventArgs e) {
if (SecretCode.Visibility==Visibility.Visible) {
MFAImage.Visibility = Visibility.Visible;
SecretCode.Visibility = Visibility.Collapsed;
SecretButton.Content = "Show Secret";
} else {
MFAImage.Visibility = Visibility.Collapsed;
SecretCode.Visibility = Visibility.Visible;
SecretButton.Content = "Show QR Code";
}
}
private void HandleKey(object sender, KeyEventArgs e) {
if (e.Key == Key.Return) {
DoSetupAuthenticate();
}
}
private void AuthCode_KeyUp(object sender, KeyEventArgs e) {
if (e.Key == Key.Return) {
DoAuthenticate();
}
}
}
}