diff --git a/DesktopEdge/App.xaml b/DesktopEdge/App.xaml
index bcd9158d..8d816d24 100644
--- a/DesktopEdge/App.xaml
+++ b/DesktopEdge/App.xaml
@@ -1,7 +1,8 @@
-
@@ -18,7 +19,7 @@
-
+
@@ -33,7 +34,7 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DesktopEdge/Assets/Images/disconnected.png b/DesktopEdge/Assets/Images/disconnected.png
new file mode 100644
index 00000000..5853d7a6
Binary files /dev/null and b/DesktopEdge/Assets/Images/disconnected.png differ
diff --git a/DesktopEdge/Assets/Images/name.png b/DesktopEdge/Assets/Images/name.png
new file mode 100644
index 00000000..0897340f
Binary files /dev/null and b/DesktopEdge/Assets/Images/name.png differ
diff --git a/DesktopEdge/Assets/Images/statusconnected.png b/DesktopEdge/Assets/Images/statusconnected.png
new file mode 100644
index 00000000..d558909d
Binary files /dev/null and b/DesktopEdge/Assets/Images/statusconnected.png differ
diff --git a/DesktopEdge/MainWindow.xaml b/DesktopEdge/MainWindow.xaml
index 9b10b302..c6fd3c04 100644
--- a/DesktopEdge/MainWindow.xaml
+++ b/DesktopEdge/MainWindow.xaml
@@ -202,7 +202,7 @@
-
+
@@ -217,7 +217,7 @@
-
+
@@ -247,7 +247,8 @@
-
+
+
diff --git a/DesktopEdge/MainWindow.xaml.cs b/DesktopEdge/MainWindow.xaml.cs
index c67c738d..14620335 100644
--- a/DesktopEdge/MainWindow.xaml.cs
+++ b/DesktopEdge/MainWindow.xaml.cs
@@ -156,6 +156,11 @@ namespace ZitiDesktopEdge {
this.ShowMFA(identity, 1);
}
+ ///
+ /// Show MFA for the identity and set the type of screen to show
+ ///
+ /// The Identity that is currently active
+ /// The type of screen to show - 1 Setup, 2 Authenticate, 3 Remove MFA, 4 Regenerate Codes
private void ShowMFA(ZitiIdentity identity, int type) {
MFASetup.Opacity = 0;
MFASetup.Visibility = Visibility.Visible;
@@ -342,10 +347,18 @@ namespace ZitiDesktopEdge {
this.IdentityMenu.MainWindow = this;
SetNotifyIcon("white");
+ this.PreviewKeyDown += KeyPressed;
MFASetup.OnLoad += MFASetup_OnLoad;
IdentityMenu.OnMessage += IdentityMenu_OnMessage;
}
+ private void KeyPressed(object sender, KeyEventArgs e) {
+ if (e.Key == Key.Escape) {
+ if (IdentityMenu.Visibility == Visibility.Visible) IdentityMenu.Visibility = Visibility.Collapsed;
+ else if (MainMenu.Visibility == Visibility.Visible) MainMenu.Visibility = Visibility.Collapsed;
+ }
+ }
+
private void MFASetup_OnLoad(bool isComplete, string title, string message) {
if (isComplete) HideLoad();
else ShowLoad(title, message);
@@ -503,6 +516,7 @@ namespace ZitiDesktopEdge {
Application.Current.Properties.Add("Identities", new List());
MainMenu.OnAttachmentChange += AttachmentChanged;
MainMenu.OnLogLevelChanged += LogLevelChanged;
+ MainMenu.OnShowBlurb += MainMenu_OnShowBlurb;
IdentityMenu.OnError += IdentityMenu_OnError;
try {
@@ -524,7 +538,11 @@ namespace ZitiDesktopEdge {
Placement();
}
- private void ServiceClient_OnBulkServiceEvent(object sender, BulkServiceEvent e) {
+ private void MainMenu_OnShowBlurb(string message) {
+ _ = ShowBlurbAsync(message, "", "info");
+ }
+
+ private void ServiceClient_OnBulkServiceEvent(object sender, BulkServiceEvent e) {
var found = identities.Find(id => id.Fingerprint == e.Fingerprint);
if (found == null) {
logger.Warn($"{e.Action} service event for {e.Fingerprint} but the provided identity fingerprint was not found!");
@@ -1287,7 +1305,14 @@ namespace ZitiDesktopEdge {
///
/// The message to show
/// The url or action name to execute
- public async Task ShowBlurbAsync(string message, string url) {
+ public async Task ShowBlurbAsync(string message, string url, string level="error") {
+ RedBlurb.Visibility = Visibility.Collapsed;
+ InfoBlurb.Visibility = Visibility.Collapsed;
+ if (level=="error") {
+ RedBlurb.Visibility = Visibility.Visible;
+ } else {
+ InfoBlurb.Visibility = Visibility.Visible;
+ }
Blurb.Content = message;
_blurbUrl = url;
BlurbArea.Visibility = Visibility.Visible;
@@ -1377,6 +1402,11 @@ namespace ZitiDesktopEdge {
someCommand = value;
}
}
+
+ private void DoLoading(bool isComplete) {
+ if (isComplete) HideLoad();
+ else ShowLoad("Loading", "Please Wait.");
+ }
}
public class ActionCommand : ICommand {
diff --git a/DesktopEdge/Models/FilterData.cs b/DesktopEdge/Models/FilterData.cs
new file mode 100644
index 00000000..408000e9
--- /dev/null
+++ b/DesktopEdge/Models/FilterData.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ZitiDesktopEdge.Models {
+ public class FilterData {
+
+ public FilterData():this("", "", "asc") { }
+
+ public FilterData(string searchFor, string sortBy, string sortHow) {
+ SearchFor = searchFor;
+ SortBy = sortBy;
+ SortHow = sortHow;
+ }
+
+ public string SearchFor { get; set; }
+ public string SortBy { get; set; }
+ public string SortHow { get; set; }
+ }
+}
diff --git a/DesktopEdge/Models/ZitiService.cs b/DesktopEdge/Models/ZitiService.cs
index c585b7b5..aa762fc5 100644
--- a/DesktopEdge/Models/ZitiService.cs
+++ b/DesktopEdge/Models/ZitiService.cs
@@ -1,133 +1,241 @@
using NLog;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-using ZitiDesktopEdge.DataStructures;
-
-namespace ZitiDesktopEdge.Models {
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+
+using ZitiDesktopEdge.DataStructures;
+
+namespace ZitiDesktopEdge.Models {
public class ZitiService {
- private static readonly Logger logger = LogManager.GetCurrentClassLogger();
-
- public string Name { get; set; }
- public string[] Protocols { get; set; }
- public Address[] Addresses { get; set; }
- public PortRange[] Ports { get; set; }
- public PostureCheck[] PostureChecks { get; set; }
- public bool OwnsIntercept { get; set; }
- public string AssignedIP { get; set; }
-
- private bool failingPostureCheck;
- public bool HasFailingPostureCheck() {
+ private static readonly Logger logger = LogManager.GetCurrentClassLogger();
+
+ public string Name { get; set; }
+ public string[] Protocols { get; set; }
+ public Address[] Addresses { get; set; }
+ public PortRange[] Ports { get; set; }
+ public PostureCheck[] PostureChecks { get; set; }
+ public bool OwnsIntercept { get; set; }
+ public string AssignedIP { get; set; }
+
+ private bool failingPostureCheck;
+ public bool HasFailingPostureCheck() {
return failingPostureCheck;
- }
- public bool IsAccessable { get; set; }
-
- public string Warning {
- get {
- if (this.OwnsIntercept) {
- return "";
- } else {
- return "this won't trigger right now"; //$"Another identity already mapped the specified hostname: {Host}.\nThis service is only available via IP";
- }
- }
- }
-
- public ZitiService() {
- }
-
- public ZitiService(Service svc) {
- this.Name = svc.Name;
- this.AssignedIP = svc.AssignedIP;
- this.Addresses = svc.Addresses;
- this.Protocols = svc.Protocols == null ? null : svc.Protocols.Select(p => p.ToUpper()).ToArray();
- this.Ports = svc.Ports;
- this.PostureChecks = svc.PostureChecks;
+ }
+ public bool IsAccessable { get; set; }
+
+ public string Warning {
+ get {
+ if (this.OwnsIntercept) {
+ return "";
+ } else {
+ return "this won't trigger right now"; //$"Another identity already mapped the specified hostname: {Host}.\nThis service is only available via IP";
+ }
+ }
+ }
+
+ public ZitiService() {
+ }
+
+ public ZitiService(Service svc) {
+ this.Name = svc.Name;
+ this.AssignedIP = svc.AssignedIP;
+ this.Addresses = svc.Addresses;
+ this.Protocols = svc.Protocols == null ? null : svc.Protocols.Select(p => p.ToUpper()).ToArray();
+ this.Ports = svc.Ports;
+ this.PostureChecks = svc.PostureChecks;
this.OwnsIntercept = svc.OwnsIntercept;
if (this.PostureChecks != null) {
this.failingPostureCheck = this.PostureChecks.Any(p => !p.IsPassing);
- }
- this.IsAccessable = svc.IsAccessable;
- //commented out for now logger.Warn("SERVICE: " + this.Name + " HAS FAILING POSTURE CHECK: " + failingPostureCheck);
- }
-
-
-
- private ServiceMatrix builtMatrix = null;
- public ServiceMatrix Matrix {
- get {
- if (builtMatrix == null) {
- builtMatrix = new ServiceMatrix();
- List matrix = new List(this.Protocols.Length * this.Addresses.Length * this.Ports.Length);
-
- foreach (var proto in this.Protocols) {
- foreach (var addy in this.Addresses) {
- foreach (var port in this.Ports) {
- ServiceMatrixElement m = new ServiceMatrixElement();
- m.Ports = port.ToString();
- m.Proto = proto.ToUpper();
- m.Address = addy.Hostname;
-
- matrix.Add(m);
- }
- }
- }
- builtMatrix.Elements = matrix;
- }
-
- return builtMatrix;
- }
- }
-
- public override string ToString() {
- string protos = "";
- if (Protocols?.Length > 0) {
- if (Protocols.Length > 1) {
- protos = "[" + string.Join(",", Protocols.Select(p => p.ToString())) + "]";
- } else {
- protos = Protocols[0];
- }
- }
- string addys = "";
- if (Addresses?.Length > 0) {
- if (Addresses.Length > 1) {
- addys = "[" + string.Join(",", Addresses.Select(a => a.ToString()).OrderBy(o => o)) + "]";
- } else {
- addys = Addresses[0].ToString();
- }
- }
- string ranges = "";
- if (Ports?.Length > 0) {
- if (Ports.Length > 1) {
- ranges = "[" + string.Join(",", Ports.Select(a => a.ToString()).OrderBy(o => o)) + "]";
- } else {
- ranges = Ports[0].ToString();
- }
- }
-
- return protos + ":" + addys + ":" + ranges;
- }
- }
-
- public class ServiceMatrix {
- public List Elements { get; internal set; }
- }
-
- public class ServiceMatrixElement {
- public ServiceMatrixElement() {
- Proto = "";
- Address = "";
- Ports = "";
- }
-
- public string Proto { get; set; }
- public string Address { get; set; }
- public string Ports { get; set; }
-
- public override string ToString() {
- return Proto + " " + Address + " " + Ports;
- }
- }
-}
+ }
+ this.IsAccessable = svc.IsAccessable;
+ //commented out for now logger.Warn("SERVICE: " + this.Name + " HAS FAILING POSTURE CHECK: " + failingPostureCheck);
+ }
+
+ public string WarningMessage {
+ get {
+ string message = Warning;
+ if (this.PostureChecks != null && this.PostureChecks.Length > 0) {
+ List messages = new List();
+ for (int i = 0; i < this.PostureChecks.Length; i++) {
+ if (!this.PostureChecks[i].IsPassing) {
+ messages = AppendMessage(messages, this.PostureChecks[i].QueryType);
+ }
+ }
+ if (messages.Count > 0) {
+ string checks = "";
+ for (int i = 0; i < messages.Count; i++) {
+ checks += ((i > 0) ? ", " : "") + messages[i].Total + " " + messages[i].Message;
+ }
+ message = message + " Posture Check Failing: " + checks;
+ return message.Trim();
+ } else return message;
+ } else return message;
+ }
+ }
+ private List AppendMessage(List items, string message) {
+ bool found = false;
+ for (int i = 0; i < items.Count; i++) {
+ if (items[i].Message == message) {
+ items[i].Total++;
+ found = true;
+ }
+ }
+ if (!found) {
+ MessageCount count = new MessageCount();
+ count.Total = 1;
+ count.Message = message;
+ items.Add(count);
+ }
+ return items;
+ }
+
+ public int WarnWidth {
+ get {
+ return (HasWarning) ? 30 : 0;
+ }
+ set { }
+ }
+
+ public Visibility WarningVisibility {
+ get {
+ return (HasWarning) ? Visibility.Visible : Visibility.Collapsed;
+ }
+ set { }
+ }
+
+ public bool HasWarning {
+ get {
+ if (!this.OwnsIntercept) return true;
+ else {
+ if (this.IsAccessable) {
+ return false;
+ } else {
+ if (this.PostureChecks==null) {
+ return false;
+ } else {
+ for (int i = 0; i < this.PostureChecks.Length; i++) {
+ if (!this.PostureChecks[i].IsPassing) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ }
+ }
+ set { }
+ }
+
+ public string ProtocolString {
+ get {
+ string toReturn = "";
+ for (int i = 0; i < this.Protocols.Length; i++) {
+ toReturn += ((i > 0) ? "," : "") + this.Protocols[i];
+ }
+ return toReturn;
+ }
+ set { }
+ }
+
+ public string PortString {
+ get {
+ string toReturn = "";
+ for (int i = 0; i < this.Ports.Length; i++) {
+ toReturn += ((i > 0) ? "," : "") + this.Ports[i].ToString();
+ }
+ return toReturn;
+ }
+ set { }
+ }
+
+ public string AddressString {
+ get {
+ string toReturn = "";
+ for (int i = 0; i < this.Addresses.Length; i++) {
+ toReturn += ((i > 0) ? "," : "") + this.Addresses[i].ToString();
+ }
+ return toReturn;
+ }
+ set { }
+ }
+
+ private ServiceMatrix builtMatrix = null;
+ public ServiceMatrix Matrix {
+ get {
+ if (builtMatrix == null) {
+ builtMatrix = new ServiceMatrix();
+ List matrix = new List(this.Protocols.Length * this.Addresses.Length * this.Ports.Length);
+
+ foreach (var proto in this.Protocols) {
+ foreach (var addy in this.Addresses) {
+ foreach (var port in this.Ports) {
+ ServiceMatrixElement m = new ServiceMatrixElement();
+ m.Ports = port.ToString();
+ m.Proto = proto.ToUpper();
+ m.Address = addy.Hostname;
+
+ matrix.Add(m);
+ }
+ }
+ }
+ builtMatrix.Elements = matrix;
+ }
+
+ return builtMatrix;
+ }
+ }
+
+ public override string ToString() {
+ string protos = "";
+ if (Protocols?.Length > 0) {
+ if (Protocols.Length > 1) {
+ protos = "[" + string.Join(",", Protocols.Select(p => p.ToString())) + "]";
+ } else {
+ protos = Protocols[0];
+ }
+ }
+ string addys = "";
+ if (Addresses?.Length > 0) {
+ if (Addresses.Length > 1) {
+ addys = "[" + string.Join(",", Addresses.Select(a => a.ToString()).OrderBy(o => o)) + "]";
+ } else {
+ addys = Addresses[0].ToString();
+ }
+ }
+ string ranges = "";
+ if (Ports?.Length > 0) {
+ if (Ports.Length > 1) {
+ ranges = "[" + string.Join(",", Ports.Select(a => a.ToString()).OrderBy(o => o)) + "]";
+ } else {
+ ranges = Ports[0].ToString();
+ }
+ }
+
+ return protos + ":" + addys + ":" + ranges;
+ }
+ }
+
+ public class ServiceMatrix {
+ public List Elements { get; internal set; }
+ }
+
+ public class ServiceMatrixElement {
+ public ServiceMatrixElement() {
+ Proto = "";
+ Address = "";
+ Ports = "";
+ }
+
+ public string Proto { get; set; }
+ public string Address { get; set; }
+ public string Ports { get; set; }
+
+ public override string ToString() {
+ return Proto + " " + Address + " " + Ports;
+ }
+ }
+}
diff --git a/DesktopEdge/Properties/AssemblyInfo.cs b/DesktopEdge/Properties/AssemblyInfo.cs
index ec3cefc3..127f5b62 100644
--- a/DesktopEdge/Properties/AssemblyInfo.cs
+++ b/DesktopEdge/Properties/AssemblyInfo.cs
@@ -50,6 +50,6 @@ using System.Windows;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.9.3.0")]
-[assembly: AssemblyVersion("1.9.3.0")]
-[assembly: AssemblyFileVersion("1.9.3.0")]
+// [assembly: AssemblyVersion("1.9.4.0")]
+[assembly: AssemblyVersion("1.9.4.0")]
+[assembly: AssemblyFileVersion("1.9.4.0")]
diff --git a/DesktopEdge/Views/Controls/StyledButton.xaml b/DesktopEdge/Views/Controls/StyledButton.xaml
index 5bb623f8..51d11a1d 100644
--- a/DesktopEdge/Views/Controls/StyledButton.xaml
+++ b/DesktopEdge/Views/Controls/StyledButton.xaml
@@ -20,6 +20,11 @@
+
+
+
+
+
diff --git a/DesktopEdge/Views/Controls/StyledButton.xaml.cs b/DesktopEdge/Views/Controls/StyledButton.xaml.cs
index 086f0cfe..c6f44b23 100644
--- a/DesktopEdge/Views/Controls/StyledButton.xaml.cs
+++ b/DesktopEdge/Views/Controls/StyledButton.xaml.cs
@@ -23,6 +23,15 @@ namespace ZitiDesktopEdge {
public delegate void ClickAction();
public event ClickAction OnClick;
private string _label = "";
+ private string bgColor = "#0069FF";
+
+ public string BgColor {
+ get { return bgColor; }
+ set {
+ bgColor = value;
+ ButtonBgColor.Color = (Color)ColorConverter.ConvertFromString(bgColor);
+ }
+ }
public string Label {
get {
@@ -44,8 +53,8 @@ namespace ZitiDesktopEdge {
/// The button object
/// The mouse event
private void Hover(object sender, MouseEventArgs e) {
- ButtonBg.Opacity = 0.8;
- ButtonBg.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(1.0, TimeSpan.FromSeconds(.3)));
+ ButtonBgDarken.Opacity = 0.0;
+ ButtonBgDarken.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(0.2, TimeSpan.FromSeconds(.3)));
}
///
@@ -54,9 +63,8 @@ namespace ZitiDesktopEdge {
/// The button object
/// The mouse event
private void Leave(object sender, MouseEventArgs e) {
- ButtonBgColor.Color = Color.FromRgb(0, 104, 249);
- ButtonBg.BeginAnimation(Grid.OpacityProperty, null);
- ButtonBg.Opacity = 0.8;
+ ButtonBgDarken.Opacity = 0.2;
+ ButtonBgDarken.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(0.0, TimeSpan.FromSeconds(.3)));
}
///
@@ -65,7 +73,7 @@ namespace ZitiDesktopEdge {
///
///
private void Down(object sender, MouseButtonEventArgs e) {
- ButtonBgColor.Color = Color.FromRgb(126, 180, 255);
+ // ButtonBgColor.Color = Color.FromRgb(126, 180, 255);
}
///
diff --git a/DesktopEdge/Views/ItemRenderers/Filter.xaml b/DesktopEdge/Views/ItemRenderers/Filter.xaml
new file mode 100644
index 00000000..f44575bf
--- /dev/null
+++ b/DesktopEdge/Views/ItemRenderers/Filter.xaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+ Address
+ Protocol
+ Port
+
+
+ Asc
+ Desc
+
+
+
+
diff --git a/DesktopEdge/Views/ItemRenderers/Filter.xaml.cs b/DesktopEdge/Views/ItemRenderers/Filter.xaml.cs
new file mode 100644
index 00000000..1c39c4b8
--- /dev/null
+++ b/DesktopEdge/Views/ItemRenderers/Filter.xaml.cs
@@ -0,0 +1,106 @@
+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.Timers;
+using ZitiDesktopEdge.Models;
+
+namespace ZitiDesktopEdge {
+ ///
+ /// Interaction logic for Filter.xaml
+ ///
+ public partial class Filter :UserControl {
+
+ public delegate void OnFilterEvent(FilterData filter);
+ public event OnFilterEvent OnFilter;
+ public string placeholder = "any text";
+ private static Timer timeout;
+
+ private FilterData filter = new FilterData("", "Name", "Asc");
+ public Filter() {
+ InitializeComponent();
+ }
+
+ public void Clear() {
+ FilterFor.Text = "";
+ filter.SearchFor = "";
+ FilterFor.Text = placeholder;
+ SortWayField.SelectedIndex = 0;
+ SortByField.SelectedIndex = 0;
+ }
+
+ private void FilterPressed(object sender, KeyEventArgs e) {
+ if (e.Key==Key.Enter) {
+ OnFilter?.Invoke(filter);
+ }
+ }
+
+ private void FilterChanged(object sender, KeyEventArgs e) {
+ string search = FilterFor.Text.Trim();
+ if (filter.SearchFor!=search) {
+ filter.SearchFor = search;
+ if (filter.SearchFor == placeholder) filter.SearchFor = "";
+
+ if (e.Key==Key.Enter) {
+ OnFilter?.Invoke(filter);
+ } else {
+ if (timeout != null && timeout.Enabled) {
+ timeout.Close();
+ }
+ timeout = new Timer(1000);
+ timeout.Elapsed += OnTimedEvent;
+ timeout.AutoReset = false;
+ timeout.Enabled = true;
+ }
+ }
+ }
+
+ private void SortWayChanged(object sender, SelectionChangedEventArgs e) {
+ ComboBoxItem selected = (ComboBoxItem)SortWayField.SelectedValue;
+ if (selected != null && selected.Content != null) {
+ if (selected.Content.ToString() != filter.SortHow) {
+ filter.SortHow = selected.Content.ToString();
+ this.OnFilter?.Invoke(filter);
+ }
+ }
+ }
+
+ private void SortByChanged(object sender, SelectionChangedEventArgs e) {
+ ComboBoxItem selected = (ComboBoxItem)SortByField.SelectedValue;
+ if (selected != null && selected.Content != null) {
+ if (selected.Content.ToString() != filter.SortBy) {
+ filter.SortBy = selected.Content.ToString();
+ this.OnFilter?.Invoke(filter);
+ }
+ }
+ }
+
+ private void FocusFilter(object sender, RoutedEventArgs e) {
+ if (FilterFor.Text==placeholder) {
+ FilterFor.Text = "";
+ }
+ }
+
+ private void FocusLostFilter(object sender, RoutedEventArgs e) {
+ if (FilterFor.Text.Trim() == "") {
+ FilterFor.Text = placeholder;
+ }
+ }
+
+ private void OnTimedEvent(Object source, ElapsedEventArgs e) {
+ this.Dispatcher.Invoke(() => {
+ OnFilter?.Invoke(filter);
+ });
+ }
+ }
+}
diff --git a/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs b/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs
index 1b75ed8e..32ca433e 100644
--- a/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs
+++ b/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs
@@ -107,8 +107,6 @@ namespace ZitiDesktopEdge {
private void OpenDetails(object sender, MouseButtonEventArgs e) {
IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu;
deets.SelectedIdentity = this;
- deets.ServiceTitle.Clear();
- deets.IdDetailToggle.Enabled = this.Identity.IsEnabled;
deets.Identity = this.Identity;
}
diff --git a/DesktopEdge/Views/ItemRenderers/MenuEditItem.xaml b/DesktopEdge/Views/ItemRenderers/MenuEditItem.xaml
index 3bebb7db..2e843e7c 100644
--- a/DesktopEdge/Views/ItemRenderers/MenuEditItem.xaml
+++ b/DesktopEdge/Views/ItemRenderers/MenuEditItem.xaml
@@ -15,6 +15,5 @@
-
\ No newline at end of file
diff --git a/DesktopEdge/Views/ItemRenderers/MenuEditSearch.xaml b/DesktopEdge/Views/ItemRenderers/MenuEditSearch.xaml
index d40627ac..02d1bc3f 100644
--- a/DesktopEdge/Views/ItemRenderers/MenuEditSearch.xaml
+++ b/DesktopEdge/Views/ItemRenderers/MenuEditSearch.xaml
@@ -21,7 +21,7 @@
diff --git a/DesktopEdge/Views/ItemRenderers/MenuIdentityItem.xaml.cs b/DesktopEdge/Views/ItemRenderers/MenuIdentityItem.xaml.cs
index 1244c1fb..36586978 100644
--- a/DesktopEdge/Views/ItemRenderers/MenuIdentityItem.xaml.cs
+++ b/DesktopEdge/Views/ItemRenderers/MenuIdentityItem.xaml.cs
@@ -64,7 +64,6 @@ namespace ZitiDesktopEdge {
private void ShowIdentity(object sender, MouseButtonEventArgs e) {
IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu;
deets.SelectedIdentityMenu = this;
- deets.IdDetailToggle.Enabled = this.Identity.IsEnabled;
deets.Identity = this.Identity;
}
}
diff --git a/DesktopEdge/Views/ItemRenderers/ServiceInfo.xaml b/DesktopEdge/Views/ItemRenderers/ServiceInfo.xaml
index cbb7e818..d88c7b68 100644
--- a/DesktopEdge/Views/ItemRenderers/ServiceInfo.xaml
+++ b/DesktopEdge/Views/ItemRenderers/ServiceInfo.xaml
@@ -9,7 +9,8 @@
-
+
+
@@ -17,8 +18,12 @@
-
-
+
+
+
+
+
+
diff --git a/DesktopEdge/Views/ItemRenderers/ServiceInfo.xaml.cs b/DesktopEdge/Views/ItemRenderers/ServiceInfo.xaml.cs
index 4534dc1e..e0e678d5 100644
--- a/DesktopEdge/Views/ItemRenderers/ServiceInfo.xaml.cs
+++ b/DesktopEdge/Views/ItemRenderers/ServiceInfo.xaml.cs
@@ -36,10 +36,41 @@ namespace ZitiDesktopEdge {
}
set {
this._info = value;
- MainEdit.ToolTip = this._info.ToString();
- MainEdit.Text = this._info.ToString();
+
+ string addresses = "";
+ if (_info.Addresses!=null) {
+ for (int i = 0; i < this._info.Addresses?.Length; i++) {
+ addresses += ((i > 0) ? "," : "") + this._info.Addresses[i].Hostname;
+ }
+ }
+
+ MainEdit.ToolTip = addresses;
+ MainEdit.Text = addresses;
+
MainLabel.ToolTip = this._info.Name;
MainLabel.Text = this._info.Name;
+
+ string ports = "";
+ if (_info.Ports != null) {
+ for (int i = 0; i < this._info.Ports.Length; i++) {
+ ports += ((i > 0) ? "," : "") + this._info.Ports[i].ToString();
+ }
+ }
+
+ Ports.ToolTip = ports;
+ Ports.Text = ports;
+
+ string protocols = "";
+
+ if (_info.Protocols != null) {
+ for (int i = 0; i < this._info.Protocols.Length; i++) {
+ protocols += ((i > 0) ? "," : "") + this._info.Protocols[i];
+ }
+ }
+
+ Protocols.ToolTip = protocols;
+ Protocols.Text = protocols;
+
WarningColumn.Width = new GridLength(0);
if (this._info.Warning.Length > 0) {
WarnIcon.ToolTip = this._info.Warning;
diff --git a/DesktopEdge/Views/Screens/IdentityDetails.xaml b/DesktopEdge/Views/Screens/IdentityDetails.xaml
index 408e801a..30fa1d48 100644
--- a/DesktopEdge/Views/Screens/IdentityDetails.xaml
+++ b/DesktopEdge/Views/Screens/IdentityDetails.xaml
@@ -6,7 +6,7 @@
xmlns:local="clr-namespace:ZitiDesktopEdge"
mc:Ignorable="d"
x:Name="IdentityArea"
- d:DesignHeight="500" d:DesignWidth="350">
+ d:DesignHeight="500" d:DesignWidth="350" IsVisibleChanged="VisibilityChanged">
-
+
-
+
-
-
+
+
-
+
-
+
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Name
- Address
- Protocol
- Port
-
-
-
-
-
-
- Asc
- Desc
-
-
-
-
-
+
+
-
-
+
@@ -149,7 +131,7 @@
-
+
diff --git a/DesktopEdge/Views/Screens/IdentityDetails.xaml.cs b/DesktopEdge/Views/Screens/IdentityDetails.xaml.cs
index ebaa8140..1bd4a1f1 100644
--- a/DesktopEdge/Views/Screens/IdentityDetails.xaml.cs
+++ b/DesktopEdge/Views/Screens/IdentityDetails.xaml.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
@@ -10,6 +11,8 @@ using System.Windows.Media.Animation;
using NLog;
using System.Web;
+using System.Windows.Media;
+using System.Windows.Data;
namespace ZitiDesktopEdge {
///
@@ -35,10 +38,21 @@ namespace ZitiDesktopEdge {
public event OnAuthenticate Authenticate;
public delegate void OnRecovery(ZitiIdentity identity);
public event OnRecovery Recovery;
+ public delegate void LoadingEvent(bool isComplete);
+ public event LoadingEvent OnLoading;
+
public int Page = 1;
public int PerPage = 50;
+ public int TotalPages = 1;
public string SortBy = "Name";
public string SortWay = "Asc";
+ private bool _loaded = false;
+ private double scrolledTo = 0;
+ public int totalServices = 0;
+ private ScrollViewer _scroller;
+
+ public ObservableCollection _services = new ObservableCollection();
+ public ObservableCollection ZitiServices { get { return _services; } }
internal MainWindow MainWindow { get; set; }
@@ -55,13 +69,15 @@ namespace ZitiDesktopEdge {
return _identity;
}
set {
+ _loaded = false;
+ FilterServices.Clear();
+ scrolledTo = 0;
_identity = value;
- this.IdDetailToggle.Enabled = _identity.IsEnabled;
+ ServiceCount.Content = _identity.Services.Count + " service"+((_identity.Services.Count>1)?"s":"");
Page = 1;
SortBy = "Name";
SortWay = "Asc";
- SortByField.SelectedIndex = 0;
- SortWayField.SelectedIndex = 0;
+ filter = "";
UpdateView();
IdentityArea.Opacity = 1.0;
IdentityArea.Visibility = Visibility.Visible;
@@ -97,16 +113,31 @@ namespace ZitiDesktopEdge {
}
public void UpdateView() {
+ if (_scroller==null) {
+ _scroller = GetScrollViewer(ServiceList) as ScrollViewer;
+ }
+ if (_scroller != null) {
+ _scroller.InvalidateScrollInfo();
+ _scroller.ScrollToVerticalOffset(0);
+ _scroller.InvalidateScrollInfo();
+ }
+ scrolledTo = 0;
IdDetailName.Text = _identity.Name;
IdDetailName.ToolTip = _identity.Name;
- IdDetailToggle.Enabled = _identity.IsEnabled;
- IdentityName.Value = _identity.Name;
- IdentityNetwork.Value = _identity.ControllerUrl;
- IdentityEnrollment.Value = _identity.EnrollmentStatus;
- IdentityStatus.Value = _identity.IsEnabled ? "active" : "disabled";
IdentityMFA.IsOn = _identity.IsMFAEnabled;
IdentityMFA.ToggleField.IsEnabled = true;
IdentityMFA.ToggleField.Opacity = 1;
+ IsConnected.Visibility = Visibility.Collapsed;
+ IsDisconnected.Visibility = Visibility.Collapsed;
+ IsConnected.ToolTip = "Enabled - Click To Disable";
+ IsDisconnected.ToolTip = "Disabled - Click to Enable";
+ IdServer.Value = _identity.ControllerUrl;
+ IdName.Value = _identity.Name;
+ if (_identity.IsEnabled) {
+ IsConnected.Visibility = Visibility.Visible;
+ } else {
+ IsDisconnected.Visibility = Visibility.Visible;
+ }
if (_identity.IsMFAEnabled) {
if (_identity.MFAInfo.IsAuthenticated) {
IdentityMFA.ToggleField.IsEnabled = true;
@@ -125,13 +156,16 @@ namespace ZitiDesktopEdge {
IdentityMFA.AuthOff.Visibility = Visibility.Collapsed;
IdentityMFA.RecoveryButton.Visibility = Visibility.Collapsed;
}
- ServiceList.Children.Clear();
- PageSortArea.Visibility = Visibility.Collapsed;
+ //ServiceList.Children.Clear();
+
+ totalServices = _identity.Services.Count;
+
if (_identity.Services.Count>0) {
- PageSortArea.Visibility = Visibility.Visible;
int index = 0;
int total = 0;
ZitiService[] services = new ZitiService[0];
+ _services = null;
+ _services = new ObservableCollection();
if (SortBy == "Name") services = _identity.Services.OrderBy(s => s.Name.ToLower()).ToArray();
else if (SortBy == "Address") services = _identity.Services.OrderBy(s => s.Addresses.ToString()).ToArray();
else if (SortBy == "Protocol") services = _identity.Services.OrderBy(s => s.Protocols.ToString()).ToArray();
@@ -140,86 +174,49 @@ namespace ZitiDesktopEdge {
int startIndex = (Page - 1) * PerPage;
for (int i= startIndex; i= 0 || zitiSvc.ToString().ToLower().IndexOf(filter.ToLower()) >= 0) {
- Logger.Trace("painting: " + zitiSvc.Name);
- ServiceInfo info = new ServiceInfo();
- info.Info = zitiSvc;
- info.OnMessage += Info_OnMessage;
- info.OnDetails += ShowDetails;
- ServiceList.Children.Add(info);
+ _services.Add(zitiSvc);
index++;
}
}
}
+ ServiceList.ItemsSource = ZitiServices;
- if (Page==1) {
- Pages.Items.Clear();
- int totalPages = (total / PerPage) + 1;
- for (int i = 1; i <= totalPages; i++) {
- ComboBoxItem item = new ComboBoxItem();
- if (i == Page) item.IsSelected = true;
- item.Content = i.ToString();
- Pages.Items.Add(item);
- }
- }
+ TotalPages = (total / PerPage) + 1;
- double newHeight = MainHeight - 330;
- ServiceRow.Height = new GridLength((double)newHeight);
+ double newHeight = MainHeight - 330;
MainDetailScroll.MaxHeight = newHeight;
MainDetailScroll.Height = newHeight;
MainDetailScroll.Visibility = Visibility.Visible;
- ServiceTitle.Label = _identity.Services.Count + " Services";
- ServiceTitle.MainEdit.Visibility = Visibility.Visible;
- ServiceTitle.Visibility = Visibility.Visible;
+
AuthMessageBg.Visibility = Visibility.Collapsed;
AuthMessageLabel.Visibility = Visibility.Collapsed;
NoAuthServices.Visibility = Visibility.Collapsed;
} else {
- ServiceRow.Height = new GridLength((double)0.0);
MainDetailScroll.Visibility = Visibility.Collapsed;
- ServiceTitle.Label = "No Services";
- ServiceTitle.MainEdit.Text = "";
- ServiceTitle.MainEdit.Visibility = Visibility.Collapsed;
if (this._identity.IsMFAEnabled&&!this._identity.MFAInfo.IsAuthenticated) {
- ServiceTitle.Visibility = Visibility.Collapsed;
AuthMessageBg.Visibility = Visibility.Visible;
AuthMessageLabel.Visibility = Visibility.Visible;
- ServiceRow.Height = new GridLength((double)30);
NoAuthServices.Visibility = Visibility.Visible;
} else {
- ServiceTitle.Visibility = Visibility.Visible;
AuthMessageBg.Visibility = Visibility.Collapsed;
AuthMessageLabel.Visibility = Visibility.Collapsed;
NoAuthServices.Visibility = Visibility.Collapsed;
}
}
ConfirmView.Visibility = Visibility.Collapsed;
+ _loaded = true;
}
private void ShowDetails(ZitiService info) {
DetailName.Text = info.Name;
+ DetailProtocols.Text = info.ProtocolString;
+ DetailAddress.Text = info.AddressString;
+ DetailPorts.Text = info.PortString;
DetailUrl.Text = info.ToString();
- string protocols = "";
- string addresses = "";
- string ports = "";
-
- for (int i = 0; i < info.Protocols.Length; i++) {
- protocols += ((i > 0) ? "," : "") + info.Protocols[i];
- }
- for (int i = 0; i < info.Addresses.Length; i++) {
- addresses += ((i>0)?",":"")+info.Addresses[i];
- }
- for (int i = 0; i < info.Ports.Length; i++) {
- ports += ((i > 0) ? "," : "") + info.Ports[i];
- }
-
- DetailProtocols.Text = protocols;
- DetailAddress.Text = addresses;
- DetailPorts.Text = ports;
-
DetailsArea.Visibility = Visibility.Visible;
DetailsArea.Opacity = 0;
DetailsArea.Margin = new Thickness(0, 0, 0, 0);
@@ -257,15 +254,6 @@ namespace ZitiDesktopEdge {
OnMessage?.Invoke(message);
}
- async private void IdToggle(bool on) {
- DataClient client = (DataClient)Application.Current.Properties["ServiceClient"];
- await client.IdentityOnOffAsync(_identity.Fingerprint, on);
- if (SelectedIdentity!=null) SelectedIdentity.ToggleSwitch.Enabled = on;
- if (SelectedIdentityMenu != null) SelectedIdentityMenu.ToggleSwitch.Enabled = on;
- _identity.IsEnabled = on;
- IdentityStatus.Value = _identity.IsEnabled ? "active" : "disabled";
- }
-
public IdentityDetails() {
InitializeComponent();
}
@@ -277,7 +265,7 @@ namespace ZitiDesktopEdge {
MainDetailScroll.Height = height;
}
- private void ForgetIdentity(object sender, MouseButtonEventArgs e) {
+ private void ForgetIdentity() {
if (this.Visibility==Visibility.Visible&&ConfirmView.Visibility==Visibility.Collapsed) {
ConfirmView.Visibility = Visibility.Visible;
}
@@ -313,12 +301,6 @@ namespace ZitiDesktopEdge {
}
}
- private void DoFilter(string filter) {
- this.filter = filter;
- if (this._identity!=null) UpdateView();
- }
-
-
private void ToggleMFA(bool isOn) {
this.OnMFAToggled?.Invoke(isOn);
}
@@ -364,33 +346,112 @@ namespace ZitiDesktopEdge {
this.Authenticate.Invoke(this.Identity);
}
- private void Pages_SelectionChanged(object sender, SelectionChangedEventArgs e) {
- ComboBoxItem selected = (ComboBoxItem)Pages.SelectedValue;
- if (selected!=null) {
- int value = Int32.Parse(selected.Content.ToString());
- if (value!=Page) {
- Page = value;
- UpdateView();
+ public static DependencyObject GetScrollViewer(DependencyObject o) {
+ if (o is ScrollViewer) { return o; }
+ for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++) {
+ var child = VisualTreeHelper.GetChild(o, i);
+ var result = GetScrollViewer(child);
+ if (result == null) {
+ continue;
+ } else {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ private void Scrolled(object sender, ScrollChangedEventArgs e) {
+ if (_loaded) {
+ if (_scroller == null) {
+ _scroller = GetScrollViewer(ServiceList) as ScrollViewer;
+ }
+ var verticalOffset = _scroller.VerticalOffset;
+ var maxVerticalOffset = _scroller.ScrollableHeight;
+
+ if ((maxVerticalOffset < 0 || verticalOffset == maxVerticalOffset) && verticalOffset>0 && scrolledTo s.Name.ToLower()).ToArray();
+ else if (SortBy == "Address") services = _identity.Services.OrderBy(s => s.Addresses.ToString()).ToArray();
+ else if (SortBy == "Protocol") services = _identity.Services.OrderBy(s => s.Protocols.ToString()).ToArray();
+ else if (SortBy == "Port") services = _identity.Services.OrderBy(s => s.Ports.ToString()).ToArray();
+ if (SortWay == "Desc") services = services.Reverse().ToArray();
+ int startIndex = (Page - 1) * PerPage;
+ for (int i = startIndex; i < services.Length; i++) {
+ ZitiService zitiSvc = services[i];
+ if (index < PerPage) {
+ if (zitiSvc.Name.ToLower().IndexOf(filter.ToLower()) >= 0 || zitiSvc.ToString().ToLower().IndexOf(filter.ToLower()) >= 0) {
+ ZitiServices.Add(zitiSvc);
+ index++;
+ }
+ }
+ }
+ double totalOffset = _scroller.VerticalOffset;
+ double toNegate = index * 33;
+ double scrollTo = (totalOffset - toNegate);
+ _scroller.InvalidateScrollInfo();
+ _scroller.ScrollToVerticalOffset(verticalOffset);
+ _scroller.InvalidateScrollInfo();
+ _loaded = true;
+ // scrollViewer.ScrollChanged += Scrolled;
+ }
}
}
}
- private void SortByField_SelectionChanged(object sender, SelectionChangedEventArgs e) {
- ComboBoxItem selected = (ComboBoxItem)SortByField.SelectedValue;
- if (selected != null && selected.Content!=null) {
- if (selected.Content.ToString()!=SortBy) {
- SortBy = selected.Content.ToString();
- UpdateView();
- }
- }
+ private void DoFilter(FilterData filterData) {
+ filter = filterData.SearchFor;
+ SortBy = filterData.SortBy;
+ SortWay = filterData.SortHow;
+ UpdateView();
}
- private void SortWayField_SelectionChanged(object sender, SelectionChangedEventArgs e) {
- ComboBoxItem selected = (ComboBoxItem)SortWayField.SelectedValue;
- if (selected != null && selected.Content != null) {
- if (selected.Content.ToString() != SortWay) {
- SortWay = selected.Content.ToString();
- UpdateView();
+ async private void DoConnect(object sender, MouseButtonEventArgs e) {
+ this.OnLoading?.Invoke(false);
+ DataClient client = (DataClient)Application.Current.Properties["ServiceClient"];
+ await client.IdentityOnOffAsync(_identity.Fingerprint, true);
+ if (SelectedIdentity != null) SelectedIdentity.ToggleSwitch.Enabled = true;
+ if (SelectedIdentityMenu != null) SelectedIdentityMenu.ToggleSwitch.Enabled = true;
+ _identity.IsEnabled = true;
+ IsConnected.Visibility = Visibility.Visible;
+ IsDisconnected.Visibility = Visibility.Collapsed;
+ this.OnLoading?.Invoke(true);
+ }
+
+ async private void DoDisconnect(object sender, MouseButtonEventArgs e) {
+ this.OnLoading?.Invoke(false);
+ DataClient client = (DataClient)Application.Current.Properties["ServiceClient"];
+ await client.IdentityOnOffAsync(_identity.Fingerprint, false);
+ if (SelectedIdentity != null) SelectedIdentity.ToggleSwitch.Enabled = false;
+ if (SelectedIdentityMenu != null) SelectedIdentityMenu.ToggleSwitch.Enabled = false;
+ _identity.IsEnabled = false;
+ IsConnected.Visibility = Visibility.Collapsed;
+ IsDisconnected.Visibility = Visibility.Visible;
+ this.OnLoading?.Invoke(true);
+ }
+
+ private void WarnClicked(object sender, MouseButtonEventArgs e) {
+ ZitiService item = (ZitiService)(sender as FrameworkElement).DataContext;
+ OnMessage?.Invoke(item.WarningMessage);
+ }
+
+ private void DetailsClicked(object sender, MouseButtonEventArgs e) {
+ ZitiService item = (ZitiService)(sender as FrameworkElement).DataContext;
+ ShowDetails(item);
+ }
+
+ private void VisibilityChanged(object sender, DependencyPropertyChangedEventArgs e) {
+ if (this.Visibility==Visibility.Collapsed) {
+ ServiceList.DataContext = null;
+ if (_services!=null) {
+ _services.Clear();
+ _services = null;
}
}
}
diff --git a/DesktopEdge/Views/Screens/MainMenu.xaml b/DesktopEdge/Views/Screens/MainMenu.xaml
index d3a8286a..b3c566a2 100644
--- a/DesktopEdge/Views/Screens/MainMenu.xaml
+++ b/DesktopEdge/Views/Screens/MainMenu.xaml
@@ -7,6 +7,7 @@
mc:Ignorable="d"
x:Name="MainMenuArea"
d:DesignHeight="400" d:DesignWidth="400" Margin="1,1,1,1">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DesktopEdge/Views/Screens/MainMenu.xaml.cs b/DesktopEdge/Views/Screens/MainMenu.xaml.cs
index aeb5726e..58ddab5d 100644
--- a/DesktopEdge/Views/Screens/MainMenu.xaml.cs
+++ b/DesktopEdge/Views/Screens/MainMenu.xaml.cs
@@ -1,472 +1,586 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
-using System.Diagnostics;
-using System;
-using System.Reflection;
-using System.Net.Mail;
-using System.IO;
-using NLog;
-
-using ZitiDesktopEdge.Models;
-using ZitiDesktopEdge.DataStructures;
-using ZitiDesktopEdge.ServiceClient;
-using System.Configuration;
-
-namespace ZitiDesktopEdge {
- ///
- /// Interaction logic for MainMenu.xaml
- ///
- public partial class MainMenu : UserControl {
- private static readonly Logger logger = LogManager.GetCurrentClassLogger();
-
- public delegate void AttachementChanged(bool attached);
- public event AttachementChanged OnAttachmentChange;
- public delegate void LogLevelChanged(string level);
- public event LogLevelChanged OnLogLevelChanged;
- public delegate void Detched(MouseButtonEventArgs e);
- public event Detched OnDetach;
- public string menuState = "Main";
- public string licenseData = "it's open source.";
- public string LogLevel = "";
- private string appVersion = null;
- private bool allowReleaseSelect = false;
- public double MainHeight = 500;
-
- private bool isBeta {
- get {
- return Application.Current.Properties["ReleaseStream"]?.ToString() == "beta";
- }
- }
-
- internal MainWindow MainWindow { get; set; }
-
- public MainMenu() {
- InitializeComponent();
- Application.Current.MainWindow.Title = "Ziti Desktop Edge";
-
- try {
- allowReleaseSelect = bool.Parse(ConfigurationManager.AppSettings.Get("ReleaseStreamSelect"));
- } catch {
- //if we can't parse the config - leave it as false...
- allowReleaseSelect = false; //setting it here in case anyone changes the default above
- }
-#if DEBUG
- Debug.WriteLine("OVERRIDING allowReleaseSelect to true!");
- allowReleaseSelect = true;
-#endif
- appVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
- LicensesItems.Text = licenseData;
- // don't check from the UI any more... CheckUpdates();
- }
-
- private void HideMenu(object sender, MouseButtonEventArgs e) {
- menuState = "Menu";
- UpdateState();
- MainMenuArea.Visibility = Visibility.Collapsed;
- }
- private void Window_MouseDown(object sender, MouseButtonEventArgs e) {
- if (e.ChangedButton == MouseButton.Left) {
- OnDetach(e);
- }
- }
-
- private void CloseApp(object sender, MouseButtonEventArgs e) {
- Application.Current.Shutdown();
- }
-
- private void ShowAbout(object sender, MouseButtonEventArgs e) {
- menuState = "About";
- UpdateState();
- }
-
- private void ShowAdvanced(object sender, MouseButtonEventArgs e) {
- menuState = "Advanced";
- UpdateState();
- }
- private void ShowIdentities(object sender, MouseButtonEventArgs e) {
- menuState = "Identities";
- UpdateState();
- }
- private void ShowLicenses(object sender, MouseButtonEventArgs e) {
- menuState = "Licenses";
- UpdateState();
- }
- private void ShowConfig(object sender, MouseButtonEventArgs e) {
- menuState = "Config";
- UpdateState();
- }
- private void ShowLogs(object sender, MouseButtonEventArgs e) {
- menuState = "Logs";
- UpdateState();
- }
- private void ShowUILogs(object sender, MouseButtonEventArgs e) {
- menuState = "UILogs";
- UpdateState();
- }
- private void ShowReleaseStreamMenuAction(object sender, MouseButtonEventArgs e) {
- logger.Warn("this is ShowReleaseStreamMenuAction at warn");
- logger.Info("this is ShowReleaseStreamMenuAction at info");
- logger.Debug("this is ShowReleaseStreamMenuAction at debug");
- logger.Trace("this is ShowReleaseStreamMenuAction at trace");
- menuState = "SetReleaseStream";
- UpdateState();
- }
-
- async private void SetReleaseStreamMenuAction(object sender, MouseButtonEventArgs e) {
- CheckForUpdateStatus.Visibility = Visibility.Collapsed;
- TriggerUpdateButton.Visibility = Visibility.Collapsed;
- SubOptionItem opt = (SubOptionItem)sender;
- var monitorClient = (MonitorClient)Application.Current.Properties["MonitorClient"];
- menuState = "SetReleaseStream";
-
- bool releaseClicked = opt.Label.ToLower() == "stable";
-
- if (releaseClicked) {
- if (isBeta) {
- //toggle to stable
- var r = await monitorClient.SetReleaseStreamAsync("stable");
- checkResponse(r, "Error When Setting Release Stream", "An error occurred while trying to set the release stream.");
- } else {
- logger.Debug("stable clicked but already on stable stream");
- }
- } else {
- if (!isBeta) {
- //toggle to beta
- var r = await monitorClient.SetReleaseStreamAsync("beta");
- checkResponse(r, "Error When Setting Release Stream", "An error occurred while trying to set the release stream.");
- } else {
- logger.Debug("beta clicked but already on beta stream");
- }
- }
- Application.Current.Properties["ReleaseStream"] = opt.Label.ToLower();
- UpdateState();
- }
-
- private void checkResponse(SvcResponse r, string titleOnErr, string msgOnErr) {
- if (r == null) {
- MainWindow.ShowError(titleOnErr, msgOnErr);
- } else {
- logger.Info(r?.ToString());
- }
- }
-
- private void SetLogLevel(object sender, MouseButtonEventArgs e) {
- menuState = "LogLevel";
- UpdateState();
- }
-
- private void UpdateState() {
- IdListScrollView.Height = this.ActualHeight-100.00;
- IdListScrollView.Visibility = Visibility.Collapsed;
- MainItems.Visibility = Visibility.Collapsed;
- AboutItems.Visibility = Visibility.Collapsed;
- MainItemsButton.Visibility = Visibility.Collapsed;
- AboutItemsArea.Visibility = Visibility.Collapsed;
- BackArrow.Visibility = Visibility.Collapsed;
- AdvancedItems.Visibility = Visibility.Collapsed;
- LicensesItems.Visibility = Visibility.Collapsed;
- LogsItems.Visibility = Visibility.Collapsed;
- ConfigItems.Visibility = Visibility.Collapsed;
- LogLevelItems.Visibility = Visibility.Collapsed;
- ReleaseStreamItems.Visibility = Visibility.Collapsed;
-
- if (menuState == "About") {
- MenuTitle.Content = "About";
- AboutItemsArea.Visibility = Visibility.Visible;
- AboutItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
-
- string version = "";
- try {
- TunnelStatus s = (TunnelStatus)Application.Current.Properties["CurrentTunnelStatus"];
- version = $"{s.ServiceVersion.Version}@{s.ServiceVersion.Revision}";
- } catch (Exception e) {
- logger.Warn(e, "Could not get service version/revision?");
- }
-
- // Interface Version
- VersionInfo.Content = $"App: {appVersion} Service: {version}";
-
- } else if (menuState == "Advanced") {
- MenuTitle.Content = "Advanced Settings";
- AdvancedItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
- ShowReleaseStreamMenuItem.Visibility = allowReleaseSelect ? Visibility.Visible : Visibility.Collapsed;
- } else if (menuState == "Licenses") {
- MenuTitle.Content = "Third Party Licenses";
- LicensesItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
- } else if (menuState == "Logs") {
- MenuTitle.Content = "Advanced Settings";
- AdvancedItems.Visibility = Visibility.Visible;
- //string targetFile = NativeMethods.GetFinalPathName(MainWindow.ExpectedLogPathServices);
- string targetFile = MainWindow.ExpectedLogPathServices;
-
- OpenLogFile("service", targetFile);
- BackArrow.Visibility = Visibility.Visible;
- } else if (menuState == "UILogs") {
- MenuTitle.Content = "Advanced Settings";
- AdvancedItems.Visibility = Visibility.Visible;
- OpenLogFile("UI", MainWindow.ExpectedLogPathUI);
- BackArrow.Visibility = Visibility.Visible;
- } else if (menuState == "LogLevel") {
- ResetLevels();
-
- MenuTitle.Content = "Set Log Level";
- LogLevelItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
- } else if (menuState == "SetReleaseStream") {
- SetReleaseStream();
-
- MenuTitle.Content = "Set Release Stream";
- ReleaseStreamItems.Visibility = allowReleaseSelect ? Visibility.Visible : Visibility.Collapsed;
- BackArrow.Visibility = Visibility.Visible;
- } else if (menuState == "Config") {
- MenuTitle.Content = "Tunnel Configuration";
- ConfigItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
-
- ConfigIp.Value = Application.Current.Properties["ip"]?.ToString();
- ConfigSubnet.Value = Application.Current.Properties["subnet"]?.ToString();
- ConfigMtu.Value = Application.Current.Properties["mtu"]?.ToString();
- ConfigDns.Value = (bool)Application.Current.Properties["dnsenabled"] ? Application.Current.Properties["dns"]?.ToString() : "disabled";
- } else if (menuState == "Identities") {
- MenuTitle.Content = "Identities";
- IdListScrollView.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
- } else {
- MenuTitle.Content = "Main Menu";
- MainItems.Visibility = Visibility.Visible;
- MainItemsButton.Visibility = Visibility.Visible;
- ReleaseStreamItems.Visibility = Visibility.Collapsed;
- }
- }
-
- private void OpenLogFile(string which, string logFile) {
- var whichRoot = Path.Combine(MainWindow.ExpectedLogPathRoot, which);
- try {
- string target = Native.NativeMethods.GetFinalPathName(logFile);
- if (File.Exists(target)) {
- logger.Info("opening {0} logs at: {1}", which, target);
- var p = Process.Start(new ProcessStartInfo(target) { UseShellExecute = true });
- if (p != null) {
- logger.Info("showing {0} logs. file: {1}", which, target);
- } else {
- Process.Start(whichRoot);
- }
- return;
- } else {
- logger.Warn("could not show {0} logs. file not found: {1}", which, target);
- }
- } catch {
- }
- Process.Start(whichRoot);
- }
-
- private void GoBack(object sender, MouseButtonEventArgs e) {
- if (menuState == "Config" || menuState == "LogLevel" || menuState == "UILogs" || menuState == "SetReleaseStream") {
- menuState = "Advanced";
- } else if (menuState == "Licenses") {
- menuState = "About";
- } else {
- menuState = "Menu";
- }
- UpdateState();
- }
- private void ShowPrivacy(object sender, MouseButtonEventArgs e) {
- Process.Start(new ProcessStartInfo("https://netfoundry.io/privacy") { UseShellExecute = true });
- }
- private void ShowTerms(object sender, MouseButtonEventArgs e) {
- Process.Start(new ProcessStartInfo("https://netfoundry.io/terms") { UseShellExecute = true });
- }
-
- async private void ShowFeedback(object sender, MouseButtonEventArgs e) {
- try {
- MainWindow.ShowLoad("Collecting Information", "Please wait while we run some commands\nand collect some diagnostic information");
- var mailMessage = new MailMessage("help@openziti.org", "help@openziti.org");
- mailMessage.Subject = "Ziti Support";
- mailMessage.IsBodyHtml = false;
- System.Text.StringBuilder sb = new System.Text.StringBuilder();
- sb.Append("Logs collected at : " + DateTime.Now.ToString());
- sb.Append(". client version : " + appVersion);
-
- mailMessage.Body = sb.ToString();
-
- string timestamp = DateTime.Now.ToFileTime().ToString();
-
- var dataClient = (DataClient)Application.Current.Properties["ServiceClient"];
- await dataClient.zitiDump();
-
- var monitorClient = (MonitorClient)Application.Current.Properties["MonitorClient"];
- MonitorServiceStatusEvent resp = await monitorClient.CaptureLogsAsync();
- if (resp == null) {
- logger.Error("no response from monitorClient?");
- MainWindow mw = (MainWindow)Application.Current.MainWindow;
- mw?.ShowError("Error Collecting Feedback", "An error occurred while trying to gather feedback.\nIs the monitor service running?");
- return;
- }
- string pathToLogs = resp.Message;
- logger.Info("Log files found at : {0}", resp.Message);
- mailMessage.Attachments.Add(new Attachment(pathToLogs));
-
- string emlFile = Path.Combine(Path.GetTempPath(), timestamp + "-ziti.eml");
-
- using (var filestream = File.Open(emlFile, FileMode.Create)) {
- var binaryWriter = new BinaryWriter(filestream);
- binaryWriter.Write(System.Text.Encoding.UTF8.GetBytes("X-Unsent: 1" + Environment.NewLine));
- var assembly = typeof(SmtpClient).Assembly;
- var mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
- var mailWriterContructor = mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(Stream) }, null);
- var mailWriter = mailWriterContructor.Invoke(new object[] { filestream });
- var sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);
- sendMethod.Invoke(mailMessage, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { mailWriter, true, true }, null);
- var closeMethod = mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
- closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null);
- }
- var p = Process.Start(emlFile);
- if (p != null) {
- p.Exited += (object lambdaSender, EventArgs lambdaEventArgs) => {
- logger.Info("Removing temp file: {0}", emlFile);
- File.Delete(emlFile);
- };
- p.EnableRaisingEvents = true;
- } else {
- logger.Debug("process was null. most likely the email file format was not known when the process tried to start");
- }
- } catch (Exception ex) {
- logger.Warn(ex, "An unexpected error has occurred when submitting feedback? {0}", ex.Message);
- }
- MainWindow.HideLoad();
- }
-
- private void ShowSupport(object sender, MouseButtonEventArgs e) {
- Process.Start(new ProcessStartInfo("https://openziti.discourse.group/") { UseShellExecute = true });
- }
-
- private void DetachWindow(object sender, MouseButtonEventArgs e) {
- Application.Current.MainWindow.ShowInTaskbar = true;
- DetachButton.Visibility = Visibility.Collapsed;
- AttachButton.Visibility = Visibility.Visible;
- Arrow.Visibility = Visibility.Collapsed;
- if (OnAttachmentChange != null) {
- OnAttachmentChange(false);
- }
- MainMenuArea.Visibility = Visibility.Collapsed;
- }
-
- public void Detach() {
- Application.Current.MainWindow.ShowInTaskbar = true;
- DetachButton.Visibility = Visibility.Collapsed;
- AttachButton.Visibility = Visibility.Visible;
- Arrow.Visibility = Visibility.Collapsed;
- }
- private void RetachWindow(object sender, MouseButtonEventArgs e) {
- Application.Current.MainWindow.ShowInTaskbar = false;
- DetachButton.Visibility = Visibility.Visible;
- AttachButton.Visibility = Visibility.Collapsed;
- Arrow.Visibility = Visibility.Visible;
- if (OnAttachmentChange != null) {
- OnAttachmentChange(true);
- }
- }
-
- private void ResetLevels() {
- if (this.LogLevel == "") this.LogLevel = "error";
- LogVerbose.IsSelected = false;
- LogDebug.IsSelected = false;
- LogInfo.IsSelected = false;
- LogError.IsSelected = false;
- LogFatal.IsSelected = false;
- LogWarn.IsSelected = false;
- LogTrace.IsSelected = false;
- if (this.LogLevel == "verbose") LogVerbose.IsSelected = true;
- else if (this.LogLevel == "debug") LogDebug.IsSelected = true;
- else if (this.LogLevel == "info") LogInfo.IsSelected = true;
- else if (this.LogLevel == "error") LogError.IsSelected = true;
- else if (this.LogLevel == "fatal") LogFatal.IsSelected = true;
- else if (this.LogLevel == "warn") LogWarn.IsSelected = true;
- else if (this.LogLevel == "trace") LogTrace.IsSelected = true;
- }
-
- private void SetLevel(object sender, MouseButtonEventArgs e) {
- SubOptionItem item = (SubOptionItem)sender;
- this.LogLevel = item.Label.ToLower();
- if (OnLogLevelChanged != null) {
- OnLogLevelChanged(this.LogLevel);
- }
- ResetLevels();
- }
-
- private void SetReleaseStream() {
- this.ReleaseStreamItemBeta.IsSelected = isBeta;
- this.ReleaseStreamItemStable.IsSelected = !isBeta;
- }
-
- async private void CheckForUpdate_Click(object sender, RoutedEventArgs e) {
- logger.Info("checking for update...");
- try {
- CheckForUpdate.IsEnabled = false;
- CheckForUpdateStatus.Content = "Checking for update...";
- CheckForUpdateStatus.Visibility = Visibility.Visible;
- var monitorClient = (MonitorClient)Application.Current.Properties["MonitorClient"];
- var r = await monitorClient.DoUpdateCheck();
- checkResponse(r, "Error When Checking for Update", "An error occurred while trying check for update.");
- CheckForUpdateStatus.Content = r.Message;
- if (r.UpdateAvailable) {
- TriggerUpdateButton.Visibility = Visibility.Visible;
- } else {
- TriggerUpdateButton.Visibility = Visibility.Collapsed;
- }
- } catch (Exception ex) {
- logger.Error(ex, "unexpected error in update check: {0}", ex.Message);
- }
- CheckForUpdate.IsEnabled = true;
- }
-
- async private void TriggerUpdate_Click(object sender, RoutedEventArgs e) {
- try {
- CheckForUpdate.IsEnabled = false;
- TriggerUpdateButton.IsEnabled = false;
- CheckForUpdateStatus.Content = "Requesting automatic update...";
- var monitorClient = (MonitorClient)Application.Current.Properties["MonitorClient"];
- var r = await monitorClient.TriggerUpdate();
- CheckForUpdateStatus.Content = "Automatic update requested...";
- checkResponse(r, "Error When Triggering Update", "An error occurred while trying to trigger the update.");
- } catch (Exception ex) {
- logger.Error(ex, "unexpected error in update check: {0}", ex.Message);
- }
- TriggerUpdateButton.IsEnabled = true;
- CheckForUpdate.IsEnabled = true;
- }
-
- public void SetupIdList(ZitiIdentity[] ids) {
- IdListView.Children.Clear();
- for (int i=0; i {
- VersionOlder.Content = msg;
- VersionNewer.Content = "";
- VersionOlder.Visibility = Visibility.Visible;
- VersionNewer.Visibility = Visibility.Collapsed;
- });
- }
- public void SetAppIsNewer(string msg) {
- this.Dispatcher.Invoke(() => {
- VersionNewer.Content = msg;
- VersionOlder.Content = "";
- VersionNewer.Visibility = Visibility.Visible;
- VersionOlder.Visibility = Visibility.Collapsed;
- });
- }
- }
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Diagnostics;
+using System;
+using System.Reflection;
+using System.Net.Mail;
+using System.IO;
+using NLog;
+using System.Windows.Media.Animation;
+
+using ZitiDesktopEdge.Models;
+using ZitiDesktopEdge.DataStructures;
+using ZitiDesktopEdge.ServiceClient;
+using System.Configuration;
+
+namespace ZitiDesktopEdge {
+ ///
+ /// Interaction logic for MainMenu.xaml
+ ///
+ public partial class MainMenu : UserControl {
+ private static readonly Logger logger = LogManager.GetCurrentClassLogger();
+
+ public delegate void AttachementChanged(bool attached);
+ public event AttachementChanged OnAttachmentChange;
+ public delegate void LogLevelChanged(string level);
+ public event LogLevelChanged OnLogLevelChanged;
+ public delegate void Detched(MouseButtonEventArgs e);
+ public event Detched OnDetach;
+ public delegate void ShowBlurb(string message);
+ public event ShowBlurb OnShowBlurb;
+ public string menuState = "Main";
+ public string licenseData = "it's open source.";
+ public string LogLevel = "";
+ private string appVersion = null;
+ private bool allowReleaseSelect = false;
+ public double MainHeight = 500;
+
+ private bool isBeta {
+ get {
+ return Application.Current.Properties["ReleaseStream"]?.ToString() == "beta";
+ }
+ }
+
+ internal MainWindow MainWindow { get; set; }
+
+ public MainMenu() {
+ InitializeComponent();
+ Application.Current.MainWindow.Title = "Ziti Desktop Edge";
+
+ try {
+ allowReleaseSelect = bool.Parse(ConfigurationManager.AppSettings.Get("ReleaseStreamSelect"));
+ } catch {
+ //if we can't parse the config - leave it as false...
+ allowReleaseSelect = false; //setting it here in case anyone changes the default above
+ }
+#if DEBUG
+ Debug.WriteLine("OVERRIDING allowReleaseSelect to true!");
+ allowReleaseSelect = true;
+#endif
+ appVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
+ LicensesItems.Text = licenseData;
+ // don't check from the UI any more... CheckUpdates();
+ }
+
+ private void HideMenu(object sender, MouseButtonEventArgs e) {
+ menuState = "Menu";
+ UpdateState();
+ MainMenuArea.Visibility = Visibility.Collapsed;
+ }
+ private void Window_MouseDown(object sender, MouseButtonEventArgs e) {
+ if (e.ChangedButton == MouseButton.Left) {
+ OnDetach(e);
+ }
+ }
+
+ private void CloseApp(object sender, MouseButtonEventArgs e) {
+ Application.Current.Shutdown();
+ }
+
+ private void ShowAbout(object sender, MouseButtonEventArgs e) {
+ menuState = "About";
+ UpdateState();
+ }
+
+ private void ShowAdvanced(object sender, MouseButtonEventArgs e) {
+ menuState = "Advanced";
+ UpdateState();
+ }
+ private void ShowIdentities(object sender, MouseButtonEventArgs e) {
+ menuState = "Identities";
+ UpdateState();
+ }
+ private void ShowLicenses(object sender, MouseButtonEventArgs e) {
+ menuState = "Licenses";
+ UpdateState();
+ }
+ private void ShowConfig(object sender, MouseButtonEventArgs e) {
+ menuState = "Config";
+ UpdateState();
+ }
+ private void ShowLogs(object sender, MouseButtonEventArgs e) {
+ menuState = "Logs";
+ UpdateState();
+ }
+ private void ShowUILogs(object sender, MouseButtonEventArgs e) {
+ menuState = "UILogs";
+ UpdateState();
+ }
+ private void ShowReleaseStreamMenuAction(object sender, MouseButtonEventArgs e) {
+ logger.Warn("this is ShowReleaseStreamMenuAction at warn");
+ logger.Info("this is ShowReleaseStreamMenuAction at info");
+ logger.Debug("this is ShowReleaseStreamMenuAction at debug");
+ logger.Trace("this is ShowReleaseStreamMenuAction at trace");
+ menuState = "SetReleaseStream";
+ UpdateState();
+ }
+
+ async private void SetReleaseStreamMenuAction(object sender, MouseButtonEventArgs e) {
+ CheckForUpdateStatus.Visibility = Visibility.Collapsed;
+ TriggerUpdateButton.Visibility = Visibility.Collapsed;
+ SubOptionItem opt = (SubOptionItem)sender;
+ var monitorClient = (MonitorClient)Application.Current.Properties["MonitorClient"];
+ menuState = "SetReleaseStream";
+
+ bool releaseClicked = opt.Label.ToLower() == "stable";
+
+ if (releaseClicked) {
+ if (isBeta) {
+ //toggle to stable
+ var r = await monitorClient.SetReleaseStreamAsync("stable");
+ checkResponse(r, "Error When Setting Release Stream", "An error occurred while trying to set the release stream.");
+ } else {
+ logger.Debug("stable clicked but already on stable stream");
+ }
+ } else {
+ if (!isBeta) {
+ //toggle to beta
+ var r = await monitorClient.SetReleaseStreamAsync("beta");
+ checkResponse(r, "Error When Setting Release Stream", "An error occurred while trying to set the release stream.");
+ } else {
+ logger.Debug("beta clicked but already on beta stream");
+ }
+ }
+ Application.Current.Properties["ReleaseStream"] = opt.Label.ToLower();
+ UpdateState();
+ }
+
+ private void checkResponse(SvcResponse r, string titleOnErr, string msgOnErr) {
+ if (r == null) {
+ MainWindow.ShowError(titleOnErr, msgOnErr);
+ } else {
+ logger.Info(r?.ToString());
+ }
+ }
+
+ private void SetLogLevel(object sender, MouseButtonEventArgs e) {
+ menuState = "LogLevel";
+ UpdateState();
+ }
+
+ private void UpdateState() {
+ IdListScrollView.Height = this.ActualHeight-100.00;
+ IdListScrollView.Visibility = Visibility.Collapsed;
+ MainItems.Visibility = Visibility.Collapsed;
+ AboutItems.Visibility = Visibility.Collapsed;
+ MainItemsButton.Visibility = Visibility.Collapsed;
+ AboutItemsArea.Visibility = Visibility.Collapsed;
+ BackArrow.Visibility = Visibility.Collapsed;
+ AdvancedItems.Visibility = Visibility.Collapsed;
+ LicensesItems.Visibility = Visibility.Collapsed;
+ LogsItems.Visibility = Visibility.Collapsed;
+ ConfigItems.Visibility = Visibility.Collapsed;
+ LogLevelItems.Visibility = Visibility.Collapsed;
+ ReleaseStreamItems.Visibility = Visibility.Collapsed;
+
+ if (menuState == "About") {
+ MenuTitle.Content = "About";
+ AboutItemsArea.Visibility = Visibility.Visible;
+ AboutItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+
+ string version = "";
+ try {
+ TunnelStatus s = (TunnelStatus)Application.Current.Properties["CurrentTunnelStatus"];
+ version = $"{s.ServiceVersion.Version}@{s.ServiceVersion.Revision}";
+ } catch (Exception e) {
+ logger.Warn(e, "Could not get service version/revision?");
+ }
+
+ // Interface Version
+ VersionInfo.Content = $"App: {appVersion} Service: {version}";
+
+ } else if (menuState == "Advanced") {
+ MenuTitle.Content = "Advanced Settings";
+ AdvancedItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+ ShowReleaseStreamMenuItem.Visibility = allowReleaseSelect ? Visibility.Visible : Visibility.Collapsed;
+ } else if (menuState == "Licenses") {
+ MenuTitle.Content = "Third Party Licenses";
+ LicensesItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+ } else if (menuState == "Logs") {
+ MenuTitle.Content = "Advanced Settings";
+ AdvancedItems.Visibility = Visibility.Visible;
+ //string targetFile = NativeMethods.GetFinalPathName(MainWindow.ExpectedLogPathServices);
+ string targetFile = MainWindow.ExpectedLogPathServices;
+
+ OpenLogFile("service", targetFile);
+ BackArrow.Visibility = Visibility.Visible;
+ } else if (menuState == "UILogs") {
+ MenuTitle.Content = "Advanced Settings";
+ AdvancedItems.Visibility = Visibility.Visible;
+ OpenLogFile("UI", MainWindow.ExpectedLogPathUI);
+ BackArrow.Visibility = Visibility.Visible;
+ } else if (menuState == "LogLevel") {
+ ResetLevels();
+
+ MenuTitle.Content = "Set Log Level";
+ LogLevelItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+ } else if (menuState == "SetReleaseStream") {
+ SetReleaseStream();
+
+ MenuTitle.Content = "Set Release Stream";
+ ReleaseStreamItems.Visibility = allowReleaseSelect ? Visibility.Visible : Visibility.Collapsed;
+ BackArrow.Visibility = Visibility.Visible;
+ } else if (menuState == "Config") {
+ MenuTitle.Content = "Tunnel Configuration";
+ ConfigItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+
+ ConfigIp.Value = Application.Current.Properties["ip"]?.ToString();
+ ConfigSubnet.Value = Application.Current.Properties["subnet"]?.ToString();
+ ConfigMtu.Value = Application.Current.Properties["mtu"]?.ToString();
+ ConfigDns.Value = (bool)Application.Current.Properties["dnsenabled"] ? Application.Current.Properties["dns"]?.ToString() : "disabled";
+ } else if (menuState == "Identities") {
+ MenuTitle.Content = "Identities";
+ IdListScrollView.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+ } else {
+ MenuTitle.Content = "Main Menu";
+ MainItems.Visibility = Visibility.Visible;
+ MainItemsButton.Visibility = Visibility.Visible;
+ ReleaseStreamItems.Visibility = Visibility.Collapsed;
+ }
+ }
+
+ private void OpenLogFile(string which, string logFile) {
+ var whichRoot = Path.Combine(MainWindow.ExpectedLogPathRoot, which);
+ try {
+ string target = Native.NativeMethods.GetFinalPathName(logFile);
+ if (File.Exists(target)) {
+ logger.Info("opening {0} logs at: {1}", which, target);
+ var p = Process.Start(new ProcessStartInfo(target) { UseShellExecute = true });
+ if (p != null) {
+ logger.Info("showing {0} logs. file: {1}", which, target);
+ } else {
+ Process.Start(whichRoot);
+ }
+ return;
+ } else {
+ logger.Warn("could not show {0} logs. file not found: {1}", which, target);
+ }
+ } catch {
+ }
+ Process.Start(whichRoot);
+ }
+
+ private void GoBack(object sender, MouseButtonEventArgs e) {
+ if (menuState == "Config" || menuState == "LogLevel" || menuState == "UILogs" || menuState == "SetReleaseStream") {
+ menuState = "Advanced";
+ } else if (menuState == "Licenses") {
+ menuState = "About";
+ } else {
+ menuState = "Menu";
+ }
+ UpdateState();
+ }
+ private void ShowPrivacy(object sender, MouseButtonEventArgs e) {
+ Process.Start(new ProcessStartInfo("https://netfoundry.io/privacy") { UseShellExecute = true });
+ }
+ private void ShowTerms(object sender, MouseButtonEventArgs e) {
+ Process.Start(new ProcessStartInfo("https://netfoundry.io/terms") { UseShellExecute = true });
+ }
+
+ async private void ShowFeedback(object sender, MouseButtonEventArgs e) {
+ try {
+ MainWindow.ShowLoad("Collecting Information", "Please wait while we run some commands\nand collect some diagnostic information");
+ var mailMessage = new MailMessage("help@openziti.org", "help@openziti.org");
+ mailMessage.Subject = "Ziti Support";
+ mailMessage.IsBodyHtml = false;
+ System.Text.StringBuilder sb = new System.Text.StringBuilder();
+ sb.Append("Logs collected at : " + DateTime.Now.ToString());
+ sb.Append(". client version : " + appVersion);
+
+ mailMessage.Body = sb.ToString();
+
+ string timestamp = DateTime.Now.ToFileTime().ToString();
+
+ var dataClient = (DataClient)Application.Current.Properties["ServiceClient"];
+ await dataClient.zitiDump();
+
+ var monitorClient = (MonitorClient)Application.Current.Properties["MonitorClient"];
+ MonitorServiceStatusEvent resp = await monitorClient.CaptureLogsAsync();
+ if (resp == null) {
+ logger.Error("no response from monitorClient?");
+ MainWindow mw = (MainWindow)Application.Current.MainWindow;
+ mw?.ShowError("Error Collecting Feedback", "An error occurred while trying to gather feedback.\nIs the monitor service running?");
+ return;
+ }
+ string pathToLogs = resp.Message;
+ logger.Info("Log files found at : {0}", resp.Message);
+ mailMessage.Attachments.Add(new Attachment(pathToLogs));
+
+ string emlFile = Path.Combine(Path.GetTempPath(), timestamp + "-ziti.eml");
+
+ using (var filestream = File.Open(emlFile, FileMode.Create)) {
+ var binaryWriter = new BinaryWriter(filestream);
+ binaryWriter.Write(System.Text.Encoding.UTF8.GetBytes("X-Unsent: 1" + Environment.NewLine));
+ var assembly = typeof(SmtpClient).Assembly;
+ var mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
+ var mailWriterContructor = mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(Stream) }, null);
+ var mailWriter = mailWriterContructor.Invoke(new object[] { filestream });
+ var sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);
+ sendMethod.Invoke(mailMessage, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { mailWriter, true, true }, null);
+ var closeMethod = mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
+ closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null);
+ }
+ var p = Process.Start(emlFile);
+ if (p != null) {
+ p.Exited += (object lambdaSender, EventArgs lambdaEventArgs) => {
+ logger.Info("Removing temp file: {0}", emlFile);
+ File.Delete(emlFile);
+ };
+ p.EnableRaisingEvents = true;
+ } else {
+ logger.Debug("process was null. most likely the email file format was not known when the process tried to start");
+ }
+ } catch (Exception ex) {
+ logger.Warn(ex, "An unexpected error has occurred when submitting feedback? {0}", ex.Message);
+ }
+ MainWindow.HideLoad();
+ }
+
+ private void ShowSupport(object sender, MouseButtonEventArgs e) {
+ Process.Start(new ProcessStartInfo("https://openziti.discourse.group/") { UseShellExecute = true });
+ }
+
+ private void DetachWindow(object sender, MouseButtonEventArgs e) {
+ Application.Current.MainWindow.ShowInTaskbar = true;
+ DetachButton.Visibility = Visibility.Collapsed;
+ AttachButton.Visibility = Visibility.Visible;
+ Arrow.Visibility = Visibility.Collapsed;
+ if (OnAttachmentChange != null) {
+ OnAttachmentChange(false);
+ }
+ MainMenuArea.Visibility = Visibility.Collapsed;
+ }
+
+ public void Detach() {
+ Application.Current.MainWindow.ShowInTaskbar = true;
+ DetachButton.Visibility = Visibility.Collapsed;
+ AttachButton.Visibility = Visibility.Visible;
+ Arrow.Visibility = Visibility.Collapsed;
+ }
+ private void RetachWindow(object sender, MouseButtonEventArgs e) {
+ Application.Current.MainWindow.ShowInTaskbar = false;
+ DetachButton.Visibility = Visibility.Visible;
+ AttachButton.Visibility = Visibility.Collapsed;
+ Arrow.Visibility = Visibility.Visible;
+ if (OnAttachmentChange != null) {
+ OnAttachmentChange(true);
+ }
+ }
+
+ private void ResetLevels() {
+ if (this.LogLevel == "") this.LogLevel = "error";
+ LogVerbose.IsSelected = false;
+ LogDebug.IsSelected = false;
+ LogInfo.IsSelected = false;
+ LogError.IsSelected = false;
+ LogFatal.IsSelected = false;
+ LogWarn.IsSelected = false;
+ LogTrace.IsSelected = false;
+ if (this.LogLevel == "verbose") LogVerbose.IsSelected = true;
+ else if (this.LogLevel == "debug") LogDebug.IsSelected = true;
+ else if (this.LogLevel == "info") LogInfo.IsSelected = true;
+ else if (this.LogLevel == "error") LogError.IsSelected = true;
+ else if (this.LogLevel == "fatal") LogFatal.IsSelected = true;
+ else if (this.LogLevel == "warn") LogWarn.IsSelected = true;
+ else if (this.LogLevel == "trace") LogTrace.IsSelected = true;
+ }
+
+ private void SetLevel(object sender, MouseButtonEventArgs e) {
+ SubOptionItem item = (SubOptionItem)sender;
+ this.LogLevel = item.Label.ToLower();
+ if (OnLogLevelChanged != null) {
+ OnLogLevelChanged(this.LogLevel);
+ }
+ ResetLevels();
+ }
+
+ private void SetReleaseStream() {
+ this.ReleaseStreamItemBeta.IsSelected = isBeta;
+ this.ReleaseStreamItemStable.IsSelected = !isBeta;
+ }
+
+ async private void CheckForUpdate_Click(object sender, RoutedEventArgs e) {
+ logger.Info("checking for update...");
+ try {
+ CheckForUpdate.IsEnabled = false;
+ CheckForUpdateStatus.Content = "Checking for update...";
+ CheckForUpdateStatus.Visibility = Visibility.Visible;
+ var monitorClient = (MonitorClient)Application.Current.Properties["MonitorClient"];
+ var r = await monitorClient.DoUpdateCheck();
+ checkResponse(r, "Error When Checking for Update", "An error occurred while trying check for update.");
+ CheckForUpdateStatus.Content = r.Message;
+ if (r.UpdateAvailable) {
+ TriggerUpdateButton.Visibility = Visibility.Visible;
+ } else {
+ TriggerUpdateButton.Visibility = Visibility.Collapsed;
+ }
+ } catch (Exception ex) {
+ logger.Error(ex, "unexpected error in update check: {0}", ex.Message);
+ }
+ CheckForUpdate.IsEnabled = true;
+ }
+
+ async public void TriggerUpdate_Click(object sender, RoutedEventArgs e) {
+ try {
+ CheckForUpdate.IsEnabled = false;
+ TriggerUpdateButton.IsEnabled = false;
+ CheckForUpdateStatus.Content = "Requesting automatic update...";
+ var monitorClient = (MonitorClient)Application.Current.Properties["MonitorClient"];
+ var r = await monitorClient.TriggerUpdate();
+ CheckForUpdateStatus.Content = "Automatic update requested...";
+ checkResponse(r, "Error When Triggering Update", "An error occurred while trying to trigger the update.");
+ } catch (Exception ex) {
+ logger.Error(ex, "unexpected error in update check: {0}", ex.Message);
+ }
+ TriggerUpdateButton.IsEnabled = true;
+ CheckForUpdate.IsEnabled = true;
+ }
+
+ public void SetupIdList(ZitiIdentity[] ids) {
+ IdListView.Children.Clear();
+ for (int i=0; i {
+ VersionOlder.Content = msg;
+ VersionNewer.Content = "";
+ VersionOlder.Visibility = Visibility.Visible;
+ VersionNewer.Visibility = Visibility.Collapsed;
+ });
+ }
+ public void SetAppIsNewer(string msg) {
+ this.Dispatcher.Invoke(() => {
+ VersionNewer.Content = msg;
+ VersionOlder.Content = "";
+ VersionNewer.Visibility = Visibility.Visible;
+ VersionOlder.Visibility = Visibility.Collapsed;
+ });
+ }
+
+ ///
+ /// Save the config information to the properties and queue for update.
+ ///
+ async private void UpdateConfig() {
+ logger.Info("updating config...");
+ DataClient client = (DataClient)Application.Current.Properties["ServiceClient"];
+ try {
+ ComboBoxItem item = (ComboBoxItem)ConfigMaskNew.SelectedValue;
+ var newMaskVar = Int32.Parse(item.Tag.ToString());
+ var addDnsNewVar = Convert.ToBoolean(AddDnsNew.IsChecked);
+
+ var r = await client.UpdateConfigAsync(ConfigIpNew.Text, newMaskVar, addDnsNewVar);
+ if (r.Code != 0) {
+ this.OnShowBlurb?.Invoke("Error: " + r.Error);
+ logger.Debug("ERROR: {0} : {1}", r.Message, r.Error);
+ } else {
+ this.OnShowBlurb?.Invoke("Config Save, Please Restart Ziti to Update");
+ this.CloseEdit();
+ }
+ logger.Info("Got response from update config task : {0}", r);
+ } catch (DataStructures.ServiceException se) {
+ this.OnShowBlurb?.Invoke("Error: " + se.Message);
+ logger.Error(se, "service exception in update check: {0}", se.Message);
+ } catch (Exception ex) {
+ this.OnShowBlurb?.Invoke("Error: " + ex.Message);
+ logger.Error(ex, "unexpected error in update check: {0}", ex.Message);
+ }
+ }
+
+ ///
+ /// Show the Edit Modal and blur the background
+ ///
+ private void ShowEdit() {
+ ConfigIpNew.Text = ConfigIp.Value;
+ for (int i=0; i0) {
+ ConfigMaskNew.SelectedIndex = i;
+ break;
+ }
+ }
+ EditArea.Opacity = 0;
+ EditArea.Visibility = Visibility.Visible;
+ EditArea.Margin = new Thickness(0, 0, 0, 0);
+ EditArea.BeginAnimation(Grid.OpacityProperty, new DoubleAnimation(1, TimeSpan.FromSeconds(.3)));
+ EditArea.BeginAnimation(Grid.MarginProperty, new ThicknessAnimation(new Thickness(30, 30, 30, 30), TimeSpan.FromSeconds(.3)));
+ ShowModal();
+ }
+
+ ///
+ /// Hide the Edit Config
+ ///
+ private void CloseEdit() {
+ DoubleAnimation animation = new DoubleAnimation(0, TimeSpan.FromSeconds(.3));
+ ThicknessAnimation animateThick = new ThicknessAnimation(new Thickness(0, 0, 0, 0), TimeSpan.FromSeconds(.3));
+ animation.Completed += CloseComplete;
+ EditArea.BeginAnimation(Grid.OpacityProperty, animation);
+ EditArea.BeginAnimation(Grid.MarginProperty, animateThick);
+ HideModal();
+ }
+
+ ///
+ /// Show the modal, aniimating opacity
+ ///
+ private void ShowModal() {
+ ModalBg.Visibility = Visibility.Visible;
+ ModalBg.Opacity = 0;
+ DoubleAnimation animation = new DoubleAnimation(.8, TimeSpan.FromSeconds(.3));
+ ModalBg.BeginAnimation(Grid.OpacityProperty, animation);
+ }
+
+ ///
+ /// Close the config window
+ ///
+ /// The close button
+ /// The event arguments
+ private void CloseComplete(object sender, EventArgs e) {
+ EditArea.Visibility = Visibility.Collapsed;
+ }
+
+ ///
+ /// Hide the modal animating the opacity
+ ///
+ private void HideModal() {
+ DoubleAnimation animation = new DoubleAnimation(0, TimeSpan.FromSeconds(.3));
+ animation.Completed += ModalHideComplete;
+ ModalBg.BeginAnimation(Grid.OpacityProperty, animation);
+ }
+
+ ///
+ /// When the animation completes, set the visibility to avoid UI object conflicts
+ ///
+ /// The animation
+ /// The event
+ private void ModalHideComplete(object sender, EventArgs e) {
+ ModalBg.Visibility = Visibility.Collapsed;
+ }
+
+ ///
+ /// Close the config editor without saving
+ ///
+ /// The image button
+ /// The click event
+ private void CloseEditConfig(object sender, MouseButtonEventArgs e) {
+ CloseEdit();
+ }
+
+ private void SaveConfig() {
+ this.UpdateConfig();
+ }
+ }
}
\ No newline at end of file
diff --git a/DesktopEdge/ZitiDesktopEdge.csproj b/DesktopEdge/ZitiDesktopEdge.csproj
index b406e57b..a6ef0dc4 100644
--- a/DesktopEdge/ZitiDesktopEdge.csproj
+++ b/DesktopEdge/ZitiDesktopEdge.csproj
@@ -143,11 +143,15 @@
MSBuild:Compile
Designer
+
StyledButton.xaml
+
+ Filter.xaml
+
MenuEditSearch.xaml
@@ -197,6 +201,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
MSBuild:Compile
Designer
@@ -447,5 +455,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Installer/ZitiDesktopEdge.aip b/Installer/ZitiDesktopEdge.aip
index fff0961b..9da73f34 100644
--- a/Installer/ZitiDesktopEdge.aip
+++ b/Installer/ZitiDesktopEdge.aip
@@ -23,10 +23,10 @@
-
+
-
+
diff --git a/ZitiDesktopEdge.Client/DataStructures/DataStructures.cs b/ZitiDesktopEdge.Client/DataStructures/DataStructures.cs
index c64191bc..5936e0c0 100644
--- a/ZitiDesktopEdge.Client/DataStructures/DataStructures.cs
+++ b/ZitiDesktopEdge.Client/DataStructures/DataStructures.cs
@@ -459,4 +459,27 @@ namespace ZitiDesktopEdge.DataStructures {
public class MfaRecoveryCodesResponse : SvcResponse {
public string[] Payload { get; set; }
}
+
+ public class ConfigPayload
+ {
+ public string TunIPv4 { get; set; }
+ public int TunIPv4Mask { get; set; }
+ public bool AddDns { get; set; }
+ }
+
+ public class ConfigUpdateFunction : ServiceFunction
+ {
+ public ConfigUpdateFunction(string tunIPv4, int tunIPv4Mask, bool addDns)
+ {
+ this.Function = "UpdateTunIpv4";
+ this.Payload = new ConfigPayload()
+ {
+ TunIPv4 = tunIPv4,
+ TunIPv4Mask = tunIPv4Mask,
+ AddDns = addDns
+ };
+ }
+ public ConfigPayload Payload { get; set; }
+ }
+
}
diff --git a/ZitiDesktopEdge.Client/ServiceClient/DataClient.cs b/ZitiDesktopEdge.Client/ServiceClient/DataClient.cs
index af87b68d..cc1f0695 100644
--- a/ZitiDesktopEdge.Client/ServiceClient/DataClient.cs
+++ b/ZitiDesktopEdge.Client/ServiceClient/DataClient.cs
@@ -390,6 +390,30 @@ namespace ZitiDesktopEdge.ServiceClient {
return;
}
+ async public Task UpdateConfigAsync(string tunIPv4, int tunIPv4Mask, bool addDns) {
+ SvcResponse resp = null;
+ try {
+
+ ConfigUpdateFunction configPayload = new ConfigUpdateFunction(tunIPv4, tunIPv4Mask, addDns);
+
+ await sendAsync(configPayload);
+ resp = await readAsync(ipcReader);
+ Logger.Debug("config update payload is sent to the ziti tunnel");
+ } catch (Exception ex) {
+ //almost certainly a problem with the pipe - recreate the pipe...
+ //setupPipe();
+ //throw;
+ Logger.Error(ex, "Unexpected error");
+ CommunicationError(ex);
+ throw ex;
+ }
+ if (resp?.Code != 0) {
+ Logger.Warn("failed to update the config. {0} {1}", resp.Message, resp.Error);
+ throw new ServiceException("Failed to update the config", resp.Code, "Un expected error.");
+ }
+ return resp;
+ }
+
async public Task debugAsync() {
try {
await sendAsync(new ServiceFunction() { Function = "Debug" });
diff --git a/ZitiUpdateService/Properties/AssemblyInfo.cs b/ZitiUpdateService/Properties/AssemblyInfo.cs
index 6c15d9ab..7b16007f 100644
--- a/ZitiUpdateService/Properties/AssemblyInfo.cs
+++ b/ZitiUpdateService/Properties/AssemblyInfo.cs
@@ -30,6 +30,6 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.9.3.0")]
-[assembly: AssemblyVersion("1.9.3.0")]
-[assembly: AssemblyFileVersion("1.9.3.0")]
+// [assembly: AssemblyVersion("1.9.4.0")]
+[assembly: AssemblyVersion("1.9.4.0")]
+[assembly: AssemblyFileVersion("1.9.4.0")]
diff --git a/ZitiUpdateService/UpdateService.cs b/ZitiUpdateService/UpdateService.cs
index 57fdf030..529ae040 100644
--- a/ZitiUpdateService/UpdateService.cs
+++ b/ZitiUpdateService/UpdateService.cs
@@ -214,7 +214,7 @@ namespace ZitiUpdateService {
}
return zipName;
} catch (Exception ex) {
- Logger.Error(ex, "Unexpected error {0}", ex.Message);
+ Logger.Error(ex, "Unexpected error in generating system files {0}", ex.Message);
return null;
}
}
@@ -233,7 +233,7 @@ namespace ZitiUpdateService {
process.Start();
process.WaitForExit();
} catch (Exception ex) {
- Logger.Error(ex, "Unexpected error {0}", ex.Message);
+ Logger.Error(ex, "Unexpected error in outputIpconfigInfo {0}", ex.Message);
}
}
@@ -251,7 +251,7 @@ namespace ZitiUpdateService {
process.Start();
process.WaitForExit();
} catch (Exception ex) {
- Logger.Error(ex, "Unexpected error {0}", ex.Message);
+ Logger.Error(ex, "Unexpected error in outputSystemInfo {0}", ex.Message);
}
}
@@ -269,7 +269,7 @@ namespace ZitiUpdateService {
process.Start();
process.WaitForExit();
} catch (Exception ex) {
- Logger.Error(ex, "Unexpected error {0}", ex.Message);
+ Logger.Error(ex, "Unexpected error in outputDnsCache {0}", ex.Message);
}
}
@@ -283,7 +283,7 @@ namespace ZitiUpdateService {
string responseBody = resp.Content.ReadAsStringAsync().Result;
File.WriteAllText(extIpFile, responseBody);
} catch (Exception ex) {
- Logger.Error(ex, "Unexpected error {0}", ex.Message);
+ Logger.Error(ex, "Unexpected error in outputExternalIP {0}", ex.Message);
}
}
diff --git a/release-notes.md b/release-notes.md
index 67b66a3f..6394b297 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -1,16 +1,14 @@
-# Release 1.9.3
+# Release 1.9.4
## What's New
-* Page Service List
-* Sort Service on Identity Details Page
-* Consistent UX for MFA Screens
+* none
## Other changes:
-* Service to UI interaction is now with one bulk update of services instead of one event per service update
-* Added a configuration option to control if DNS is applied to the TUN. Some users are having issues with NRPT-only working. For now we'll add a boolean that allows the user to control if DNS should be added to the TUN
+* none
## Bugs fixed:
-* none
+* [#362](https://github.com/openziti/desktop-edge-win/issues/362) Update tun ip, mask and addDns flag
+* [#364](https://github.com/openziti/desktop-edge-win/issues/364) Add the test nrpt policy function in the startup method
## Dependency Updates
* none
@@ -24,6 +22,7 @@
## Other changes:
* Service to UI interaction is now with one bulk update of services instead of one event per service update
+* Added a configuration option to control if DNS is applied to the TUN. Some users are having issues with NRPT-only working. For now we'll add a boolean that allows the user to control if DNS should be added to the TUN
## Bugs fixed:
* none
diff --git a/service/windns/windns.go b/service/windns/windns.go
index ae2897c0..23e63f74 100644
--- a/service/windns/windns.go
+++ b/service/windns/windns.go
@@ -238,3 +238,53 @@ ForEach ($ns in $toRemove){
log.Errorf("ERROR removing nrpt rules: %v", err)
}
}
+
+func IsNrptPoliciesEffective(dnsserver string) bool {
+ script := fmt.Sprintf(`Add-DnsClientNrptRule -Namespace ".ziti.test" -NameServers "%s" -Comment "Added by ziti-tunnel" -DisplayName "ziti-tunnel:.ziti.test"
+ Get-DnsClientNrptPolicy -Effective | Select-Object Namespace -Unique | Where-Object Namespace -Eq ".ziti.test"`, dnsserver)
+ log.Debugf("checking the nrpt policies with: %s", script)
+
+ cmd := exec.Command("powershell", "-Command", script)
+ cmd.Stderr = os.Stdout
+ output := new(bytes.Buffer)
+ cmd.Stdout = output
+
+ err := cmd.Run()
+ if err != nil {
+ log.Errorf("ERROR adding the test nrpt rules: %v", err)
+ return false
+ }
+
+ policyFound := false
+ for {
+ l, err := output.ReadString('\n')
+ policyOut := strings.Trim(l, "\r\n")
+ if err != nil {
+ break
+ }
+
+ if strings.Compare(policyOut, ".ziti.test") == 0 {
+ policyFound = true
+ log.Debug("The nrpt policies are effective in this client")
+ break
+ }
+ }
+ removeSingleNrtpRule(".ziti.test")
+
+ return policyFound
+}
+
+func removeSingleNrtpRule(nrptRule string) {
+ script := fmt.Sprintf(`Get-DnsClientNrptRule | where Namespace -eq "%s" | Remove-DnsClientNrptRule -Force -ErrorAction SilentlyContinue`, nrptRule)
+ log.Debugf("Removing the nrpt rule with: %s", script)
+
+ cmd := exec.Command("powershell", "-Command", script)
+ cmd.Stderr = os.Stdout
+ output := new(bytes.Buffer)
+ cmd.Stdout = output
+
+ err := cmd.Run()
+ if err != nil {
+ log.Errorf("ERROR removing the nrpt rules: %v", err)
+ }
+}
diff --git a/service/ziti-tunnel/cli/constants.go b/service/ziti-tunnel/cli/constants.go
index 3c21a278..150d45af 100644
--- a/service/ziti-tunnel/cli/constants.go
+++ b/service/ziti-tunnel/cli/constants.go
@@ -42,6 +42,10 @@ var NOTIFY_IDENTITY_UI = dto.CommandMsg{
Function: "NotifyIdentityUI",
}
+var UPDATE_TUN_IPV4 = dto.CommandMsg{
+ Function: "UpdateTunIpv4",
+}
+
var monitorIpcPipe = `\\.\pipe\OpenZiti\ziti-monitor\ipc`
var templateIdentity = `{{printf "%40s" "Name"}} | {{printf "%41s" "FingerPrint"}} | {{printf "%6s" "Active"}} | {{printf "%30s" "Config"}} | {{"Status"}}
diff --git a/service/ziti-tunnel/cli/responseGenerator.go b/service/ziti-tunnel/cli/responseGenerator.go
index f0143d26..d469dad7 100644
--- a/service/ziti-tunnel/cli/responseGenerator.go
+++ b/service/ziti-tunnel/cli/responseGenerator.go
@@ -57,11 +57,11 @@ func convertToServiceCli(svc dto.Service) dto.ServiceCli {
}
return dto.ServiceCli{
- Name: svc.Name,
- Id: svc.Id,
- Protocols: strings.Join(svc.Protocols, ","),
- Ports: cliPorts,
- Addresses: cliAddresses,
+ Name: svc.Name,
+ Id: svc.Id,
+ Protocols: strings.Join(svc.Protocols, ","),
+ Ports: cliPorts,
+ Addresses: cliAddresses,
}
}
diff --git a/service/ziti-tunnel/cli/service.go b/service/ziti-tunnel/cli/service.go
index ae695c88..bda4320d 100644
--- a/service/ziti-tunnel/cli/service.go
+++ b/service/ziti-tunnel/cli/service.go
@@ -1,9 +1,27 @@
package cli
-import (
- "strings"
+/*
+ * Copyright NetFoundry, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+import (
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/dto"
+ "net"
+ "strconv"
+ "strings"
)
//GetIdentities is to fetch identities through cmdline
@@ -53,3 +71,40 @@ func SetLogLevel(args []string, flags map[string]bool) {
func GetFeedback(args []string, flags map[string]bool) {
GetDataFromMonitorIpcPipe(&dto.FEEDBACK_REQUEST, args, flags)
}
+
+func UpdateConfigIPSubnet(args []string, flags map[string]interface{}) {
+ CIDRstring := flags["CIDR"]
+ AddDns := flags["AddDns"]
+ log.Info("Updating the config file")
+
+ updateTunIpv4Payload := make(map[string]interface{})
+ if CIDRstring != "" {
+ ip, ipnet, err := net.ParseCIDR(CIDRstring.(string))
+ if err != nil {
+ log.Error("Incorrect cidr %s", CIDRstring.(string))
+ }
+ ipMask, _ := ipnet.Mask.Size()
+
+ updateTunIpv4Payload["TunIPv4"] = ip
+ updateTunIpv4Payload["TunIPv4Mask"] = ipMask
+ }
+ if AddDns != "" {
+ addDnsBool, err := strconv.ParseBool(AddDns.(string))
+
+ if err != nil {
+ log.Errorf("Incorrect addDns %v", err)
+ return
+ }
+ updateTunIpv4Payload["AddDns"] = addDnsBool
+ }
+
+ UPDATE_TUN_IPV4.Payload = updateTunIpv4Payload
+ log.Debugf("updateTunIpv4 Payload %v", UPDATE_TUN_IPV4)
+
+ status := GetDataFromIpcPipe(&UPDATE_TUN_IPV4, nil, GetResponseObjectFromRTS, args, nil)
+
+ if !status {
+ log.Infof("Config can be updated only if the tunnel is started")
+ }
+
+}
diff --git a/service/ziti-tunnel/cmd/config.go b/service/ziti-tunnel/cmd/config.go
new file mode 100644
index 00000000..81c2ee08
--- /dev/null
+++ b/service/ziti-tunnel/cmd/config.go
@@ -0,0 +1,41 @@
+package cmd
+
+/*
+ * Copyright NetFoundry, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import (
+ "github.com/spf13/cobra"
+)
+
+// configCmd represents the config command
+var configCmd = &cobra.Command{
+ Use: "config",
+ Short: "A brief description of your command",
+ Long: `A longer description that spans multiple lines and likely contains examples
+and usage of using your command. For example:
+
+Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.`,
+ Run: func(cmd *cobra.Command, args []string) {
+ checkHelp()
+ },
+}
+
+func init() {
+ rootCmd.AddCommand(configCmd)
+}
diff --git a/service/ziti-tunnel/cmd/update.go b/service/ziti-tunnel/cmd/update.go
new file mode 100644
index 00000000..a72d9958
--- /dev/null
+++ b/service/ziti-tunnel/cmd/update.go
@@ -0,0 +1,50 @@
+package cmd
+
+/*
+ * Copyright NetFoundry, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import (
+ "github.com/openziti/desktop-edge-win/service/ziti-tunnel/cli"
+
+ "github.com/spf13/cobra"
+)
+
+var CIDR string
+var AddDns string
+
+// updateCmd represents the update command
+var updateCmd = &cobra.Command{
+ Use: "update",
+ Short: "Updates data into the ziti-tunnel",
+ Long: `update command should be used as a sub command to the main command
+ It helps to update the data into the ziti-tunnel.
+ eg: ziti-tunnel config update --CIDR 100.64.0.1/10 --AddDns=true`,
+ Run: func(cmd *cobra.Command, args []string) {
+ flags := map[string]interface{}{}
+ flags["CIDR"] = CIDR
+ flags["AddDns"] = AddDns
+ cli.UpdateConfigIPSubnet(args, flags)
+ },
+}
+
+func init() {
+ configCmd.AddCommand(updateCmd)
+
+ updateCmd.Flags().StringVar(&CIDR, "CIDR", "", "Updates the cidr property in the config file")
+ updateCmd.Flags().StringVar(&AddDns, "AddDns", "", "Updates the Add Dns property in the config file")
+
+}
diff --git a/service/ziti-tunnel/dto/clidtos.go b/service/ziti-tunnel/dto/clidtos.go
index 6f7e840d..df93a954 100644
--- a/service/ziti-tunnel/dto/clidtos.go
+++ b/service/ziti-tunnel/dto/clidtos.go
@@ -27,11 +27,11 @@ type IdentityCli struct {
}
type ServiceCli struct {
- Name string
- Id string
- Protocols string
- Ports string
- Addresses string
+ Name string
+ Id string
+ Protocols string
+ Ports string
+ Addresses string
}
type IdentityOnOffPayload struct {
diff --git a/service/ziti-tunnel/main.go b/service/ziti-tunnel/main.go
index c1c3f236..1b5a51db 100644
--- a/service/ziti-tunnel/main.go
+++ b/service/ziti-tunnel/main.go
@@ -111,6 +111,8 @@ func main() {
commandline.Execute()
case "feedback":
commandline.Execute()
+ case "config":
+ commandline.Execute()
default:
usage(fmt.Sprintf("invalid command %s", cmd))
}
@@ -126,7 +128,7 @@ func usage(errmsg string) {
"%s\n\n"+
"usage: %s \n"+
" where is one of\n"+
- " install, remove, debug, start, stop, pause, continue, list, identity, loglevel, feedback or version.\n",
+ " install, remove, debug, start, stop, pause, continue, list, identity, loglevel, feedback, config or version.\n",
errmsg, os.Args[0])
os.Exit(2)
}
diff --git a/service/ziti-tunnel/service/ipc.go b/service/ziti-tunnel/service/ipc.go
index 4bd5cf49..f06e14ea 100644
--- a/service/ziti-tunnel/service/ipc.go
+++ b/service/ziti-tunnel/service/ipc.go
@@ -41,6 +41,7 @@ import (
"net"
"os"
"os/signal"
+ "strconv"
"strings"
"sync"
"time"
@@ -498,6 +499,21 @@ func serveIpc(conn net.Conn) {
//save the state
rts.SaveState()
+ case "UpdateTunIpv4":
+ var tunIPv4 string
+ var tunIPv4Mask int
+ var addDns string
+ if cmd.Payload["TunIPv4"] != nil {
+ tunIPv4 = cmd.Payload["TunIPv4"].(string)
+ }
+ if cmd.Payload["TunIPv4Mask"] != nil {
+ var tunIpv4Mask = cmd.Payload["TunIPv4Mask"].(float64)
+ tunIPv4Mask = int(tunIpv4Mask)
+ }
+ if cmd.Payload["AddDns"] != nil {
+ addDns = strconv.FormatBool(cmd.Payload["AddDns"].(bool))
+ }
+ updateTunIpv4(enc, tunIPv4, tunIPv4Mask, addDns)
case "NotifyLogLevelUIAndUpdateService":
sendLogLevelAndNotify(enc, cmd.Payload["Level"].(string))
case "NotifyIdentityUI":
@@ -622,6 +638,17 @@ func setLogLevel(out *json.Encoder, level string) {
respond(out, dto.Response{Message: "log level set", Code: SUCCESS, Error: "", Payload: nil})
}
+func updateTunIpv4(out *json.Encoder, ip string, ipMask int, addDns string) {
+
+ err := UpdateRuntimeStateIpv4(ip, ipMask, addDns)
+ if err != nil {
+ respondWithError(out, "Could not set Tun ip and mask", UNKNOWN_ERROR, err)
+ return
+ }
+
+ respond(out, dto.Response{Message: "TunIPv4 and mask is set, Manual Restart is required", Code: SUCCESS, Error: "", Payload: ""})
+}
+
func serveLogs(conn net.Conn) {
log.Debug("accepted a logs connection, writing logs to pipe")
w := bufio.NewWriter(conn)
diff --git a/service/ziti-tunnel/service/state.go b/service/ziti-tunnel/service/state.go
index cb5b06a3..7d667cfd 100644
--- a/service/ziti-tunnel/service/state.go
+++ b/service/ziti-tunnel/service/state.go
@@ -20,24 +20,26 @@ package service
import (
"bufio"
"encoding/json"
+ "errors"
"fmt"
+ "github.com/openziti/desktop-edge-win/service/cziti"
+ "github.com/openziti/desktop-edge-win/service/windns"
+ "github.com/openziti/desktop-edge-win/service/ziti-tunnel/config"
+ "github.com/openziti/desktop-edge-win/service/ziti-tunnel/constants"
+ "github.com/openziti/desktop-edge-win/service/ziti-tunnel/dto"
+ idcfg "github.com/openziti/sdk-golang/ziti/config"
"golang.org/x/sys/windows"
+ "golang.org/x/sys/windows/registry"
+ "golang.zx2c4.com/wireguard/tun"
+ "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
"io"
"io/ioutil"
"net"
"os"
"path"
+ "strconv"
"strings"
"time"
-
- "github.com/openziti/desktop-edge-win/service/cziti"
- "github.com/openziti/desktop-edge-win/service/ziti-tunnel/config"
- "github.com/openziti/desktop-edge-win/service/ziti-tunnel/constants"
- "github.com/openziti/desktop-edge-win/service/ziti-tunnel/dto"
- idcfg "github.com/openziti/sdk-golang/ziti/config"
- "golang.org/x/sys/windows/registry"
- "golang.zx2c4.com/wireguard/tun"
- "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
)
type RuntimeState struct {
@@ -221,7 +223,14 @@ func (t *RuntimeState) CreateTun(ipv4 string, ipv4mask int, applyDns bool) (net.
}
log.Info("routing applied")
- if applyDns {
+ zitiPoliciesEffective := windns.IsNrptPoliciesEffective(ipv4)
+ if applyDns || !zitiPoliciesEffective {
+ if applyDns {
+ log.Infof("DNS is applied to the TUN interface, because apply Dns flag in the config file is %t ", applyDns)
+ }
+ if !applyDns && !zitiPoliciesEffective {
+ log.Infof("DNS is applied to the TUN interface, because Ziti policies test result in this client is %t", zitiPoliciesEffective)
+ }
//for windows 10+, could 'domains' be able to replace NRPT? dunno - didn't test it
luid.SetDNS(windows.AF_INET, []net.IP{ip}, nil)
}
@@ -401,6 +410,35 @@ func (t *RuntimeState) UpdateIpv4(ipv4 string) {
rts.SaveState()
}
+func UpdateRuntimeStateIpv4(ip string, ipv4Mask int, addDns string) error {
+
+ log.Infof("updating configuration ip: %s, mask: %d, dns: %t", ip, ipv4Mask, addDns)
+
+ if ipv4Mask < constants.Ipv4MaxMask || ipv4Mask > constants.Ipv4MinMask {
+ return errors.New(fmt.Sprintf("ipv4Mask should be between %d and %d", constants.Ipv4MaxMask, constants.Ipv4MinMask))
+ }
+
+ if addDns != "" {
+ addDnsBool, err := strconv.ParseBool(addDns)
+
+ if err != nil {
+ return errors.New(fmt.Sprintf("Incorrect addDns %v", err))
+ }
+
+ rts.state.AddDns = addDnsBool
+ }
+
+ // if ip is not empty, then we set both ip and mask
+ if ip != "" {
+ rts.state.TunIpv4 = ip
+ rts.state.TunIpv4Mask = ipv4Mask
+ }
+
+ rts.SaveState()
+
+ return nil
+}
+
// uses the registry to determine if IPv6 is enabled or disabled on this machine. If it is disabled an IPv6 DNS entry
// will end up causing a fatal error on startup of the service. For this registry key and values see the MS documentation
// at https://docs.microsoft.com/en-us/troubleshoot/windows-server/networking/configure-ipv6-in-windows
diff --git a/service/ziti-tunnel/version.go b/service/ziti-tunnel/version.go
index 6f114ee5..7e992ac7 100644
--- a/service/ziti-tunnel/version.go
+++ b/service/ziti-tunnel/version.go
@@ -20,9 +20,9 @@
package main
const (
- Version = "1.9.3"
- Revision = "a02a50cf6437"
- Branch = "main"
+ Version = "1.9.4"
+ Revision = "2db5f6a8362d"
+ Branch = "release-next"
BuildUser = ""
- BuildDate = "2021-04-12 17:35:14"
+ BuildDate = "2021-04-21 18:46:25"
)
diff --git a/version b/version
index 77fee73a..d615fd0c 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1.9.3
+1.9.4