mirror of
https://github.com/openziti/desktop-edge-win.git
synced 2026-10-12 15:58:34 +00:00
Merge pull request #358 from openziti/release-next
release 1.9.3 merge to main
This commit is contained in:
@@ -149,5 +149,23 @@
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ComboBoxTextBoxStyle" TargetType="{x:Type TextBox}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type TextBox}">
|
||||
<Grid>
|
||||
<Border CornerRadius="5,0,0,5"
|
||||
BorderThickness="1"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="Black">
|
||||
<ScrollViewer x:Name="PART_ContentHost"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -68,8 +68,8 @@ namespace ZitiDesktopEdge {
|
||||
ExpectedLogPathServices = Path.Combine(ExpectedLogPathRoot, "service", $"ziti-tunneler.log");
|
||||
}
|
||||
|
||||
private void IdentityMenu_OnMessage(string message) {
|
||||
ShowBlurbAsync(message, "");
|
||||
async private void IdentityMenu_OnMessage(string message) {
|
||||
await ShowBlurbAsync(message, "");
|
||||
}
|
||||
|
||||
private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e) {
|
||||
@@ -105,14 +105,14 @@ namespace ZitiDesktopEdge {
|
||||
/// <param name="e">The MFA Event</param>
|
||||
private void ServiceClient_OnMfaEvent(object sender, MfaEvent mfa) {
|
||||
HideLoad();
|
||||
this.Dispatcher.Invoke(() => {
|
||||
this.Dispatcher.Invoke(async () => {
|
||||
if (mfa.Action == "enrollment_challenge") {
|
||||
string url = HttpUtility.UrlDecode(mfa.ProvisioningUrl);
|
||||
string secret = HttpUtility.ParseQueryString(url)["secret"];
|
||||
this.IdentityMenu.Identity.MFAInfo.RecoveryCodes = mfa?.RecoveryCodes?.ToArray();
|
||||
SetupMFA(this.IdentityMenu.Identity, url, secret);
|
||||
} else if (mfa.Action == "auth_challenge") {
|
||||
ShowBlurbAsync("Setting Up auth_challenge", "");
|
||||
await ShowBlurbAsync("Setting Up auth_challenge", "");
|
||||
} else if (mfa.Action == "enrollment_verification") {
|
||||
if (mfa.Successful) {
|
||||
ShowMFARecoveryCodes(this.IdentityMenu.Identity);
|
||||
@@ -127,7 +127,7 @@ namespace ZitiDesktopEdge {
|
||||
} else if (mfa.Action == "enrollment_remove") {
|
||||
// ShowBlurb("removed mfa: " + mfa.Successful, "");
|
||||
} else {
|
||||
ShowBlurbAsync("Unexpected error when processing MFA", "");
|
||||
await ShowBlurbAsync ("Unexpected error when processing MFA", "");
|
||||
logger.Error("unexpected action: " + mfa.Action);
|
||||
}
|
||||
LoadIdentities(true);
|
||||
@@ -172,9 +172,9 @@ namespace ZitiDesktopEdge {
|
||||
/// Show the MFA Recovery Codes
|
||||
/// </summary>
|
||||
/// <param name="identity">The Ziti Identity to Authenticate</param>
|
||||
public void ShowMFARecoveryCodes(ZitiIdentity identity) {
|
||||
async public void ShowMFARecoveryCodes(ZitiIdentity identity) {
|
||||
if (identity.MFAInfo!=null) {
|
||||
if (identity.MFAInfo.RecoveryCodes?.Length > 0) {
|
||||
if (identity.MFAInfo.IsAuthenticated&& identity.MFAInfo.RecoveryCodes!=null) {
|
||||
MFASetup.Opacity = 0;
|
||||
MFASetup.Visibility = Visibility.Visible;
|
||||
MFASetup.Margin = new Thickness(0, 0, 0, 0);
|
||||
@@ -188,7 +188,7 @@ namespace ZitiDesktopEdge {
|
||||
this.ShowMFA(IdentityMenu.Identity, 2);
|
||||
}
|
||||
} else {
|
||||
ShowBlurbAsync("MFA is not setup on this Identity", "");
|
||||
await ShowBlurbAsync("MFA is not setup on this Identity", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ namespace ZitiDesktopEdge {
|
||||
/// <summary>
|
||||
/// Close the MFA Screen with animation
|
||||
/// </summary>
|
||||
private void DoClose(bool isComplete) {
|
||||
async private void DoClose(bool isComplete) {
|
||||
DoubleAnimation animation = new DoubleAnimation(0, TimeSpan.FromSeconds(.3));
|
||||
ThicknessAnimation animateThick = new ThicknessAnimation(new Thickness(0, 0, 0, 0), TimeSpan.FromSeconds(.3));
|
||||
animation.Completed += CloseComplete;
|
||||
@@ -252,15 +252,11 @@ namespace ZitiDesktopEdge {
|
||||
if (IdentityMenu.IsVisible) {
|
||||
if (isComplete) {
|
||||
if (MFASetup.Type == 2) {
|
||||
if (IdentityMenu.Identity.MFAInfo?.RecoveryCodes?.Length > 0) {
|
||||
ShowRecovery(IdentityMenu.Identity);
|
||||
} else {
|
||||
ShowBlurbAsync("You do not have anymore recovery codes", this.RECOVER);
|
||||
}
|
||||
ShowRecovery(IdentityMenu.Identity);
|
||||
} else if (MFASetup.Type == 3) {
|
||||
IdentityMenu.Identity.IsMFAEnabled = false;
|
||||
IdentityMenu.Identity.MFAInfo.IsAuthenticated = false;
|
||||
ShowBlurbAsync("MFA Disabled, Service Access Can Be Limited", "");
|
||||
await ShowBlurbAsync("MFA Disabled, Service Access Can Be Limited", "");
|
||||
} else if (MFASetup.Type == 4) {
|
||||
ShowRecovery(IdentityMenu.Identity);
|
||||
}
|
||||
@@ -346,9 +342,15 @@ namespace ZitiDesktopEdge {
|
||||
this.IdentityMenu.MainWindow = this;
|
||||
SetNotifyIcon("white");
|
||||
|
||||
MFASetup.OnLoad += MFASetup_OnLoad;
|
||||
IdentityMenu.OnMessage += IdentityMenu_OnMessage;
|
||||
}
|
||||
|
||||
private void MFASetup_OnLoad(bool isComplete, string title, string message) {
|
||||
if (isComplete) HideLoad();
|
||||
else ShowLoad(title, message);
|
||||
}
|
||||
|
||||
private void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e) {
|
||||
if (notifyIcon != null) {
|
||||
notifyIcon.Visible = false;
|
||||
@@ -487,7 +489,8 @@ namespace ZitiDesktopEdge {
|
||||
serviceClient.OnServiceEvent += ServiceClient_OnServiceEvent;
|
||||
serviceClient.OnTunnelStatusEvent += ServiceClient_OnTunnelStatusEvent;
|
||||
serviceClient.OnMfaEvent += ServiceClient_OnMfaEvent;
|
||||
serviceClient.OnLogLevelEvent += ServiceClient_OnLogLevelEvent;
|
||||
serviceClient.OnLogLevelEvent += ServiceClient_OnLogLevelEvent;
|
||||
serviceClient.OnBulkServiceEvent += ServiceClient_OnBulkServiceEvent;
|
||||
Application.Current.Properties.Add("ServiceClient", serviceClient);
|
||||
|
||||
monitorClient = new MonitorClient();
|
||||
@@ -521,6 +524,28 @@ namespace ZitiDesktopEdge {
|
||||
Placement();
|
||||
}
|
||||
|
||||
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!");
|
||||
return;
|
||||
} else {
|
||||
foreach (var removed in e.RemovedServices) {
|
||||
removeService(found, removed);
|
||||
}
|
||||
foreach (var added in e.AddedServices) {
|
||||
addService(found, added);
|
||||
}
|
||||
LoadIdentities(false);
|
||||
this.Dispatcher.Invoke(() => {
|
||||
IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu;
|
||||
if (deets.IsVisible) {
|
||||
deets.UpdateView();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
string nextVersionStr = null;
|
||||
private void MonitorClient_OnReconnectFailure(object sender, object e) {
|
||||
if (nextVersionStr == null) {
|
||||
@@ -699,6 +724,9 @@ namespace ZitiDesktopEdge {
|
||||
|
||||
private void ServiceClient_OnClientDisconnected(object sender, object e) {
|
||||
this.Dispatcher.Invoke(() => {
|
||||
IdentityMenu.Visibility = Visibility.Collapsed;
|
||||
MFASetup.Visibility = Visibility.Collapsed;
|
||||
HideModal();
|
||||
IdList.Children.Clear();
|
||||
if (e != null) {
|
||||
logger.Debug(e.ToString());
|
||||
@@ -770,34 +798,20 @@ namespace ZitiDesktopEdge {
|
||||
private void ServiceClient_OnServiceEvent(object sender, ServiceEvent e) {
|
||||
if (e == null) return;
|
||||
|
||||
Debug.WriteLine($"==== ServiceEvent : action:{e.Action} fingerprint:{e.Fingerprint} name:{e.Service.Name} ");
|
||||
logger.Debug($"==== ServiceEvent : action:{e.Action} fingerprint:{e.Fingerprint} name:{e.Service.Name} ");
|
||||
var found = identities.Find(id => id.Fingerprint == e.Fingerprint);
|
||||
if (found == null) {
|
||||
logger.Debug($"{e.Action} service event for {e.Service.Name} but the provided identity fingerprint {e.Fingerprint} is not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Action == "added") {
|
||||
addService(found, e.Service);
|
||||
} else {
|
||||
removeService(found, e.Service);
|
||||
}
|
||||
LoadIdentities(false);
|
||||
this.Dispatcher.Invoke(() => {
|
||||
var found = identities.Find(id => id.Fingerprint == e.Fingerprint);
|
||||
|
||||
if (found == null) {
|
||||
Debug.WriteLine($"{e.Action} service event for {e.Service.Name} but the provided identity fingerprint {e.Fingerprint} is not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Action == "added") {
|
||||
ZitiService zs = new ZitiService(e.Service);
|
||||
var svc = found.Services.Find(s => s.Name == zs.Name);
|
||||
if (svc == null) {
|
||||
found.Services.Add(zs);
|
||||
if (zs.HasFailingPostureCheck()) {
|
||||
found.HasServiceFailingPostureCheck = true;
|
||||
if (zs.PostureChecks.Any(p => !p.IsPassing && p.QueryType == "MFA")) {
|
||||
found.MFAInfo.IsAuthenticated = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.Debug("the service named " + zs.Name + " is already accounted for on this identity.");
|
||||
}
|
||||
} else {
|
||||
logger.Debug("removing the service named: " + e.Service.Name);
|
||||
found.Services.RemoveAll(s => s.Name == e.Service.Name);
|
||||
}
|
||||
LoadIdentities(false);
|
||||
IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu;
|
||||
if (deets.IsVisible) {
|
||||
deets.UpdateView();
|
||||
@@ -805,6 +819,27 @@ namespace ZitiDesktopEdge {
|
||||
});
|
||||
}
|
||||
|
||||
private void addService(ZitiIdentity found, Service added) {
|
||||
ZitiService zs = new ZitiService(added);
|
||||
var svc = found.Services.Find(s => s.Name == zs.Name);
|
||||
if (svc == null) {
|
||||
found.Services.Add(zs);
|
||||
if (zs.HasFailingPostureCheck()) {
|
||||
found.HasServiceFailingPostureCheck = true;
|
||||
if (zs.PostureChecks.Any(p => !p.IsPassing && p.QueryType == "MFA")) {
|
||||
found.MFAInfo.IsAuthenticated = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.Debug("the service named " + zs.Name + " is already accounted for on this identity.");
|
||||
}
|
||||
}
|
||||
|
||||
private void removeService(ZitiIdentity found, Service removed) {
|
||||
logger.Debug("removing the service named: {0}", removed.Name);
|
||||
found.Services.RemoveAll(s => s.Name == removed.Name);
|
||||
}
|
||||
|
||||
private void ServiceClient_OnTunnelStatusEvent(object sender, TunnelStatusEvent e) {
|
||||
if (e == null) return; //just skip it for now...
|
||||
logger.Debug($"==== TunnelStatusEvent: ");
|
||||
@@ -889,6 +924,9 @@ namespace ZitiDesktopEdge {
|
||||
if (!Application.Current.Properties.Contains("dns")) {
|
||||
Application.Current.Properties.Add("dns", status?.IpInfo?.DNS);
|
||||
}
|
||||
if (!Application.Current.Properties.Contains("dnsenabled")) {
|
||||
Application.Current.Properties.Add("dnsenabled", status?.AddDns);
|
||||
}
|
||||
|
||||
foreach (var id in status.Identities) {
|
||||
updateViewWithIdentity(id);
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace ZitiDesktopEdge.Models {
|
||||
|
||||
public int Total { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string ToString() {
|
||||
public override string ToString() {
|
||||
return Total + " " + Message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.2.0")]
|
||||
[assembly: AssemblyVersion("1.9.2.0")]
|
||||
[assembly: AssemblyFileVersion("1.9.2.0")]
|
||||
// [assembly: AssemblyVersion("1.9.3.0")]
|
||||
[assembly: AssemblyVersion("1.9.3.0")]
|
||||
[assembly: AssemblyFileVersion("1.9.3.0")]
|
||||
|
||||
@@ -54,6 +54,13 @@ namespace ZitiDesktopEdge {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Toggle() {
|
||||
Enabled = !Enabled;
|
||||
if (OnToggled != null) {
|
||||
OnToggled(Enabled);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnToggle(object sender, RoutedEventArgs e) {
|
||||
e.Handled = true;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="30"/>
|
||||
<ColumnDefinition Width="30" Cursor="Hand" MouseUp="OpenDetails"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid HorizontalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -24,22 +24,31 @@
|
||||
<RowDefinition Height="40"/>
|
||||
<RowDefinition Height="20"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<local:Toggler x:Name="ToggleSwitch" Grid.Column="0" Grid.Row="0" Margin="0,10,0,0"></local:Toggler>
|
||||
<Label Name="ToggleStatus" Grid.Column="0" Grid.Row="1" Margin="0,-5,0,0" Content="Enabled" Foreground="White" FontSize="11" Typography.Capitals="AllSmallCaps" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center"></Label>
|
||||
<Label Name="IdName" Cursor="Hand" MouseUp="OpenDetails" MaxWidth="230" VerticalAlignment="Bottom" Grid.Column="1" Margin="0,6,0,0" FontFamily="pack://application:,,,/Assets/Fonts/#Open Sans" FontSize="16" Foreground="White" HorizontalAlignment="Left">
|
||||
<Rectangle Fill="Transparent" Grid.Column="0" Grid.RowSpan="2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Cursor="Hand" MouseUp="ToggledSwitch"></Rectangle>
|
||||
|
||||
<Label Name="IdName" MaxWidth="230" Grid.Row="0" Grid.Column="1" VerticalAlignment="Bottom" Margin="0,6,0,0" FontFamily="pack://application:,,,/Assets/Fonts/#Open Sans" FontSize="16" Foreground="White" HorizontalAlignment="Left">
|
||||
<TextBlock TextTrimming="CharacterEllipsis">Identity Name</TextBlock>
|
||||
</Label>
|
||||
<Rectangle Fill="Transparent" Grid.RowSpan="2" Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Cursor="Hand" MouseUp="OpenDetails"></Rectangle>
|
||||
|
||||
<Label Name="IdUrl" Cursor="Hand" MouseUp="OpenDetails" MaxWidth="180" MinWidth="230" Grid.Column="1" Grid.Row="1" FontSize="11" Margin="0,-5,0,0" Typography.Capitals="AllSmallCaps" FontFamily="pack://application:,,,/Assets/Fonts/#Open Sans" Foreground="White" HorizontalAlignment="Left">
|
||||
<TextBlock TextTrimming="CharacterEllipsis">https://serverUrlThisShouldTrimIfItsLong:8080</TextBlock>
|
||||
</Label>
|
||||
<Image Name="MfaRequired" Source="/Assets/Images/mfaoff.png" Grid.Column="2" Cursor="Hand" Width="50" Height="20" VerticalAlignment="Bottom" RenderOptions.BitmapScalingMode="Fant" Stretch="Uniform" Visibility="Visible" MouseUp="MFAAuthenticate"></Image>
|
||||
<Canvas Name="ServiceCountArea" Grid.Column="2" Grid.Row="0" Width="50" Height="40" MouseUp="OpenDetails" Cursor="Hand" Visibility="Collapsed">
|
||||
<Image Name="MfaRequired" Source="/Assets/Images/mfaoff.png" Grid.Column="2" Cursor="Hand" Width="50" Height="26" VerticalAlignment="Bottom" RenderOptions.BitmapScalingMode="Fant" Stretch="Uniform" Visibility="Visible" MouseUp="MFAAuthenticate"></Image>
|
||||
<Canvas Name="ServiceCountArea" Grid.Column="2" Grid.Row="0" Width="50" Height="40" Cursor="Hand" Visibility="Collapsed">
|
||||
<Border Width="44" Height="26" Background="#0068F9" CornerRadius="12" Canvas.Top="10" Canvas.Left="3"></Border>
|
||||
<Label Name="ServiceCount" Width="50" Height="26" Canvas.Top="9" Padding="0,0,0,0" FontSize="17" Content="23" Foreground="White" HorizontalAlignment="Center" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"></Label>
|
||||
<Label Name="ServiceCount" Width="50" Height="26" Canvas.Top="9" Padding="0,0,0,0" FontSize="14" Content="23" Foreground="White" HorizontalAlignment="Center" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"></Label>
|
||||
</Canvas>
|
||||
<Label Name="ServiceCountAreaLabel" Grid.Column="3" MouseUp="OpenDetails" Grid.Row="1" Margin="0,-5,0,0" Content="authorize" Cursor="Hand" Foreground="White" FontSize="11" HorizontalAlignment="Stretch" Typography.Capitals="AllSmallCaps" HorizontalContentAlignment="Center"></Label>
|
||||
<Rectangle Fill="Transparent" Grid.Column="2" Grid.RowSpan="2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Cursor="Hand" MouseUp="DoMFAOrOpen"></Rectangle>
|
||||
|
||||
</Grid>
|
||||
<Image Grid.Column="1" Source="/Assets/Images/next.png" Width="12" MouseUp="OpenDetails" Cursor="Hand"></Image>
|
||||
<Rectangle Fill="Transparent" Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Cursor="Hand" MouseUp="OpenDetails"></Rectangle>
|
||||
|
||||
</Grid>
|
||||
</Canvas>
|
||||
</UserControl>
|
||||
|
||||
@@ -115,5 +115,17 @@ namespace ZitiDesktopEdge {
|
||||
private void MFAAuthenticate(object sender, MouseButtonEventArgs e) {
|
||||
this.Authenticate?.Invoke(_identity);
|
||||
}
|
||||
|
||||
private void ToggledSwitch(object sender, MouseButtonEventArgs e) {
|
||||
ToggleSwitch.Toggle();
|
||||
}
|
||||
|
||||
private void DoMFAOrOpen(object sender, MouseButtonEventArgs e) {
|
||||
if (MfaRequired.Visibility==Visibility.Visible) {
|
||||
MFAAuthenticate(sender, e);
|
||||
} else {
|
||||
OpenDetails(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<RowDefinition Height="30"></RowDefinition>
|
||||
<RowDefinition Height="30"></RowDefinition>
|
||||
<RowDefinition x:Name="ServiceRow" Height="140"></RowDefinition>
|
||||
<RowDefinition Height="40"></RowDefinition>
|
||||
<RowDefinition Height="30"></RowDefinition>
|
||||
<RowDefinition Height="40"></RowDefinition>
|
||||
<RowDefinition x:Name="IdImage" Height="0"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
@@ -78,10 +78,41 @@
|
||||
</Rectangle>
|
||||
<Label x:Name="AuthMessageLabel" HorizontalAlignment="Center" Content="Authenticate" IsHitTestVisible="False" Foreground="#FFFFFF" Grid.Row="6"></Label>
|
||||
|
||||
<!-- Forget Identity Button -->
|
||||
<Label Name="ForgetIdentityButton" Grid.Column="0" Grid.Row="7" Padding="0,10,0,10" Margin="0,0,0,0" Content="Forget This Identity" Cursor="Hand" Foreground="#F4044D" HorizontalAlignment="Center" Mouse.MouseUp="ForgetIdentity"></Label>
|
||||
<!-- Sorting and Paging -->
|
||||
<Grid x:Name="PageSortArea" Grid.Column="0" Grid.Row="7">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="40"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="40"></ColumnDefinition>
|
||||
<ColumnDefinition Width="90"></ColumnDefinition>
|
||||
<ColumnDefinition Width="70"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Content="Page" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center"></Label>
|
||||
<ComboBox Name="Pages" Grid.Column="1" Grid.Row="0" SelectionChanged="Pages_SelectionChanged" Width="60" Height="28" VerticalAlignment="Top" HorizontalAlignment="Left" BorderThickness="0" Background="#FFD4CECE" Foreground="#FF292626" FontFamily="/ZitiDesktopEdge;component/Assets/Fonts/#Open Sans" FontSize="14"></ComboBox>
|
||||
|
||||
<Image Name="ForgetIdentityImage" Visibility="Collapsed" Source="/Assets/Images/identity.png" Grid.Column="0" Grid.Row="8" Height="80" Width="80" Opacity="0.3" HorizontalAlignment="Stretch"></Image>
|
||||
<Label Content="Sort" Grid.Column="2" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center"></Label>
|
||||
<ComboBox Name="SortByField" Grid.Column="3" Grid.Row="0" SelectionChanged="SortByField_SelectionChanged" Height="28" VerticalAlignment="Top" HorizontalAlignment="Stretch" BorderThickness="0" Background="#FFD4CECE" Foreground="#FF292626" FontFamily="/ZitiDesktopEdge;component/Assets/Fonts/#Open Sans" FontSize="14">
|
||||
<ComboBoxItem IsSelected="True">Name</ComboBoxItem>
|
||||
<ComboBoxItem>Address</ComboBoxItem>
|
||||
<ComboBoxItem>Protocol</ComboBoxItem>
|
||||
<ComboBoxItem>Port</ComboBoxItem>
|
||||
</ComboBox>
|
||||
<ComboBox Name="SortWayField" Grid.Column="4" Grid.Row="0" Margin="5,0,0,0" SelectionChanged="SortWayField_SelectionChanged" Height="28" VerticalAlignment="Top" HorizontalAlignment="Stretch" BorderThickness="0" Foreground="#FF292626" FontFamily="/ZitiDesktopEdge;component/Assets/Fonts/#Open Sans" FontSize="14">
|
||||
<ComboBox.Resources>
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.WindowBrushKey}" Color="Yellow" />
|
||||
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Red" />
|
||||
</ComboBox.Resources>
|
||||
<ComboBoxItem IsSelected="True">Asc</ComboBoxItem>
|
||||
<ComboBoxItem>Desc</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
|
||||
<!-- Forget Identity Button -->
|
||||
<Label Name="ForgetIdentityButton" Grid.Column="0" Grid.Row="8" Padding="0,10,0,10" Margin="0,0,0,0" Content="Forget This Identity" Cursor="Hand" Foreground="#F4044D" HorizontalAlignment="Center" Mouse.MouseUp="ForgetIdentity"></Label>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -35,6 +35,10 @@ namespace ZitiDesktopEdge {
|
||||
public event OnAuthenticate Authenticate;
|
||||
public delegate void OnRecovery(ZitiIdentity identity);
|
||||
public event OnRecovery Recovery;
|
||||
public int Page = 1;
|
||||
public int PerPage = 50;
|
||||
public string SortBy = "Name";
|
||||
public string SortWay = "Asc";
|
||||
|
||||
internal MainWindow MainWindow { get; set; }
|
||||
|
||||
@@ -53,6 +57,11 @@ namespace ZitiDesktopEdge {
|
||||
set {
|
||||
_identity = value;
|
||||
this.IdDetailToggle.Enabled = _identity.IsEnabled;
|
||||
Page = 1;
|
||||
SortBy = "Name";
|
||||
SortWay = "Asc";
|
||||
SortByField.SelectedIndex = 0;
|
||||
SortWayField.SelectedIndex = 0;
|
||||
UpdateView();
|
||||
IdentityArea.Opacity = 1.0;
|
||||
IdentityArea.Visibility = Visibility.Visible;
|
||||
@@ -117,17 +126,45 @@ namespace ZitiDesktopEdge {
|
||||
IdentityMFA.RecoveryButton.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
ServiceList.Children.Clear();
|
||||
PageSortArea.Visibility = Visibility.Collapsed;
|
||||
if (_identity.Services.Count>0) {
|
||||
foreach(var zitiSvc in _identity.Services.OrderBy(s => s.Name.ToLower())) {
|
||||
if (zitiSvc.Name.ToLower().IndexOf(filter.ToLower()) >=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);
|
||||
PageSortArea.Visibility = Visibility.Visible;
|
||||
int index = 0;
|
||||
int total = 0;
|
||||
ZitiService[] services = new ZitiService[0];
|
||||
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();
|
||||
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];
|
||||
total++;
|
||||
if (index<100) {
|
||||
if (zitiSvc.Name.ToLower().IndexOf(filter.ToLower()) >= 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);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
double newHeight = MainHeight - 330;
|
||||
ServiceRow.Height = new GridLength((double)newHeight);
|
||||
MainDetailScroll.MaxHeight = newHeight;
|
||||
@@ -326,5 +363,36 @@ namespace ZitiDesktopEdge {
|
||||
private void AuthFromMessage(object sender, MouseButtonEventArgs e) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,19 @@
|
||||
<DropShadowEffect BlurRadius="20" Direction="1" RenderingBias="Quality" ShadowDepth="1" Opacity="1"/>
|
||||
</Border.Effect>
|
||||
</Border>
|
||||
<Rectangle Margin="10,10,10,10" RadiusX="12" RadiusY="12" ClipToBounds="True">
|
||||
<Rectangle x:Name="MainBrush" Margin="10,10,10,10" RadiusX="12" RadiusY="12" ClipToBounds="True">
|
||||
<Rectangle.Fill>
|
||||
<SolidColorBrush Color="#FFFFFF" Opacity="0.97"/>
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="AuthBrush" Margin="10,10,10,10" RadiusX="12" RadiusY="12" ClipToBounds="True">
|
||||
<Rectangle.Fill>
|
||||
<SolidColorBrush Color="#131429" Opacity="0.97"/>
|
||||
</Rectangle.Fill>
|
||||
<Rectangle.Stroke>
|
||||
<SolidColorBrush Color="White" Opacity="0.4"></SolidColorBrush>
|
||||
</Rectangle.Stroke>
|
||||
</Rectangle>
|
||||
<Rectangle x:Name="SeperationColor" Margin="16,10,16,16" RadiusX="10" RadiusY="10" ClipToBounds="True" Height="160" VerticalAlignment="Bottom">
|
||||
<Rectangle.Fill>
|
||||
<SolidColorBrush Color="#131429" Opacity="0.97"/>
|
||||
@@ -51,7 +59,7 @@
|
||||
</StackPanel>
|
||||
<Label Content="enter the code below to finish setup" Grid.Row="4" FontSize="11" Foreground="DarkGray" HorizontalAlignment="Center"></Label>
|
||||
<Label Content="Authentication Code" Grid.Row="5" FontSize="18" Foreground="#FFFFFF" HorizontalAlignment="Center" FontWeight="Bold" FontFamily="/ZitiDesktopEdge;component/Assets/Fonts/#Russo One"></Label>
|
||||
<TextBox x:Name="SetupCode" MaxLength="6" Padding="0,5,0,0" TextBlock.LineHeight="80" Grid.Row="6" Keyboard.KeyUp="HandleKey" BorderThickness="0 0 0 0" TextAlignment="Center" FontSize="50">
|
||||
<TextBox x:Name="SetupCode" MaxLength="6" Padding="0,5,0,0" Grid.Row="6" Keyboard.KeyUp="HandleKey" BorderThickness="0 0 0 0" TextAlignment="Center" FontSize="50">
|
||||
<TextBox.Resources>
|
||||
<Style TargetType="{x:Type Border}">
|
||||
<Setter Property="CornerRadius" Value="7"/>
|
||||
@@ -73,6 +81,8 @@
|
||||
</Grid.RowDefinitions>
|
||||
<Label Content="MFA Recovery Codes" Grid.Row="0" FontSize="16" HorizontalAlignment="Center" FontWeight="Bold"></Label>
|
||||
<UniformGrid x:Name="RecoveryList" Grid.Row="1" Columns="3"></UniformGrid>
|
||||
<TextBlock TextWrapping="WrapWithOverflow" x:Name="NoRecovery" Visibility="Collapsed" Text="No Recovery Codes Available" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20,0,20,0" FontSize="16"></TextBlock>
|
||||
|
||||
<Grid Grid.Row="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="160"></ColumnDefinition>
|
||||
@@ -91,28 +101,22 @@
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"></RowDefinition>
|
||||
<RowDefinition Height="30"></RowDefinition>
|
||||
<RowDefinition Height="100"></RowDefinition>
|
||||
<RowDefinition Height="80"></RowDefinition>
|
||||
<RowDefinition Height="30"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<Label Content="Authorize MFA" Grid.Row="0" FontSize="16" HorizontalAlignment="Center" FontWeight="Bold"></Label>
|
||||
<Label x:Name="AuthSubTitle" Content="Enter your authentication code" Grid.Row="1" FontSize="12" HorizontalAlignment="Center"></Label>
|
||||
<TextBox x:Name="AuthCode" MaxLength="6" FontSize="50" Padding="0,5,0,0" Grid.Row="2" Keyboard.KeyUp="AuthCode_KeyUp" TextAlignment="Center" BorderThickness="0 0 0 2">
|
||||
<Label Content="Authorize MFA" Foreground="White" Grid.Row="0" FontSize="16" HorizontalAlignment="Center" FontWeight="Bold"></Label>
|
||||
<Label x:Name="AuthSubTitle" Foreground="White" Opacity="0.7" Content="Enter Authorization or Recovery Code" Grid.Row="1" FontSize="12" HorizontalAlignment="Center"></Label>
|
||||
<TextBox x:Name="AuthCode" MaxLength="8" FontSize="50" Padding="0,5,0,0" Grid.Row="2" Keyboard.KeyUp="AuthCode_KeyUp" TextAlignment="Center" BorderThickness="0 0 0 0" Margin="0,0,0,5">
|
||||
<TextBox.Resources>
|
||||
<Style TargetType="{x:Type Border}">
|
||||
<Setter Property="CornerRadius" Value="7"/>
|
||||
</Style>
|
||||
</TextBox.Resources>
|
||||
</TextBox>
|
||||
<Grid Grid.Row="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="160"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label x:Name="ToggleType" HorizontalAlignment="Center" Content="Use Recovery Code" Foreground="#0069FF" Cursor="Hand" Grid.Column="0" MouseUp="ToggleRecovery"></Label>
|
||||
<Label HorizontalAlignment="Center" Content="Authenticate" Foreground="#0069FF" Cursor="Hand" Grid.Column="1" MouseUp="DoAuthenticate"></Label>
|
||||
</Grid>
|
||||
<local:StyledButton x:Name="AuthButton" OnClick="DoAuthenticate" Label="Authenticate" Grid.Row="7"></local:StyledButton>
|
||||
</Grid>
|
||||
|
||||
<Image Source="/Assets/Images/closeBlack.png" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,40,40,0" Width="10" Height="10" Cursor="Hand" MouseUp="ExecuteClose"></Image>
|
||||
<Image x:Name="CloseBlack" Source="/Assets/Images/closeBlack.png" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,40,40,0" Width="10" Height="10" Cursor="Hand" MouseUp="ExecuteClose"></Image>
|
||||
<Image x:Name="CloseWhite" Source="/Assets/Images/close.png" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,40,40,0" Width="10" Height="10" Cursor="Hand" MouseUp="ExecuteClose"></Image>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@@ -31,6 +31,8 @@ namespace ZitiDesktopEdge {
|
||||
public partial class MFAScreen : UserControl {
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public delegate void LoadEvent(bool isComplete, string title, string message);
|
||||
public event LoadEvent OnLoad;
|
||||
public delegate void CloseAction(bool isComplete);
|
||||
public event CloseAction OnClose;
|
||||
private string _url = "";
|
||||
@@ -83,10 +85,14 @@ namespace ZitiDesktopEdge {
|
||||
this._identity = identity;
|
||||
MFAImage.Visibility = Visibility.Visible;
|
||||
SecretCode.Visibility = Visibility.Collapsed;
|
||||
CloseBlack.Visibility = Visibility.Visible;
|
||||
CloseWhite.Visibility = Visibility.Collapsed;
|
||||
SecretButton.Content = "Show Secret";
|
||||
IdName.Content = identity.Name;
|
||||
Logger.Debug($"MFA Url: {url}");
|
||||
|
||||
AuthBrush.Visibility = Visibility.Collapsed;
|
||||
MainBrush.Visibility = Visibility.Visible;
|
||||
|
||||
MFAImage.Source = CreateQRFromUrl(url);
|
||||
SecretCode.Text = secret;
|
||||
|
||||
@@ -107,24 +113,39 @@ namespace ZitiDesktopEdge {
|
||||
MFARecoveryArea.Visibility = Visibility.Visible;
|
||||
RecoveryList.Children.Clear();
|
||||
_codes = codes;
|
||||
AuthBrush.Visibility = Visibility.Collapsed;
|
||||
MainBrush.Visibility = Visibility.Visible;
|
||||
CloseBlack.Visibility = Visibility.Visible;
|
||||
CloseWhite.Visibility = Visibility.Collapsed;
|
||||
MFAArea.Height = 380;
|
||||
for (int i=0; i<codes.Length; i++) {
|
||||
TextBox label = new TextBox();
|
||||
label.Text = codes[i];
|
||||
label.BorderThickness = new Thickness(0);
|
||||
label.Background = new SolidColorBrush();
|
||||
label.Background.Opacity = 0;
|
||||
label.HorizontalAlignment = HorizontalAlignment.Center;
|
||||
label.HorizontalContentAlignment = HorizontalAlignment.Center;
|
||||
label.VerticalAlignment = VerticalAlignment.Center;
|
||||
label.VerticalContentAlignment = VerticalAlignment.Center;
|
||||
RecoveryList.Children.Add(label);
|
||||
if (codes.Length>0) {
|
||||
for (int i = 0; i < codes.Length; i++) {
|
||||
TextBox label = new TextBox();
|
||||
label.Text = codes[i];
|
||||
label.BorderThickness = new Thickness(0);
|
||||
label.Background = new SolidColorBrush();
|
||||
label.Background.Opacity = 0;
|
||||
label.HorizontalAlignment = HorizontalAlignment.Center;
|
||||
label.HorizontalContentAlignment = HorizontalAlignment.Center;
|
||||
label.VerticalAlignment = VerticalAlignment.Center;
|
||||
label.VerticalContentAlignment = VerticalAlignment.Center;
|
||||
RecoveryList.Children.Add(label);
|
||||
}
|
||||
RecoveryList.Visibility = Visibility.Visible;
|
||||
NoRecovery.Visibility = Visibility.Collapsed;
|
||||
} else {
|
||||
RecoveryList.Visibility = Visibility.Collapsed;
|
||||
NoRecovery.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowMFA(ZitiIdentity identity, int type) {
|
||||
this.Type = type;
|
||||
AuthCode.Text = "";
|
||||
AuthBrush.Visibility = Visibility.Visible;
|
||||
MainBrush.Visibility = Visibility.Collapsed;
|
||||
CloseBlack.Visibility = Visibility.Collapsed;
|
||||
CloseWhite.Visibility = Visibility.Visible;
|
||||
this._identity = identity;
|
||||
MFASetupArea.Visibility = Visibility.Collapsed;
|
||||
MFARecoveryArea.Visibility = Visibility.Collapsed;
|
||||
@@ -152,21 +173,6 @@ namespace ZitiDesktopEdge {
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleRecovery(object sender, MouseButtonEventArgs e) {
|
||||
AuthCode.Text = "";
|
||||
if (AuthCode.MaxLength==6) {
|
||||
GenerateMFACodes(null, null);
|
||||
AuthCode.MaxLength = 8;
|
||||
ToggleType.Content = "Use Auth Code";
|
||||
AuthSubTitle.Content = "Enter a recovery code";
|
||||
AuthCode.Focus();
|
||||
} else {
|
||||
AuthCode.MaxLength = 6;
|
||||
ToggleType.Content = "Use Recovery Code";
|
||||
AuthSubTitle.Content = "Enter your authorization code";
|
||||
AuthCode.Focus();
|
||||
}
|
||||
}
|
||||
async private void ReturnMFACodes(object sender, MouseButtonEventArgs e) {
|
||||
DataClient serviceClient = serviceClient = (DataClient)Application.Current.Properties["ServiceClient"];
|
||||
string code = AuthCode.Text;
|
||||
@@ -214,17 +220,14 @@ namespace ZitiDesktopEdge {
|
||||
}
|
||||
}
|
||||
|
||||
async private void DoAuthenticate(object sender, MouseButtonEventArgs e) {
|
||||
async private void DoAuthenticate() {
|
||||
if (!this._executing) {
|
||||
|
||||
this._executing = true;
|
||||
string code = AuthCode.Text;
|
||||
if (AuthCode.MaxLength == 8) {
|
||||
if (code.Length != 8) this.ShowError("You must enter a valid recovery code");
|
||||
} else {
|
||||
if (code.Length != 6) this.ShowError("You must enter a valid code");
|
||||
}
|
||||
|
||||
DataClient serviceClient = (DataClient)Application.Current.Properties["ServiceClient"];
|
||||
this.OnLoad?.Invoke(false, "Authentication", "One Moment Please...");
|
||||
if (this.Type == 1) {
|
||||
SvcResponse authResult = await serviceClient.AuthMFA(this._identity.Fingerprint, code);
|
||||
if (authResult?.Code != 0) {
|
||||
@@ -238,6 +241,7 @@ namespace ZitiDesktopEdge {
|
||||
this.OnClose?.Invoke(true);
|
||||
this._executing = false;
|
||||
}
|
||||
this.OnLoad?.Invoke(true, "", "");
|
||||
} else if (this.Type == 2) {
|
||||
MfaRecoveryCodesResponse codeResponse = await serviceClient.ReturnMFACodes(this._identity.Fingerprint, code);
|
||||
if (codeResponse?.Code != 0) {
|
||||
@@ -250,6 +254,7 @@ namespace ZitiDesktopEdge {
|
||||
this.OnClose?.Invoke(true);
|
||||
this._executing = false;
|
||||
}
|
||||
this.OnLoad?.Invoke(true, "", "");
|
||||
} else if (this.Type == 3) {
|
||||
SvcResponse authResult = await serviceClient.RemoveMFA(this._identity.Fingerprint, code);
|
||||
if (authResult?.Code != 0) {
|
||||
@@ -261,6 +266,7 @@ namespace ZitiDesktopEdge {
|
||||
this.OnClose?.Invoke(true);
|
||||
this._executing = false;
|
||||
}
|
||||
this.OnLoad?.Invoke(true, "", "");
|
||||
} else if (this.Type == 4) {
|
||||
MfaRecoveryCodesResponse codeResponse = await serviceClient.GenerateMFACodes(this._identity.Fingerprint, code);
|
||||
if (codeResponse?.Code != 0) {
|
||||
@@ -273,6 +279,7 @@ namespace ZitiDesktopEdge {
|
||||
this.OnClose?.Invoke(true);
|
||||
this._executing = false;
|
||||
}
|
||||
this.OnLoad?.Invoke(true, "", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,7 +308,7 @@ namespace ZitiDesktopEdge {
|
||||
|
||||
private void AuthCode_KeyUp(object sender, KeyEventArgs e) {
|
||||
if (e.Key == Key.Return) {
|
||||
DoAuthenticate(sender, null);
|
||||
DoAuthenticate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ namespace ZitiDesktopEdge {
|
||||
ConfigIp.Value = Application.Current.Properties["ip"]?.ToString();
|
||||
ConfigSubnet.Value = Application.Current.Properties["subnet"]?.ToString();
|
||||
ConfigMtu.Value = Application.Current.Properties["mtu"]?.ToString();
|
||||
ConfigDns.Value = Application.Current.Properties["dns"]?.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;
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.7.8\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationFramework.Aero2" />
|
||||
<Reference Include="QRCoder, Version=1.4.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\QRCoder.1.4.1\lib\net40\QRCoder.dll</HintPath>
|
||||
</Reference>
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
<ROW Property="CTRLS" Value="2"/>
|
||||
<ROW Property="Manufacturer" Value="NetFoundry, Inc."/>
|
||||
<ROW Property="MsiLogging" MultiBuildValue="AnyCPU_Release:vp"/>
|
||||
<ROW Property="ProductCode" Value="1033:{147D2A26-A83E-4878-A57C-9646407357C3} " Type="16"/>
|
||||
<ROW Property="ProductCode" Value="1033:{758AA10B-B1A9-45FB-97AB-20759FAB902D} " Type="16"/>
|
||||
<ROW Property="ProductLanguage" Value="1033"/>
|
||||
<ROW Property="ProductName" Value="Ziti Desktop Edge"/>
|
||||
<ROW Property="ProductVersion" Value="1.9.2" Type="32"/>
|
||||
<ROW Property="ProductVersion" Value="1.9.3" Type="32"/>
|
||||
<ROW Property="REBOOT" MultiBuildValue="AnyCPU_Release:Suppress"/>
|
||||
<ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND;AI_SETUPEXEPATH;SETUPEXEDIR"/>
|
||||
<ROW Property="UpgradeCode" Value="{CB7E173A-663D-4A23-BB22-D1E8D885C2F3}"/>
|
||||
|
||||
@@ -264,7 +264,11 @@ namespace ZitiDesktopEdge.DataStructures {
|
||||
public int Prefix { get; set; }
|
||||
|
||||
public override string ToString() {
|
||||
return Hostname;
|
||||
if (IsHost) {
|
||||
return Hostname;
|
||||
} else {
|
||||
return IP + "/" + Prefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,6 +337,7 @@ namespace ZitiDesktopEdge.DataStructures {
|
||||
public string LogLevel { get; set; }
|
||||
|
||||
public ServiceVersion ServiceVersion { get; set; }
|
||||
public bool AddDns { get; set; }
|
||||
|
||||
public void Dump(System.IO.TextWriter writer)
|
||||
{
|
||||
@@ -408,12 +413,17 @@ namespace ZitiDesktopEdge.DataStructures {
|
||||
public List<Identity> Identities { get; set; }
|
||||
}
|
||||
|
||||
public class ServiceEvent : ActionEvent
|
||||
{
|
||||
public class ServiceEvent : ActionEvent {
|
||||
public string Fingerprint { get; set; }
|
||||
public Service Service { get; set; }
|
||||
}
|
||||
|
||||
public class BulkServiceEvent : ActionEvent {
|
||||
public string Fingerprint { get; set; }
|
||||
public List<Service> AddedServices { get; set; }
|
||||
public List<Service> RemovedServices { get; set; }
|
||||
}
|
||||
|
||||
public class IdentityEvent : ActionEvent
|
||||
{
|
||||
public Identity Id { get; set; }
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace ZitiDesktopEdge.ServiceClient {
|
||||
public event EventHandler<ServiceEvent> OnServiceEvent;
|
||||
public event EventHandler<LogLevelEvent> OnLogLevelEvent;
|
||||
public event EventHandler<MfaEvent> OnMfaEvent;
|
||||
public event EventHandler<BulkServiceEvent> OnBulkServiceEvent;
|
||||
|
||||
protected override void ShutdownEvent(StatusEvent e) {
|
||||
Logger.Debug("Clean shutdown detected from ziti");
|
||||
@@ -57,12 +58,15 @@ namespace ZitiDesktopEdge.ServiceClient {
|
||||
protected virtual void ServiceEvent(ServiceEvent e) {
|
||||
OnServiceEvent?.Invoke(this, e);
|
||||
}
|
||||
|
||||
|
||||
protected virtual void BulkServiceEvent(BulkServiceEvent e) {
|
||||
OnBulkServiceEvent?.Invoke(this, e);
|
||||
}
|
||||
|
||||
protected virtual void LogLevelEvent(LogLevelEvent e) {
|
||||
OnLogLevelEvent?.Invoke(this, e);
|
||||
}
|
||||
|
||||
|
||||
protected virtual void MfaEvent(MfaEvent e) {
|
||||
OnMfaEvent?.Invoke(this, e);
|
||||
}
|
||||
@@ -199,21 +203,6 @@ namespace ZitiDesktopEdge.ServiceClient {
|
||||
return;
|
||||
}
|
||||
|
||||
async public Task SetLogLevelAsync(LogLevelEnum level) {
|
||||
try {
|
||||
await sendAsync(new SetLogLevelFunction(Enum.GetName(level.GetType(), level)));
|
||||
SvcResponse resp = await readAsync<SvcResponse>(ipcReader);
|
||||
return;
|
||||
} catch (Exception ioe) {
|
||||
//almost certainly a problem with the pipe - recreate the pipe...
|
||||
//setupPipe();
|
||||
//throw ioe;
|
||||
Logger.Error(ioe, "Unexpected error");
|
||||
CommunicationError(ioe);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
async public Task<Identity> IdentityOnOffAsync(string fingerprint, bool onOff) {
|
||||
try {
|
||||
await sendAsync(new IdentityToggleFunction(fingerprint, onOff));
|
||||
@@ -351,6 +340,14 @@ namespace ZitiDesktopEdge.ServiceClient {
|
||||
ServiceEvent(svc);
|
||||
}
|
||||
break;
|
||||
case "bulkservice":
|
||||
//dbg comment Logger.Warn("BULKSERVICE EVENT: \n" + respAsString);
|
||||
BulkServiceEvent bsvc = serializer.Deserialize<BulkServiceEvent>(jsonReader);
|
||||
|
||||
if (bsvc != null) {
|
||||
BulkServiceEvent(bsvc);
|
||||
}
|
||||
break;
|
||||
case "logLevel":
|
||||
LogLevelEvent ll = serializer.Deserialize<LogLevelEvent>(jsonReader);
|
||||
|
||||
|
||||
@@ -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.2.0")]
|
||||
[assembly: AssemblyVersion("1.9.2.0")]
|
||||
[assembly: AssemblyFileVersion("1.9.2.0")]
|
||||
// [assembly: AssemblyVersion("1.9.3.0")]
|
||||
[assembly: AssemblyVersion("1.9.3.0")]
|
||||
[assembly: AssemblyFileVersion("1.9.3.0")]
|
||||
|
||||
@@ -1,3 +1,36 @@
|
||||
# Release 1.9.3
|
||||
|
||||
## What's New
|
||||
* Page Service List
|
||||
* Sort Service on Identity Details Page
|
||||
* Consistent UX for MFA Screens
|
||||
|
||||
## 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
|
||||
|
||||
## Dependency Updates
|
||||
* none
|
||||
|
||||
# Release 1.9.3
|
||||
|
||||
## What's New
|
||||
* Page Service List
|
||||
* Sort Service on Identity Details Page
|
||||
* Consistent UX for MFA Screens
|
||||
|
||||
## Other changes:
|
||||
* Service to UI interaction is now with one bulk update of services instead of one event per service update
|
||||
|
||||
## Bugs fixed:
|
||||
* none
|
||||
|
||||
## Dependency Updates
|
||||
* none
|
||||
|
||||
# Release 1.9.2
|
||||
|
||||
## What's New
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
@echo off
|
||||
powershell "Get-Process | where -Property Name -eq "ziti-tunnel" | select -ExpandProperty id" > zid
|
||||
set /p zid= < zid
|
||||
del zid
|
||||
echo %zid%
|
||||
|
||||
"c:\Program Files\JetBrains\GoLand 2020.1.1\plugins\go\lib\dlv\windows\dlv.exe" attach %zid% --headless --log --only-same-user=false --api-version=2 --accept-multiclient --listen=localhost:50000
|
||||
@@ -151,35 +151,6 @@ dns_manager* get_dns_mgr_from_c() {
|
||||
return &dns_mgr_c;
|
||||
}
|
||||
|
||||
/* functions allowing go to iterate tunneleed_service_t* */
|
||||
protocol_t* stailq_first_protocol(tunneled_service_t* ts) {
|
||||
if(ts == NULL || ts->intercept == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
return STAILQ_FIRST(&ts->intercept->protocols);
|
||||
}
|
||||
address_t* stailq_first_address(tunneled_service_t* ts) {
|
||||
if(ts == NULL || ts->intercept == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
return STAILQ_FIRST(&ts->intercept->addresses);
|
||||
}
|
||||
port_range_t* stailq_first_port_range(tunneled_service_t* ts) {
|
||||
if(ts == NULL || ts->intercept == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
return STAILQ_FIRST(&ts->intercept->port_ranges);
|
||||
}
|
||||
protocol_t* stailq_next_protocol(protocol_t* cur) {
|
||||
return STAILQ_NEXT(cur, entries);
|
||||
}
|
||||
address_t* stailq_next_address(address_t* cur) {
|
||||
return STAILQ_NEXT(cur, entries);
|
||||
}
|
||||
port_range_t* stailq_next_port_range(port_range_t* cur) {
|
||||
return STAILQ_NEXT(cur, entries);
|
||||
}
|
||||
|
||||
char* ziti_char_array_get(char** arr, int idx) {
|
||||
return arr ? arr[idx] : NULL;
|
||||
}
|
||||
|
||||
+220
-192
@@ -41,37 +41,28 @@ void ziti_dump_to_file(void *ctx, char* outputPath);
|
||||
int ziti_dump_to_log(void *ctx, void* stringsBuilder);
|
||||
void* stailq_first_forgo(void* entries);
|
||||
|
||||
protocol_t* stailq_first_protocol(tunneled_service_t* ts);
|
||||
address_t* stailq_first_address(tunneled_service_t* ts);
|
||||
port_range_t* stailq_first_port_range(tunneled_service_t* ts);
|
||||
|
||||
protocol_t* stailq_next_protocol(protocol_t* cur);
|
||||
address_t* stailq_next_address(address_t* cur);
|
||||
port_range_t* stailq_next_port_range(port_range_t* cur);
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/openziti/desktop-edge-win/service/windns"
|
||||
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/api"
|
||||
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/dto"
|
||||
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/util/logging"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
ADDED = "added"
|
||||
REMOVED = "removed"
|
||||
)
|
||||
|
||||
var log = logging.Logger()
|
||||
var noFileLog = logging.NoFilenameLogger()
|
||||
var Version dto.ServiceVersion
|
||||
var ServiceChanges = make(chan dto.ServiceEvent, 256)
|
||||
var BulkServiceChanges = make(chan BulkServiceChange, 32)
|
||||
|
||||
var cCfgZitiTunnelerClientV1 = C.CString("ziti-tunneler-client.v1")
|
||||
var cCfgInterceptV1 = C.CString("intercept.v1")
|
||||
|
||||
type sdk struct {
|
||||
libuvCtx *C.libuv_ctx
|
||||
@@ -81,6 +72,13 @@ type ServiceChange struct {
|
||||
Service *ZService
|
||||
ZitiContext *ZIdentity
|
||||
}
|
||||
type BulkServiceChange struct {
|
||||
Fingerprint string
|
||||
HostnamesToAdd map[string]bool
|
||||
HostnamesToRemove map[string]bool
|
||||
ServicesToRemove []*dto.Service
|
||||
ServicesToAdd []*dto.Service
|
||||
}
|
||||
|
||||
var _impl sdk
|
||||
|
||||
@@ -150,54 +148,54 @@ func NewZid(statusChange func(int)) *ZIdentity {
|
||||
return zid
|
||||
}
|
||||
|
||||
func (c *ZIdentity) GetMetrics() (int64, int64, bool) {
|
||||
if c == nil {
|
||||
func (zid *ZIdentity) GetMetrics() (int64, int64, bool) {
|
||||
if zid == nil {
|
||||
return 0, 0, false
|
||||
}
|
||||
if unsafe.Pointer(c.czctx) == C.NULL {
|
||||
log.Debugf("ziti context is still null. the identity is probably not initialized yet: %s", c.Fingerprint)
|
||||
if unsafe.Pointer(zid.czctx) == C.NULL {
|
||||
log.Debugf("ziti context is still null. the identity is probably not initialized yet: %s", zid.Fingerprint)
|
||||
return 0, 0, false
|
||||
}
|
||||
var up, down C.double
|
||||
C.ziti_get_transfer_rates(c.czctx, &up, &down)
|
||||
C.ziti_get_transfer_rates(zid.czctx, &up, &down)
|
||||
|
||||
return int64(up), int64(down), true
|
||||
}
|
||||
|
||||
func (c *ZIdentity) UnsafePointer() unsafe.Pointer {
|
||||
return unsafe.Pointer(c.czctx)
|
||||
func (zid *ZIdentity) UnsafePointer() unsafe.Pointer {
|
||||
return unsafe.Pointer(zid.czctx)
|
||||
}
|
||||
func (c *ZIdentity) AsKey() string {
|
||||
func (zid *ZIdentity) AsKey() string {
|
||||
return "marker askey"
|
||||
}
|
||||
|
||||
func (c *ZIdentity) Status() (int, error) {
|
||||
return c.status, c.statusErr
|
||||
func (zid *ZIdentity) Status() (int, error) {
|
||||
return zid.status, zid.statusErr
|
||||
}
|
||||
|
||||
func (c *ZIdentity) setVersionFromId() string {
|
||||
if len(c.Version) > 0 {
|
||||
return c.Version
|
||||
func (zid *ZIdentity) setVersionFromId() string {
|
||||
if len(zid.Version) > 0 {
|
||||
return zid.Version
|
||||
}
|
||||
c.Version = "<unknown version>"
|
||||
if c != nil {
|
||||
if c.czctx != nil {
|
||||
v1 := C.ziti_get_controller_version(c.czctx)
|
||||
zid.Version = "<unknown version>"
|
||||
if zid != nil {
|
||||
if zid.czctx != nil {
|
||||
v1 := C.ziti_get_controller_version(zid.czctx)
|
||||
return C.GoString(v1.version)
|
||||
}
|
||||
}
|
||||
return c.Version
|
||||
return zid.Version
|
||||
}
|
||||
|
||||
func (c *ZIdentity) setNameFromId() string {
|
||||
if len(c.Name) > 0 {
|
||||
return c.Name
|
||||
func (zid *ZIdentity) setNameFromId() string {
|
||||
if len(zid.Name) > 0 {
|
||||
return zid.Name
|
||||
}
|
||||
c.Name = "<unknown>"
|
||||
if c != nil {
|
||||
if c.czid != nil {
|
||||
if c.czid.name != nil {
|
||||
c.Name = C.GoString(c.czid.name)
|
||||
zid.Name = "<unknown>"
|
||||
if zid != nil {
|
||||
if zid.czid != nil {
|
||||
if zid.czid.name != nil {
|
||||
zid.Name = C.GoString(zid.czid.name)
|
||||
} else {
|
||||
log.Debug("in Name - c.zid.name was nil")
|
||||
}
|
||||
@@ -207,12 +205,12 @@ func (c *ZIdentity) setNameFromId() string {
|
||||
} else {
|
||||
log.Debug("in Name - c was nil")
|
||||
}
|
||||
return c.Name
|
||||
return zid.Name
|
||||
}
|
||||
|
||||
func (c *ZIdentity) Tags() []string {
|
||||
if c.czctx != nil && c.czid != nil {
|
||||
C.c_mapiter(&c.czid.tags)
|
||||
func (zid *ZIdentity) Tags() []string {
|
||||
if zid.czctx != nil && zid.czid != nil {
|
||||
C.c_mapiter(&zid.czid.tags)
|
||||
/*
|
||||
it := C.model_map_iterator(&c.zid.tags)
|
||||
for {
|
||||
@@ -230,11 +228,11 @@ func (c *ZIdentity) Tags() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ZIdentity) Controller() string {
|
||||
if c.czctx != nil {
|
||||
return C.GoString(C.ziti_get_controller(c.czctx))
|
||||
func (zid *ZIdentity) Controller() string {
|
||||
if zid.czctx != nil {
|
||||
return C.GoString(C.ziti_get_controller(zid.czctx))
|
||||
}
|
||||
return C.GoString(c.Options.controller)
|
||||
return C.GoString(zid.Options.controller)
|
||||
}
|
||||
|
||||
func (zid *ZIdentity) Shutdown() {
|
||||
@@ -253,24 +251,84 @@ func doZitiShutdown(async *C.uv_async_t) {
|
||||
C.ziti_shutdown(ctx)
|
||||
}
|
||||
|
||||
func serviceCB(ziti_ctx C.ziti_context, service *C.ziti_service, status C.int, zid *ZIdentity) []dto.Address {
|
||||
type clientV1Cfg struct {
|
||||
//{"addresses":["eth0.ziti.ranged","eth0.second","eth0.third"],"portRanges":[{"high":80,"low":80},{"high":443,"low":443}],"protocols":["tcp"]}
|
||||
Addresses []string `json:"addresses"`
|
||||
PortRanges []dto.PortRange `json:"portRanges"`
|
||||
Protocols []string `json:"protocols"`
|
||||
}
|
||||
type v1ClientCfg struct {
|
||||
//{"hostname":"192.168.15.15","port":80}
|
||||
Hostname string `json:"hostname"`
|
||||
Port int `json:"port"`
|
||||
}
|
||||
|
||||
func serviceCB(ziti_ctx C.ziti_context, service *C.ziti_service, status C.int, zid *ZIdentity) *dto.Service {
|
||||
if zid == nil {
|
||||
log.Errorf("in serviceCB with nil zid??? ")
|
||||
return make([]dto.Address, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
name := C.GoString(service.name)
|
||||
svcId := C.GoString(service.id)
|
||||
log.Debugf("============ INSIDE serviceCB - status: %s:%s - %v, %v ============", name, svcId, status, service.perm_flags)
|
||||
ts := C.ziti_sdk_c_on_service(ziti_ctx, service, status, unsafe.Pointer(theTun.tunCtx))
|
||||
C.ziti_sdk_c_on_service(ziti_ctx, service, status, unsafe.Pointer(theTun.tunCtx))
|
||||
|
||||
var protocols []string
|
||||
var portRanges []dto.PortRange
|
||||
var addresses []dto.Address
|
||||
|
||||
strClientV1cfg := C.GoString(C.ziti_service_get_raw_config(service, cCfgInterceptV1))
|
||||
if strClientV1cfg != "" {
|
||||
log.Tracef("intercept.v1: %s", strClientV1cfg)
|
||||
var obj clientV1Cfg
|
||||
uerr := json.Unmarshal([]byte(strClientV1cfg), &obj)
|
||||
if uerr != nil {
|
||||
log.Errorf("could not marshall json? %v", uerr)
|
||||
}
|
||||
protocols = obj.Protocols
|
||||
portRanges = obj.PortRanges
|
||||
a := make([]dto.Address, len(obj.Addresses))
|
||||
for idx, add := range obj.Addresses {
|
||||
a[idx] = toAddy(add)
|
||||
}
|
||||
|
||||
addresses = append(a)
|
||||
} else {
|
||||
strZitiTunnelerClientV1 := C.GoString(C.ziti_service_get_raw_config(service, cCfgZitiTunnelerClientV1))
|
||||
log.Tracef("ziti-tunneler-client.v1: %s", strZitiTunnelerClientV1)
|
||||
var obj v1ClientCfg
|
||||
uerr := json.Unmarshal([]byte(strZitiTunnelerClientV1), &obj)
|
||||
if uerr != nil {
|
||||
log.Errorf("could not marshall json? %v", uerr)
|
||||
}
|
||||
protocols = []string{"UDP", "TCP"}
|
||||
portRanges = []dto.PortRange{{Low: obj.Port, High: obj.Port}}
|
||||
addresses = []dto.Address{toAddy(obj.Hostname)}
|
||||
}
|
||||
|
||||
protocols := getTunneledServiceProtocols(ts)
|
||||
addresses := getTunneledServiceAddresses(ts)
|
||||
portRanges := getTunneledServicePortRanges(ts)
|
||||
log.Infof("service update: %s, id: %s, portocols:%s, addresses:%v, portRanges: %v", name, svcId, protocols, addresses, portRanges)
|
||||
|
||||
var svc *dto.Service
|
||||
|
||||
if status == C.ZITI_SERVICE_UNAVAILABLE {
|
||||
serviceUnavailable(zid, svcId, name)
|
||||
log.Debugf("serivce has become unavailable: %s [%s]", name, svcId)
|
||||
f, ok := zid.Services.Load(svcId)
|
||||
if ok {
|
||||
svc = &dto.Service{
|
||||
Name: name,
|
||||
Id: svcId,
|
||||
Addresses: addresses,
|
||||
}
|
||||
found := f.(*ZService)
|
||||
if found != nil {
|
||||
found.Service = nil
|
||||
}
|
||||
zid.Services.Delete(svcId)
|
||||
return svc
|
||||
} else {
|
||||
log.Warnf("could not remove service? service not found with id: %s, name: %s in context %d", svcId, name, &zid)
|
||||
}
|
||||
} else if status == C.ZITI_OK {
|
||||
pcIds := make(map[string]bool)
|
||||
var postureChecks []dto.PostureCheck
|
||||
@@ -315,7 +373,7 @@ func serviceCB(ziti_ctx C.ziti_context, service *C.ziti_service, status C.int, z
|
||||
}
|
||||
}
|
||||
|
||||
svc := &dto.Service{
|
||||
svc = &dto.Service{
|
||||
Name: name,
|
||||
Id: svcId,
|
||||
Protocols: protocols,
|
||||
@@ -325,46 +383,47 @@ func serviceCB(ziti_ctx C.ziti_context, service *C.ziti_service, status C.int, z
|
||||
PostureChecks: postureChecks,
|
||||
IsAccessable: hasAccess,
|
||||
}
|
||||
|
||||
added := ZService{
|
||||
Name: name,
|
||||
Id: svcId,
|
||||
Service: svc,
|
||||
Czctx: ziti_ctx,
|
||||
}
|
||||
|
||||
se := dto.ServiceEvent{
|
||||
ActionEvent: dto.SERVICE_ADDED,
|
||||
Fingerprint: zid.Fingerprint,
|
||||
Service: svc,
|
||||
}
|
||||
|
||||
zid.Services.Store(svcId, &added)
|
||||
go func() {ServiceChanges <- se}() //do this in a go routine just in case it gets blocked so the uv loop doesn't block
|
||||
}
|
||||
return addresses
|
||||
|
||||
return svc
|
||||
}
|
||||
|
||||
func serviceUnavailable(ctx *ZIdentity, svcId string, name string) {
|
||||
log.Debugf("serivce has become unavailalbe: %s [%s]", name, svcId)
|
||||
f, ok := ctx.Services.Load(svcId)
|
||||
if ok {
|
||||
found := f.(*ZService)
|
||||
found.Service = nil
|
||||
ctx.Services.Delete(svcId)
|
||||
se := dto.ServiceEvent{
|
||||
ActionEvent: dto.SERVICE_REMOVED,
|
||||
Fingerprint: ctx.Fingerprint,
|
||||
Service: &dto.Service{
|
||||
Name: name,
|
||||
Id: svcId,
|
||||
},
|
||||
}
|
||||
ServiceChanges <- se
|
||||
log.Debugf("dispatched serivce has become unavailalbe to ui: %s [%s]", name, svcId)
|
||||
} else {
|
||||
log.Warnf("could not remove service? service not found with id: %s, name: %s in context %d", svcId, name, &ctx)
|
||||
func toAddy(hostOrIpOrCidr string) dto.Address {
|
||||
addy := dto.Address{
|
||||
IsHost: false,
|
||||
HostName: "",
|
||||
IP: "",
|
||||
Prefix: 0,
|
||||
}
|
||||
|
||||
log.Debugf("parsing %s to address", hostOrIpOrCidr)
|
||||
ip, ipnet, err := net.ParseCIDR(hostOrIpOrCidr)
|
||||
if err != nil {
|
||||
//must not be an CIDR... try IP parse
|
||||
ip = net.ParseIP(hostOrIpOrCidr)
|
||||
if ip == nil {
|
||||
log.Debugf("%s does not appear to be an ip/cidr combination. considering it a hostname", hostOrIpOrCidr)
|
||||
addy.HostName = hostOrIpOrCidr
|
||||
addy.IsHost = true
|
||||
} else {
|
||||
log.Debugf("%s determined to be ip", hostOrIpOrCidr)
|
||||
addy.IP = ip.String()
|
||||
}
|
||||
} else {
|
||||
log.Debugf("%s appears to be a proper CIDR", hostOrIpOrCidr)
|
||||
ones, _ := ipnet.Mask.Size()
|
||||
addy.IP = ip.String()
|
||||
addy.Prefix = ones
|
||||
}
|
||||
log.Tracef("parsed address: %v from %s", addy, hostOrIpOrCidr)
|
||||
return addy
|
||||
}
|
||||
|
||||
//export eventCB
|
||||
@@ -402,6 +461,9 @@ func eventCB(ztx C.ziti_context, event *C.ziti_event_t) {
|
||||
case C.ZitiServiceEvent:
|
||||
hostnamesToAdd := make(map[string]bool)
|
||||
hostnamesToRemove := make(map[string]bool)
|
||||
servicesToRemove := make([]*dto.Service, 0)
|
||||
servicesToAdd := make([]*dto.Service, 0)
|
||||
|
||||
srvEvent := C.ziti_event_service_event(event)
|
||||
|
||||
for i := 0; true; i++ {
|
||||
@@ -409,11 +471,16 @@ func eventCB(ztx C.ziti_context, event *C.ziti_event_t) {
|
||||
if unsafe.Pointer(removed) == C.NULL {
|
||||
break
|
||||
}
|
||||
addys := serviceCB(ztx, removed, C.ZITI_SERVICE_UNAVAILABLE, zid)
|
||||
for _, toRemove := range addys {
|
||||
if toRemove.IsHost {
|
||||
hostnamesToRemove[toRemove.HostName] = true
|
||||
|
||||
svcToRemove := serviceCB(ztx, removed, C.ZITI_SERVICE_UNAVAILABLE, zid)
|
||||
if svcToRemove != nil {
|
||||
remAddys := svcToRemove.Addresses
|
||||
for _, toRemove := range remAddys {
|
||||
if toRemove.IsHost && hostnameRemoved(toRemove.HostName) == 0 {
|
||||
hostnamesToRemove[toRemove.HostName] = true
|
||||
}
|
||||
}
|
||||
servicesToRemove = append(servicesToRemove, svcToRemove)
|
||||
}
|
||||
}
|
||||
for i := 0; true; i++ {
|
||||
@@ -421,19 +488,29 @@ func eventCB(ztx C.ziti_context, event *C.ziti_event_t) {
|
||||
if unsafe.Pointer(changed) == C.NULL {
|
||||
break
|
||||
}
|
||||
|
||||
log.Info("service changed remove the service then add it back immediately", C.GoString(changed.name))
|
||||
addys := serviceCB(ztx, changed, C.ZITI_SERVICE_UNAVAILABLE, zid)
|
||||
for _, toRemove := range addys {
|
||||
if toRemove.IsHost {
|
||||
hostnamesToRemove[toRemove.HostName] = true
|
||||
svcToRemove := serviceCB(ztx, changed, C.ZITI_SERVICE_UNAVAILABLE, zid)
|
||||
if svcToRemove != nil {
|
||||
|
||||
remAddys := svcToRemove.Addresses
|
||||
for _, toRemove := range remAddys {
|
||||
if toRemove.IsHost && hostnameRemoved(toRemove.HostName) == 0 {
|
||||
hostnamesToRemove[toRemove.HostName] = true
|
||||
}
|
||||
}
|
||||
servicesToRemove = append(servicesToRemove, svcToRemove)
|
||||
}
|
||||
|
||||
addys = serviceCB(ztx, changed, C.ZITI_OK, zid)
|
||||
for _, toAdd := range addys {
|
||||
if toAdd.IsHost {
|
||||
hostnamesToAdd[toAdd.HostName] = true
|
||||
svcToAdd := serviceCB(ztx, changed, C.ZITI_OK, zid)
|
||||
if svcToAdd != nil {
|
||||
addAddys := svcToAdd.Addresses
|
||||
for _, toAdd := range addAddys {
|
||||
if toAdd.IsHost && hostnameAdded(toAdd.HostName) == 1 {
|
||||
hostnamesToAdd[toAdd.HostName] = true
|
||||
}
|
||||
}
|
||||
servicesToAdd = append(servicesToAdd, svcToAdd)
|
||||
}
|
||||
}
|
||||
for i := 0; true; i++ {
|
||||
@@ -441,40 +518,37 @@ func eventCB(ztx C.ziti_context, event *C.ziti_event_t) {
|
||||
if unsafe.Pointer(added) == C.NULL {
|
||||
break
|
||||
}
|
||||
addys := serviceCB(ztx, added, C.ZITI_OK, zid)
|
||||
for _, toAdd := range addys {
|
||||
if toAdd.IsHost {
|
||||
hostnamesToAdd[toAdd.HostName] = true
|
||||
svcToAdd := serviceCB(ztx, added, C.ZITI_OK, zid)
|
||||
if svcToAdd != nil {
|
||||
addAddys := svcToAdd.Addresses
|
||||
for _, toAdd := range addAddys {
|
||||
if toAdd.IsHost && hostnameAdded(toAdd.HostName) == 1 {
|
||||
hostnamesToAdd[toAdd.HostName] = true
|
||||
}
|
||||
}
|
||||
servicesToAdd = append(servicesToAdd, svcToAdd)
|
||||
}
|
||||
}
|
||||
|
||||
if len(hostnamesToAdd) > 0 {
|
||||
windns.AddNrptRules(hostnamesToAdd, dnsip.String())
|
||||
log.Infof("mapped the following hostnames: %v", hostnamesToAdd)
|
||||
svcChange := BulkServiceChange{
|
||||
Fingerprint: zid.Fingerprint,
|
||||
HostnamesToAdd: hostnamesToAdd,
|
||||
HostnamesToRemove: hostnamesToRemove,
|
||||
ServicesToAdd: servicesToAdd,
|
||||
ServicesToRemove: servicesToRemove,
|
||||
}
|
||||
|
||||
if len(hostnamesToRemove) > 0 {
|
||||
windns.RemoveNrptRules(hostnamesToRemove)
|
||||
log.Infof("unmapped the following hostnames: %v", hostnamesToRemove)
|
||||
if len(BulkServiceChanges) == cap(BulkServiceChanges) {
|
||||
log.Warn("Service changes are not being processed fast enough. This client is out of date from the controller! This is unexpected. If you see this warning please report")
|
||||
} else {
|
||||
BulkServiceChanges <- svcChange
|
||||
}
|
||||
|
||||
var m = dto.IdentityEvent{
|
||||
ActionEvent: dto.IdentityUpdateComplete,
|
||||
Id: dto.Identity{
|
||||
FingerPrint: zid.Fingerprint,
|
||||
},
|
||||
}
|
||||
|
||||
goapi.BroadcastEvent(m)
|
||||
|
||||
default:
|
||||
log.Infof("event %d not handled", event._type)
|
||||
}
|
||||
}
|
||||
|
||||
func zitiContextEvent(ztx C.ziti_context, status C.int, zid *ZIdentity) {
|
||||
|
||||
zid.status = int(status)
|
||||
zid.statusErr = zitiError(status)
|
||||
zid.czctx = ztx
|
||||
@@ -605,81 +679,35 @@ func ziti_dump_go_to_log_cb(stringsBuilder unsafe.Pointer, charData *C.char) {
|
||||
sb := (*strings.Builder)(stringsBuilder)
|
||||
sb.WriteString(C.GoString(charData))
|
||||
}
|
||||
func ZitiDumpOnShutdown(zid *ZIdentity, sb *strings.Builder) {
|
||||
C.ziti_dump_to_log(unsafe.Pointer(zid.czctx), unsafe.Pointer(sb))
|
||||
}
|
||||
|
||||
func getTunneledServiceProtocols(ts *C.tunneled_service_t) []string {
|
||||
var protocols []string
|
||||
next := C.stailq_first_protocol(ts)
|
||||
if unsafe.Pointer(next) != C.NULL {
|
||||
protocols = append(protocols, C.GoString(next.protocol))
|
||||
for {
|
||||
next = C.stailq_next_protocol(next)
|
||||
if unsafe.Pointer(next) != C.NULL {
|
||||
protocols = append(protocols, C.GoString(next.protocol))
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return protocols
|
||||
}
|
||||
|
||||
func getTunneledServicePortRanges(ts *C.tunneled_service_t) []dto.PortRange {
|
||||
var values []dto.PortRange
|
||||
next := C.stailq_first_port_range(ts)
|
||||
if unsafe.Pointer(next) != C.NULL {
|
||||
p := dto.PortRange{
|
||||
High: int(next.high),
|
||||
Low: int(next.low),
|
||||
}
|
||||
values = append(values, p)
|
||||
for {
|
||||
next = C.stailq_next_port_range(next)
|
||||
if unsafe.Pointer(next) != C.NULL {
|
||||
p := dto.PortRange{
|
||||
High: int(next.high),
|
||||
Low: int(next.low),
|
||||
}
|
||||
values = append(values, p)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
func getTunneledServiceAddresses(ts *C.tunneled_service_t) []dto.Address {
|
||||
var values []dto.Address
|
||||
next := C.stailq_first_address(ts)
|
||||
if unsafe.Pointer(next) != C.NULL {
|
||||
p := dto.Address{
|
||||
IsHost: bool(next.is_hostname),
|
||||
HostName: C.GoString(&next.str[0]),
|
||||
IP: C.GoString(C.ipaddr_ntoa(&next.ip)),
|
||||
Prefix: int(next.prefix_len),
|
||||
}
|
||||
values = append(values, p)
|
||||
for {
|
||||
next = C.stailq_next_address(next)
|
||||
if unsafe.Pointer(next) != C.NULL {
|
||||
p := dto.Address{
|
||||
IsHost: bool(next.is_hostname),
|
||||
HostName: C.GoString(&next.str[0]),
|
||||
IP: C.GoString(C.ipaddr_ntoa(&next.ip)),
|
||||
Prefix: int(next.prefix_len),
|
||||
}
|
||||
values = append(values, p)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return values
|
||||
func ZitiDumpOnShutdown(zid *ZIdentity) {
|
||||
sb := strings.Builder{}
|
||||
C.ziti_dump_to_log(unsafe.Pointer(zid.czctx), unsafe.Pointer(&sb))
|
||||
log.Infof("working around the c sdk's limitation of embedding newlines on calling ziti_shutdown\n %s", sb.String())
|
||||
}
|
||||
|
||||
func InitTunnelerDns(ipBase uint32, mask int) {
|
||||
C.ziti_tunneler_init_dns(C.uint32_t(ipBase), C.int(mask))
|
||||
}
|
||||
|
||||
var addressCount = make(map[string]int)
|
||||
|
||||
func hostnameAdded(host string) int {
|
||||
count := 1
|
||||
if cur, ok := addressCount[host]; ok {
|
||||
count = cur + 1
|
||||
}
|
||||
addressCount[host] = count
|
||||
log.Debugf("hostname added: %s. count now: %d", host, count)
|
||||
return count
|
||||
}
|
||||
func hostnameRemoved(host string) int {
|
||||
count := 0
|
||||
if cur, ok := addressCount[host]; ok {
|
||||
if cur > 0 {
|
||||
count = cur - 1
|
||||
}
|
||||
}
|
||||
addressCount[host] = count
|
||||
log.Debugf("hostname removed %s. count now: %d", host, count)
|
||||
return count
|
||||
}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
cls & "c:\Program Files\JetBrains\GoLand 2020.1.1\plugins\go\lib\dlv\windows\dlv.exe" --listen=localhost:50000 --headless=true --api-version=2 --check-go-version=false --only-same-user=false exec c:\git\github\openziti\desktop-edge-win\service\ziti-tunnel.exe debug
|
||||
cls & "c:\Program Files\JetBrains\GoLand 2020.1.1\plugins\go\lib\dlv\windows\dlv.exe" --listen=localhost:50000 --headless=true --api-version=2 --check-go-version=false --only-same-user=false exec ziti-tunnel.exe debug
|
||||
|
||||
+60
-25
@@ -27,7 +27,12 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
MAX_POWERSHELL_SCRIPT_LEN = 7500 //represents how long the powershell script can be. as of apr 2021 the limit was 8k (8192). leaves a little room for the rest of the script
|
||||
)
|
||||
|
||||
var log = logging.Logger()
|
||||
var exeName = "ziti-tunnel"
|
||||
|
||||
func GetConnectionSpecificDomains() []string {
|
||||
script := `Get-DnsClient | Select-Object ConnectionSpecificSuffix -Unique | ForEach-Object { $_.ConnectionSpecificSuffix }; (Get-DnsClientGlobalSetting).SuffixSearchList`
|
||||
@@ -103,8 +108,8 @@ func FlushDNS() {
|
||||
}
|
||||
|
||||
func RemoveAllNrptRules() {
|
||||
script := fmt.Sprintf(`Get-DnsClientNrptRule | Where { $_.Comment.StartsWith("Added by ziti-tunnel") } | Remove-DnsClientNrptRule -ErrorAction SilentlyContinue -Force`)
|
||||
log.Debugf("removing all nrpt rules with: %s", script)
|
||||
script := fmt.Sprintf(`Get-DnsClientNrptRule | Where { $_.Comment.StartsWith("Added by %s") } | Remove-DnsClientNrptRule -ErrorAction SilentlyContinue -Force`, exeName)
|
||||
log.Tracef("removing all nrpt rules with: %s", script)
|
||||
|
||||
cmd := exec.Command("powershell", "-Command", script)
|
||||
cmd.Stderr = os.Stdout
|
||||
@@ -116,24 +121,27 @@ func RemoveAllNrptRules() {
|
||||
}
|
||||
}
|
||||
|
||||
var namespaceTemplate = `%s@{n="%s";}`
|
||||
var namespaceTemplatePadding = len(namespaceTemplate)
|
||||
|
||||
func AddNrptRules(domainsToMap map[string]bool, dnsServer string) {
|
||||
if len(domainsToMap) == 0 {
|
||||
log.Debug("no domains to map specified to AddNrptRules. exiting early")
|
||||
return
|
||||
}
|
||||
|
||||
blockSize := 50
|
||||
if len(domainsToMap) > blockSize {
|
||||
log.Debugf("domainsToMap is too long [%d] and may fail on some systems. splitting the requested entries into blocks of %d", len(domainsToMap), blockSize)
|
||||
}
|
||||
maxBucketSize := 500
|
||||
currentSize := 0
|
||||
hostnames := make([]string, blockSize)
|
||||
hostnames := make([]string, maxBucketSize)
|
||||
ruleSize := 0
|
||||
for hostname := range domainsToMap {
|
||||
if currentSize >= blockSize {
|
||||
ruleSize = ruleSize + len(hostname) + namespaceTemplatePadding
|
||||
if ruleSize > MAX_POWERSHELL_SCRIPT_LEN || currentSize >= maxBucketSize {
|
||||
log.Debugf("sending chunk of domains to be added to NRPT")
|
||||
chunkedAddNrptRules(hostnames, dnsServer)
|
||||
hostnames = make([]string, blockSize)
|
||||
chunkedAddNrptRules(hostnames[:currentSize], dnsServer)
|
||||
hostnames = make([]string, maxBucketSize)
|
||||
currentSize = 0
|
||||
ruleSize = len(hostname) + namespaceTemplatePadding
|
||||
}
|
||||
hostnames[currentSize] = hostname
|
||||
currentSize++
|
||||
@@ -146,21 +154,23 @@ func AddNrptRules(domainsToMap map[string]bool, dnsServer string) {
|
||||
|
||||
func chunkedAddNrptRules(domainsToAdd []string, dnsServer string) {
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString(`$Rules = @(
|
||||
sb.WriteString(`$Namespaces = @(
|
||||
`)
|
||||
|
||||
for _, hostname := range domainsToAdd {
|
||||
sb.WriteString(fmt.Sprintf(`@{ Namespace ="%s"; NameServers = @("%s"); Comment = "Added by ziti-tunnel"; DisplayName = "ziti-tunnel:%s"; }%s`, hostname, dnsServer, hostname, "\n"))
|
||||
sb.WriteString(fmt.Sprintf(namespaceTemplate, "\n", hostname))
|
||||
}
|
||||
|
||||
sb.WriteString(fmt.Sprintf(`)
|
||||
|
||||
ForEach ($Rule in $Rules) {
|
||||
Add-DnsClientNrptRule @Rule
|
||||
}`))
|
||||
ForEach ($Namespace in $Namespaces) {
|
||||
$ns=$Namespace["n"]
|
||||
$Rule = @{Namespace="${ns}"; NameServers=@("%s"); Comment="Added by %s"; DisplayName="%s:${ns}"; }
|
||||
Add-DnsClientNrptRule @Rule
|
||||
}`, dnsServer, exeName, exeName))
|
||||
|
||||
script := sb.String()
|
||||
log.Debugf("Executing NRPT script containing %d domains:\n%s", len(domainsToAdd), script)
|
||||
log.Tracef("Executing ADD NRPT script containing %d domains. total script size: %d\n%s", len(domainsToAdd), len(script), script)
|
||||
|
||||
cmd := exec.Command("powershell", "-Command", script)
|
||||
cmd.Stderr = os.Stdout
|
||||
@@ -172,27 +182,52 @@ ForEach ($Rule in $Rules) {
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveNrptRules(domainsToMap map[string]bool) {
|
||||
if len(domainsToMap) == 0 {
|
||||
func RemoveNrptRules(domainsToRemove map[string]bool) {
|
||||
if len(domainsToRemove) == 0 {
|
||||
log.Debug("no domains to map specified to RemoveNrptRules. exiting early")
|
||||
return
|
||||
}
|
||||
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString(`$toRemove = @(
|
||||
`)
|
||||
maxBucketSize := 500
|
||||
currentSize := 0
|
||||
hostnames := make([]string, maxBucketSize)
|
||||
ruleSize := 0
|
||||
for hostname := range domainsToRemove {
|
||||
ruleSize = ruleSize + len(hostname) + namespaceTemplatePadding
|
||||
if ruleSize > MAX_POWERSHELL_SCRIPT_LEN || currentSize >= maxBucketSize {
|
||||
log.Debugf("sending chunk of domains to be added to NRPT")
|
||||
chunkedRemoveNrptRules(hostnames[:currentSize])
|
||||
hostnames = make([]string, maxBucketSize)
|
||||
currentSize = 0
|
||||
ruleSize = len(hostname) + namespaceTemplatePadding
|
||||
}
|
||||
hostnames[currentSize] = hostname
|
||||
currentSize++
|
||||
}
|
||||
|
||||
for hostname := range domainsToMap {
|
||||
sb.WriteString(fmt.Sprintf(`"%s"%s`, hostname, "\n"))
|
||||
if currentSize > 0 {
|
||||
//means there's a chunk still to add....
|
||||
chunkedRemoveNrptRules(hostnames[:currentSize])
|
||||
}
|
||||
}
|
||||
|
||||
func chunkedRemoveNrptRules(domainsToRemove []string) {
|
||||
sb := strings.Builder{}
|
||||
sb.WriteString(`$toRemove = @(`)
|
||||
|
||||
for _, hostname := range domainsToRemove {
|
||||
sb.WriteString(fmt.Sprintf(namespaceTemplate, "\n", hostname))
|
||||
}
|
||||
|
||||
sb.WriteString(fmt.Sprintf(`)
|
||||
|
||||
Get-DnsClientNrptRule | Where { $toRemove -contains $_.DisplayName } | Remove-DnsClientNrptRule -ErrorAction SilentlyContinue -Force
|
||||
ForEach ($ns in $toRemove){
|
||||
Get-DnsClientNrptRule | where Namespace -eq $ns["n"] | Remove-DnsClientNrptRule -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
`))
|
||||
|
||||
script := sb.String()
|
||||
log.Debugf("Executing NRPT script:\n%s", script)
|
||||
log.Tracef("Executing REMOVE NRPT script containing %d domains. total script size: %d\n%s", len(domainsToRemove), len(script), script)
|
||||
|
||||
cmd := exec.Command("powershell", "-Command", script)
|
||||
cmd.Stderr = os.Stdout
|
||||
|
||||
@@ -18,9 +18,9 @@ package cli
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
@@ -119,6 +119,7 @@ type TunnelStatus struct {
|
||||
TunIpv4 string
|
||||
TunIpv4Mask int
|
||||
Status string
|
||||
AddDns bool
|
||||
}
|
||||
|
||||
type ServiceVersion struct {
|
||||
@@ -152,10 +153,11 @@ type MetricsEvent struct {
|
||||
Identities []*Identity
|
||||
}
|
||||
|
||||
type ServiceEvent struct {
|
||||
type BulkServiceEvent struct {
|
||||
ActionEvent
|
||||
Fingerprint string
|
||||
Service *Service
|
||||
Fingerprint string
|
||||
AddedServices []*Service
|
||||
RemovedServices []*Service
|
||||
}
|
||||
|
||||
type IdentityEvent struct {
|
||||
|
||||
@@ -18,17 +18,19 @@ package dto
|
||||
|
||||
const (
|
||||
ADDED = "added"
|
||||
BULK = "bulk"
|
||||
REMOVED = "removed"
|
||||
ERROR = "error"
|
||||
UPDATED = "updated"
|
||||
CHANGED = "changed"
|
||||
NORMAL = "Normal"
|
||||
|
||||
SERVICE_OP = "service"
|
||||
IDENTITY_OP = "identity"
|
||||
LOGLEVEL_OP = "logLevel"
|
||||
FEEDBACK_OP = "CaptureLogs"
|
||||
MFA_OP = "mfa"
|
||||
SERVICE_OP = "service"
|
||||
BULK_SERVICE_OP = "bulkservice"
|
||||
IDENTITY_OP = "identity"
|
||||
LOGLEVEL_OP = "logLevel"
|
||||
FEEDBACK_OP = "CaptureLogs"
|
||||
MFA_OP = "mfa"
|
||||
|
||||
MFAEnrollmentChallengAtion = "enrollment_challenge"
|
||||
MFAEnrollmentVerificationAction = "enrollment_verification"
|
||||
@@ -45,6 +47,10 @@ var SERVICE_REMOVED = ActionEvent{
|
||||
StatusEvent: StatusEvent{Op: SERVICE_OP},
|
||||
Action: REMOVED,
|
||||
}
|
||||
var SERVICE_BULK = ActionEvent{
|
||||
StatusEvent: StatusEvent{Op: BULK_SERVICE_OP},
|
||||
Action: BULK,
|
||||
}
|
||||
|
||||
var IDENTITY_ADDED = ActionEvent{
|
||||
StatusEvent: StatusEvent{Op: IDENTITY_OP},
|
||||
|
||||
@@ -25,11 +25,11 @@ import (
|
||||
func dbg() {
|
||||
|
||||
r := rts.ToStatus(true)
|
||||
events.broadcast <- dto.TunnelStatusEvent{
|
||||
rts.BroadcastEvent(dto.TunnelStatusEvent{
|
||||
StatusEvent: dto.StatusEvent{Op: "status"},
|
||||
Status: r,
|
||||
ApiVersion: API_VERSION,
|
||||
}
|
||||
})
|
||||
|
||||
svcs := make([]*dto.Service, 2)
|
||||
svcs[0] = &dto.Service{
|
||||
@@ -39,7 +39,7 @@ func dbg() {
|
||||
Name: "Second Fake Service",
|
||||
}
|
||||
|
||||
events.broadcast <- dto.IdentityEvent{
|
||||
rts.BroadcastEvent(dto.IdentityEvent{
|
||||
ActionEvent: dto.IDENTITY_ADDED,
|
||||
Id: dto.Identity{
|
||||
Name: "NewIdentity",
|
||||
@@ -52,25 +52,9 @@ func dbg() {
|
||||
Services: svcs,
|
||||
Metrics: nil,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
events.broadcast <- dto.ServiceEvent{
|
||||
ActionEvent: dto.SERVICE_ADDED,
|
||||
Service: &dto.Service{
|
||||
Name: "New Service",
|
||||
},
|
||||
Fingerprint: "new_id_fingerprint",
|
||||
}
|
||||
|
||||
events.broadcast <- dto.ServiceEvent{
|
||||
ActionEvent: dto.SERVICE_REMOVED,
|
||||
Service: &dto.Service{
|
||||
Name: "New Service",
|
||||
},
|
||||
Fingerprint: "new_id_fingerprint",
|
||||
}
|
||||
|
||||
events.broadcast <- dto.IdentityEvent{
|
||||
rts.BroadcastEvent(dto.IdentityEvent{
|
||||
ActionEvent: dto.IDENTITY_REMOVED,
|
||||
Id: dto.Identity{
|
||||
Name: "",
|
||||
@@ -81,5 +65,5 @@ func dbg() {
|
||||
Services: nil,
|
||||
Metrics: nil,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -119,9 +119,7 @@ func SubMain(ops chan string, changes chan<- svc.Status) error {
|
||||
log.Debug("shutting down. start a ZitiDump")
|
||||
for _, id := range rts.ids {
|
||||
if id.CId != nil {
|
||||
sb := strings.Builder{}
|
||||
cziti.ZitiDumpOnShutdown(id.CId, &sb)
|
||||
log.Infof("working around the c sdk's limitation of embedding newlines on calling ziti_shutdown\n %s", sb.String())
|
||||
cziti.ZitiDumpOnShutdown(id.CId)
|
||||
}
|
||||
}
|
||||
log.Debug("shutting down. ZitiDump complete")
|
||||
@@ -129,9 +127,9 @@ func SubMain(ops chan string, changes chan<- svc.Status) error {
|
||||
requestShutdown("service shutdown")
|
||||
|
||||
// signal to any connected consumers that the service is shutting down normally
|
||||
events.broadcast <- dto.StatusEvent{
|
||||
rts.BroadcastEvent(dto.StatusEvent{
|
||||
Op: "shutdown",
|
||||
}
|
||||
})
|
||||
|
||||
// wait 1 second for the shutdown to send to clients
|
||||
shutdownDelay := make(chan bool)
|
||||
@@ -282,7 +280,7 @@ func initialize(cLogLevel int) error {
|
||||
dnsIpAsUint32 := binary.BigEndian.Uint32(ipnet.IP)
|
||||
cziti.InitTunnelerDns(dnsIpAsUint32, len(ipnet.Mask))
|
||||
|
||||
assignedIp, t, err := rts.CreateTun(rts.state.TunIpv4, rts.state.TunIpv4Mask)
|
||||
assignedIp, t, err := rts.CreateTun(rts.state.TunIpv4, rts.state.TunIpv4Mask, rts.state.AddDns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -681,8 +679,9 @@ func serveEvents(conn net.Conn) {
|
||||
log.Debugf("accepting a new client for serveEvents. total connection count: %d", eventsConnections)
|
||||
|
||||
consumer := make(chan interface{}, 8)
|
||||
events.register(randomInt, consumer)
|
||||
defer events.unregister(randomInt)
|
||||
id := fmt.Sprintf("serveEvents:%d", randomInt)
|
||||
events.register(id, consumer)
|
||||
defer events.unregister(id)
|
||||
|
||||
w := bufio.NewWriter(conn)
|
||||
o := json.NewEncoder(w)
|
||||
@@ -704,12 +703,18 @@ loop:
|
||||
for {
|
||||
select {
|
||||
case msg := <-consumer:
|
||||
err := o.Encode(msg)
|
||||
if err != nil {
|
||||
log.Debugf("exiting from serveEvents - %v", err)
|
||||
log.Tracef("sending event to id: %s [%v]", id, msg)
|
||||
eerr := o.Encode(msg)
|
||||
if eerr != nil {
|
||||
log.Warnf("exiting from serveEvents due to error: %v", eerr)
|
||||
break loop
|
||||
}
|
||||
_ = w.Flush()
|
||||
ferr := w.Flush()
|
||||
if ferr != nil {
|
||||
log.Warnf("flush error: %v", ferr)
|
||||
return
|
||||
}
|
||||
log.Tracef("sent event to id: %s [%v]", id, msg)
|
||||
case <-interrupt:
|
||||
break loop
|
||||
}
|
||||
@@ -717,6 +722,10 @@ loop:
|
||||
log.Info("a connected event client has disconnected")
|
||||
}
|
||||
|
||||
func writerFlush(writer bufio.Writer) {
|
||||
writer.Flush()
|
||||
}
|
||||
|
||||
func reportStatus(out *json.Encoder) {
|
||||
s := rts.ToStatus(true)
|
||||
respond(out, dto.ZitiTunnelStatus{
|
||||
@@ -901,10 +910,10 @@ func connectIdentity(id *Id) {
|
||||
return true
|
||||
})
|
||||
|
||||
events.broadcast <- dto.IdentityEvent{
|
||||
rts.BroadcastEvent(dto.IdentityEvent{
|
||||
ActionEvent: dto.IDENTITY_ADDED,
|
||||
Id: id.Identity,
|
||||
}
|
||||
})
|
||||
log.Infof("connecting identity completed: %s[%s] %t/%t", id.Name, id.FingerPrint, id.MfaEnabled, id.MfaNeeded)
|
||||
}
|
||||
}
|
||||
@@ -1003,15 +1012,50 @@ func acceptServices() {
|
||||
select {
|
||||
case <-shutdown:
|
||||
return
|
||||
case serviceChange := <-cziti.ServiceChanges:
|
||||
log.Debugf("processing service change event. id:%s name:%s", serviceChange.Service.Id, serviceChange.Service.Name)
|
||||
change := dto.ServiceEvent(serviceChange)
|
||||
events.broadcast <- change
|
||||
log.Debugf("dispatched %s service change event", serviceChange.Op)
|
||||
case bulkServiceChange := <-cziti.BulkServiceChanges:
|
||||
log.Debugf("processing a bulk service change event. Hostnames to add/remove:[%d/%d] service notifications added/removed: [%d/%d]",
|
||||
len(bulkServiceChange.HostnamesToAdd),
|
||||
len(bulkServiceChange.HostnamesToRemove),
|
||||
len(bulkServiceChange.ServicesToAdd),
|
||||
len(bulkServiceChange.ServicesToRemove))
|
||||
handleBulkServiceChange(bulkServiceChange)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleBulkServiceChange(sc cziti.BulkServiceChange) {
|
||||
if len(sc.HostnamesToRemove) > 0 {
|
||||
log.Debug("removing rules from NRPT")
|
||||
windns.RemoveNrptRules(sc.HostnamesToRemove)
|
||||
log.Info("removed NRPT rules for: %v", sc.HostnamesToRemove)
|
||||
} else {
|
||||
log.Debug("bulk service change had no hostnames to remove")
|
||||
}
|
||||
|
||||
if len(sc.HostnamesToAdd) > 0 {
|
||||
log.Debug("adding rules to NRPT")
|
||||
windns.AddNrptRules(sc.HostnamesToAdd, rts.state.TunIpv4)
|
||||
log.Infof("mapped the following hostnames: %v", sc.HostnamesToAdd)
|
||||
}
|
||||
|
||||
be := dto.BulkServiceEvent{
|
||||
ActionEvent: dto.SERVICE_BULK,
|
||||
Fingerprint: sc.Fingerprint,
|
||||
AddedServices: sc.ServicesToAdd,
|
||||
RemovedServices: sc.ServicesToRemove,
|
||||
}
|
||||
|
||||
rts.BroadcastEvent(be)
|
||||
|
||||
var m = dto.IdentityEvent{
|
||||
ActionEvent: dto.IdentityUpdateComplete,
|
||||
Id: dto.Identity{
|
||||
FingerPrint: sc.Fingerprint,
|
||||
},
|
||||
}
|
||||
rts.BroadcastEvent(m)
|
||||
}
|
||||
|
||||
func handleEvents(isInitialized chan struct{}) {
|
||||
events.run()
|
||||
d := 5 * time.Second
|
||||
@@ -1027,10 +1071,10 @@ func handleEvents(isInitialized chan struct{}) {
|
||||
case <-every5s.C:
|
||||
s := rts.ToMetrics()
|
||||
|
||||
events.broadcast <- dto.MetricsEvent{
|
||||
rts.BroadcastEvent(dto.MetricsEvent{
|
||||
StatusEvent: dto.StatusEvent{Op: "metrics"},
|
||||
Identities: s.Identities,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1098,10 +1142,10 @@ func authMfa(out *json.Encoder, fingerprint string, code string) {
|
||||
|
||||
// when the log level is updated through command line, the message is broadcasted to UI and update service as well
|
||||
func sendLogLevelAndNotify(enc *json.Encoder, loglevel string) {
|
||||
events.broadcast <- dto.LogLevelEvent{
|
||||
rts.BroadcastEvent(dto.LogLevelEvent{
|
||||
ActionEvent: dto.LOGLEVEL_CHANGED,
|
||||
LogLevel: loglevel,
|
||||
}
|
||||
})
|
||||
message := fmt.Sprintf("Loglevel %s is sent to the events channel", loglevel)
|
||||
log.Info(message)
|
||||
resp := dto.Response{Message: "success", Code: SUCCESS, Error: "", Payload: message}
|
||||
@@ -1112,10 +1156,10 @@ func sendLogLevelAndNotify(enc *json.Encoder, loglevel string) {
|
||||
func sendIdentityAndNotifyUI(enc *json.Encoder, fingerprint string) {
|
||||
for _, id := range rts.ids {
|
||||
if id.FingerPrint == fingerprint {
|
||||
events.broadcast <- dto.IdentityEvent{
|
||||
rts.BroadcastEvent(dto.IdentityEvent{
|
||||
ActionEvent: dto.IDENTITY_ADDED,
|
||||
Id: id.Identity,
|
||||
}
|
||||
})
|
||||
message := fmt.Sprintf("Identity %s - %s updated message is sent to the events channel", id.Identity.Name, id.Identity.FingerPrint)
|
||||
log.Info(message)
|
||||
resp := dto.Response{Message: "success", Code: SUCCESS, Error: "", Payload: message}
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"golang.org/x/sys/windows"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
@@ -121,6 +122,7 @@ func (t *RuntimeState) ToStatus(onlyInitialized bool) dto.TunnelStatus {
|
||||
ServiceVersion: Version,
|
||||
TunIpv4: t.state.TunIpv4,
|
||||
TunIpv4Mask: t.state.TunIpv4Mask,
|
||||
AddDns: t.state.AddDns,
|
||||
}
|
||||
|
||||
i := 0
|
||||
@@ -162,7 +164,7 @@ func (t *RuntimeState) ToMetrics() dto.TunnelStatus {
|
||||
return clean
|
||||
}
|
||||
|
||||
func (t *RuntimeState) CreateTun(ipv4 string, ipv4mask int) (net.IP, *tun.Device, error) {
|
||||
func (t *RuntimeState) CreateTun(ipv4 string, ipv4mask int, applyDns bool) (net.IP, *tun.Device, error) {
|
||||
log.Infof("creating TUN device: %s", TunName)
|
||||
tunDevice, err := tun.CreateTUN(TunName, 64*1024-1)
|
||||
if err == nil {
|
||||
@@ -219,6 +221,11 @@ func (t *RuntimeState) CreateTun(ipv4 string, ipv4mask int) (net.IP, *tun.Device
|
||||
}
|
||||
log.Info("routing applied")
|
||||
|
||||
if applyDns {
|
||||
//for windows 10+, could 'domains' be able to replace NRPT? dunno - didn't test it
|
||||
luid.SetDNS(windows.AF_INET, []net.IP{ip}, nil)
|
||||
}
|
||||
|
||||
return ip, t.tun, nil
|
||||
}
|
||||
|
||||
@@ -262,10 +269,10 @@ func (t *RuntimeState) LoadIdentity(id *Id, refreshInterval int) {
|
||||
id.MfaEnabled = id.CId.MfaEnabled
|
||||
id.MfaNeeded = id.CId.MfaNeeded
|
||||
|
||||
events.broadcast <- dto.IdentityEvent{
|
||||
rts.BroadcastEvent(dto.IdentityEvent{
|
||||
ActionEvent: dto.IDENTITY_ADDED,
|
||||
Id: id.Identity,
|
||||
}
|
||||
})
|
||||
log.Infof("connecting identity completed: %s[%s] %t/%t", id.Name, id.FingerPrint, id.MfaEnabled, id.MfaNeeded)
|
||||
}
|
||||
|
||||
@@ -477,6 +484,9 @@ func (t *RuntimeState) ReleaseIP() {
|
||||
}
|
||||
|
||||
func (t *RuntimeState) BroadcastEvent(event interface{}) {
|
||||
if len(events.broadcast) == cap(events.broadcast) {
|
||||
log.Warn("event channel is full and is about to block!")
|
||||
}
|
||||
events.broadcast <- event
|
||||
}
|
||||
|
||||
|
||||
@@ -19,23 +19,23 @@ package service
|
||||
|
||||
type topic struct {
|
||||
broadcast chan interface{}
|
||||
channels map[int]chan interface{}
|
||||
channels map[string]chan interface{}
|
||||
done chan bool
|
||||
}
|
||||
|
||||
func newTopic(cap int16) topic {
|
||||
return topic{
|
||||
broadcast: make(chan interface{}, cap),
|
||||
channels: make(map[int]chan interface{}, cap),
|
||||
channels: make(map[string]chan interface{}, cap),
|
||||
done: make(chan bool, cap),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *topic) register(id int, c chan interface{}) {
|
||||
func (t *topic) register(id string, c chan interface{}) {
|
||||
t.channels[id] = c
|
||||
}
|
||||
|
||||
func (t *topic) unregister(id int) {
|
||||
func (t *topic) unregister(id string) {
|
||||
delete(t.channels, id)
|
||||
}
|
||||
|
||||
@@ -48,7 +48,10 @@ func (t *topic) run() {
|
||||
for {
|
||||
select {
|
||||
case msg := <-t.broadcast:
|
||||
for _, c := range t.channels {
|
||||
for id, c := range t.channels {
|
||||
if len(c) == cap(c) {
|
||||
log.Warnf("channel with id [%s] is about to block!", id)
|
||||
}
|
||||
c <- msg
|
||||
}
|
||||
break
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
package main
|
||||
|
||||
const (
|
||||
Version = "1.9.2"
|
||||
Revision = "4e9875920983"
|
||||
Branch = "main"
|
||||
Version = "1.9.3"
|
||||
Revision = "b6361cdb1b8d"
|
||||
Branch = "release-next"
|
||||
BuildUser = ""
|
||||
BuildDate = "2021-04-08 11:05:00"
|
||||
BuildDate = "2021-04-12 17:20:21"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user