Projects STRLCPY NETworkManager Commits 5d841373
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■
    Source/NETworkManager/ViewModels/SNMPViewModel.cs
    skipped 5 lines
    6 6  using System.Collections.Generic;
    7 7  using System.Collections.ObjectModel;
    8 8  using System.ComponentModel;
    9  -using System.Diagnostics;
    10 9  using System.Linq;
    11 10  using System.Net;
    12  -using System.Net.Sockets;
    13 11  using System.Windows;
    14 12  using System.Windows.Data;
    15 13  using System.Windows.Input;
    skipped 5 lines
    21 19  using MahApps.Metro.Controls.Dialogs;
    22 20  using NETworkManager.Models.Export;
    23 21  using NETworkManager.Views;
     22 +using System.Security;
    24 23   
    25 24  namespace NETworkManager.ViewModels
    26 25  {
    skipped 95 lines
    122 121   }
    123 122   }
    124 123   
    125  - private string _community;
    126  - public string Community
     124 + private bool _isCommunityEmpty = true; // Initial it's empty
     125 + public bool IsCommunityEmpty
     126 + {
     127 + get => _isCommunityEmpty;
     128 + set
     129 + {
     130 + if (value == _isCommunityEmpty)
     131 + return;
     132 + 
     133 + _isCommunityEmpty = value;
     134 + OnPropertyChanged();
     135 + }
     136 + }
     137 + 
     138 + private SecureString _community;
     139 + public SecureString Community
    127 140   {
    128 141   get => _community;
    129 142   set
    130 143   {
    131 144   if (value == _community)
    132 145   return;
     146 + 
     147 + // Validate the community string
     148 + if (value == null)
     149 + IsCommunityEmpty = true;
     150 + else
     151 + IsCommunityEmpty = string.IsNullOrEmpty(SecureStringHelper.ConvertToString(value));
    133 152   
    134 153   _community = value;
    135 154   OnPropertyChanged();
    skipped 33 lines
    169 188   }
    170 189   }
    171 190   
    172  - private string _auth;
    173  - public string Auth
     191 + private bool _isAuthEmpty = true; // Initial it's empty
     192 + public bool IsAuthEmpty
     193 + {
     194 + get => _isAuthEmpty;
     195 + set
     196 + {
     197 + if (value == _isAuthEmpty)
     198 + return;
     199 + 
     200 + _isAuthEmpty = value;
     201 + OnPropertyChanged();
     202 + }
     203 + }
     204 +
     205 + private SecureString _auth;
     206 + public SecureString Auth
    174 207   {
    175 208   get => _auth;
    176 209   set
    177 210   {
    178 211   if (value == _auth)
    179 212   return;
     213 + 
     214 + // Validate the auth string
     215 + if (value == null)
     216 + IsAuthEmpty = true;
     217 + else
     218 + IsAuthEmpty = string.IsNullOrEmpty(SecureStringHelper.ConvertToString(value));
    180 219   
    181 220   _auth = value;
    182 221   OnPropertyChanged();
    skipped 19 lines
    202 241   }
    203 242   }
    204 243   
    205  - private string _priv;
    206  - public string Priv
     244 + private bool _isPrivEmpty = true; // Initial it's empty
     245 + public bool IsPrivEmpty
     246 + {
     247 + get => _isPrivEmpty;
     248 + set
     249 + {
     250 + if (value == _isPrivEmpty)
     251 + return;
     252 + 
     253 + _isPrivEmpty = value;
     254 + OnPropertyChanged();
     255 + }
     256 + }
     257 + 
     258 + private SecureString _priv;
     259 + public SecureString Priv
    207 260   {
    208 261   get => _priv;
    209 262   set
    210 263   {
    211 264   if (value == _priv)
    212 265   return;
     266 + 
     267 + // Validate the auth string
     268 + if (value == null)
     269 + IsPrivEmpty = true;
     270 + else
     271 + IsPrivEmpty = string.IsNullOrEmpty(SecureStringHelper.ConvertToString(value));
    213 272   
    214 273   _priv = value;
    215 274   OnPropertyChanged();
    skipped 332 lines
    548 607   Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(delegate
    549 608   {
    550 609   //lock (QueryResults)
    551  - QueryResults.Add(snmpReceivedInfo);
     610 + QueryResults.Add(snmpReceivedInfo);
    552 611   }));
    553 612   }
    554 613   
    skipped 43 lines
  • ■ ■ ■ ■ ■ ■
    Source/NETworkManager/Views/SNMPView.xaml
    skipped 12 lines
    13 13   xmlns:localization="clr-namespace:NETworkManager.Localization.Resources;assembly=NETworkManager.Localization"
    14 14   xmlns:dialogs="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
    15 15   xmlns:controls="clr-namespace:NETworkManager.Controls;assembly=NETworkManager.Controls"
     16 + xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
     17 + xmlns:interactivity="http://schemas.microsoft.com/xaml/behaviors"
    16 18   dialogs:DialogParticipation.Register="{Binding}"
    17 19   mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:SNMPViewModel}">
    18 20   <UserControl.Resources>
    skipped 77 lines
    96 98   </Style>
    97 99   </TextBlock.Style>
    98 100   </TextBlock>
    99  - <TextBox Grid.Column="8" Grid.Row="2" Grid.ColumnSpan="5" Name="TextBoxCommunity" mah:TextBoxHelper.Watermark="{x:Static localization:StaticStrings.ExampleSNMPCommunity}" IsEnabled="{Binding IsWorking, Converter={StaticResource BooleanReverseConverter}}">
    100  - <TextBox.Style>
    101  - <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource DefaultTextBox}">
     101 + <PasswordBox Grid.Column="8" Grid.Row="2" Grid.ColumnSpan="5" Name="PasswordBoxCommunity" mah:TextBoxHelper.Watermark="{x:Static localization:StaticStrings.ExampleSNMPCommunity}" IsEnabled="{Binding IsWorking, Converter={StaticResource BooleanReverseConverter}}">
     102 + <PasswordBox.Style>
     103 + <Style TargetType="{x:Type PasswordBox}" BasedOn="{StaticResource DefaultPasswordBox}">
    102 104   <Setter Property="Visibility" Value="Visible" />
    103 105   <Style.Triggers>
    104 106   <DataTrigger Binding="{Binding Version}" Value="v3">
    skipped 1 lines
    106 108   </DataTrigger>
    107 109   </Style.Triggers>
    108 110   </Style>
    109  - </TextBox.Style>
    110  - <TextBox.Text>
    111  - <Binding Path="Community" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
    112  - <Binding.ValidationRules>
    113  - <validators:EmptyValidator ValidatesOnTargetUpdated="True" />
    114  - </Binding.ValidationRules>
    115  - </Binding>
    116  - </TextBox.Text>
    117  - </TextBox>
     111 + </PasswordBox.Style>
     112 + <interactivity:Interaction.Behaviors>
     113 + <wpfHelpers:PasswordBoxBindingBehavior Password="{Binding Community, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
     114 + </interactivity:Interaction.Behaviors>
     115 + </PasswordBox>
    118 116   <TextBlock Grid.Column="6" Grid.Row="2" Text="{x:Static localization:Strings.Security}">
    119 117   <TextBlock.Style>
    120 118   <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource CenterTextBlock}">
    skipped 103 lines
    224 222   </Style>
    225 223   </ComboBox.Style>
    226 224   </ComboBox>
    227  - <TextBox Grid.Column="4" Grid.Row="3" Name="TextBoxAuth" IsEnabled="{Binding IsWorking, Converter={StaticResource BooleanReverseConverter}}" Margin="0,10,0,0">
    228  - <TextBox.Style>
    229  - <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource DefaultTextBox}">
     225 + <PasswordBox Grid.Column="4" Grid.Row="3" Name="PasswordBoxAuth" IsEnabled="{Binding IsWorking, Converter={StaticResource BooleanReverseConverter}}" Margin="0,10,0,0">
     226 + <PasswordBox.Style>
     227 + <Style TargetType="{x:Type PasswordBox}" BasedOn="{StaticResource DefaultPasswordBox}">
    230 228   <Setter Property="Visibility" Value="Collapsed" />
    231 229   <Style.Triggers>
    232 230   <MultiDataTrigger>
    skipped 16 lines
    249 247   </MultiDataTrigger>
    250 248   </Style.Triggers>
    251 249   </Style>
    252  - </TextBox.Style>
    253  - <TextBox.Text>
    254  - <Binding Path="Auth" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
    255  - <Binding.ValidationRules>
    256  - <validators:EmptyValidator ValidatesOnTargetUpdated="True" />
    257  - </Binding.ValidationRules>
    258  - </Binding>
    259  - </TextBox.Text>
    260  - </TextBox>
     250 + </PasswordBox.Style>
     251 + <interactivity:Interaction.Behaviors>
     252 + <wpfHelpers:PasswordBoxBindingBehavior Password="{Binding Auth, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
     253 + </interactivity:Interaction.Behaviors>
     254 + </PasswordBox>
    261 255   <TextBlock Grid.Column="6" Grid.Row="3" Text="{x:Static localization:Strings.Priv}" Margin="0,10,0,0">
    262 256   <TextBlock.Style>
    263 257   <Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource CenterTextBlock}">
    skipped 30 lines
    294 288   </Style>
    295 289   </ComboBox.Style>
    296 290   </ComboBox>
    297  - <TextBox Grid.Column="10" Grid.ColumnSpan="3" Grid.Row="3" Name="TextBoxPriv" IsEnabled="{Binding IsWorking, Converter={StaticResource BooleanReverseConverter}}" Margin="0,10,0,0">
    298  - <TextBox.Style>
    299  - <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource DefaultTextBox}">
     291 + <PasswordBox Grid.Column="10" Grid.ColumnSpan="3" Grid.Row="3" Name="PasswordBoxPriv" IsEnabled="{Binding IsWorking, Converter={StaticResource BooleanReverseConverter}}" Margin="0,10,0,0">
     292 + <PasswordBox.Style>
     293 + <Style TargetType="{x:Type PasswordBox}" BasedOn="{StaticResource DefaultPasswordBox}">
    300 294   <Setter Property="Visibility" Value="Collapsed" />
    301 295   <Style.Triggers>
    302 296   <MultiDataTrigger>
    skipped 7 lines
    310 304   </MultiDataTrigger>
    311 305   </Style.Triggers>
    312 306   </Style>
    313  - </TextBox.Style>
    314  - <TextBox.Text>
    315  - <Binding Path="Priv" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
    316  - <Binding.ValidationRules>
    317  - <validators:EmptyValidator ValidatesOnTargetUpdated="True" />
    318  - <validators:PrivacyAESValidator ValidatesOnTargetUpdated="True" />
    319  - </Binding.ValidationRules>
    320  - </Binding>
    321  - </TextBox.Text>
    322  - </TextBox>
     307 + </PasswordBox.Style>
     308 + <interactivity:Interaction.Behaviors>
     309 + <wpfHelpers:PasswordBoxBindingBehavior Password="{Binding Priv, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
     310 + </interactivity:Interaction.Behaviors>
     311 + </PasswordBox>
    323 312   </Grid>
    324 313   <!-- ReSharper disable once Xaml.MissingGridIndex, in Resources -->
    325 314   <Button x:Name="ButtonQuery" Grid.Column="2" Command="{Binding WorkCommand}" IsDefault="{Binding IsWorking, Converter={StaticResource BooleanReverseConverter}}" IsCancel="{Binding IsWorking}" VerticalAlignment="Bottom">
    skipped 12 lines
    338 327   <Condition Binding="{Binding Version}" Value="v1" />
    339 328   <Condition Binding="{Binding ElementName=ComboBoxHost, Path=(Validation.HasError)}" Value="False" />
    340 329   <Condition Binding="{Binding ElementName=ComboBoxOID, Path=(Validation.HasError)}" Value="False" />
    341  - <Condition Binding="{Binding ElementName=TextBoxCommunity, Path=(Validation.HasError)}" Value="False" />
     330 + <Condition Binding="{Binding IsCommunityEmpty}" Value="False" />
    342 331   <Condition Binding="{Binding IsWorking}" Value="False" />
    343 332   </MultiDataTrigger.Conditions>
    344 333   <MultiDataTrigger.Setters>
    skipped 5 lines
    350 339   <Condition Binding="{Binding Version}" Value="v2c" />
    351 340   <Condition Binding="{Binding ElementName=ComboBoxHost, Path=(Validation.HasError)}" Value="False" />
    352 341   <Condition Binding="{Binding ElementName=ComboBoxOID, Path=(Validation.HasError)}" Value="False" />
    353  - <Condition Binding="{Binding ElementName=TextBoxCommunity, Path=(Validation.HasError)}" Value="False" />
     342 + <Condition Binding="{Binding IsCommunityEmpty}" Value="False" />
    354 343   <Condition Binding="{Binding IsWorking}" Value="False" />
    355 344   </MultiDataTrigger.Conditions>
    356 345   <MultiDataTrigger.Setters>
    skipped 20 lines
    377 366   <Condition Binding="{Binding ElementName=ComboBoxHost, Path=(Validation.HasError)}" Value="False" />
    378 367   <Condition Binding="{Binding ElementName=ComboBoxOID, Path=(Validation.HasError)}" Value="False" />
    379 368   <Condition Binding="{Binding ElementName=TextBoxUsername, Path=(Validation.HasError)}" Value="False" />
    380  - <Condition Binding="{Binding ElementName=TextBoxAuth, Path=(Validation.HasError)}" Value="False" />
     369 + <Condition Binding="{Binding IsAuthEmpty}" Value="False" />
    381 370   <Condition Binding="{Binding IsWorking}" Value="False" />
    382 371   </MultiDataTrigger.Conditions>
    383 372   <MultiDataTrigger.Setters>
    skipped 7 lines
    391 380   <Condition Binding="{Binding ElementName=ComboBoxHost, Path=(Validation.HasError)}" Value="False" />
    392 381   <Condition Binding="{Binding ElementName=ComboBoxOID, Path=(Validation.HasError)}" Value="False" />
    393 382   <Condition Binding="{Binding ElementName=TextBoxUsername, Path=(Validation.HasError)}" Value="False" />
    394  - <Condition Binding="{Binding ElementName=TextBoxAuth, Path=(Validation.HasError)}" Value="False" />
    395  - <Condition Binding="{Binding ElementName=TextBoxPriv, Path=(Validation.HasError)}" Value="False" />
     383 + <Condition Binding="{Binding IsAuthEmpty}" Value="False" />
     384 + <Condition Binding="{Binding IsPrivEmpty}" Value="False" />
    396 385   <Condition Binding="{Binding IsWorking}" Value="False" />
    397 386   </MultiDataTrigger.Conditions>
    398 387   <MultiDataTrigger.Setters>
    skipped 176 lines
  • ■ ■ ■ ■ ■ ■
    Source/NETworkManager.Models/Network/SNMP.cs
    1 1  using Lextm.SharpSnmpLib;
    2 2  using Lextm.SharpSnmpLib.Messaging;
    3 3  using Lextm.SharpSnmpLib.Security;
     4 +using NETworkManager.Utilities;
    4 5  using System;
    5 6  using System.Collections.Generic;
    6 7  using System.Net;
     8 +using System.Security;
    7 9  using System.Threading.Tasks;
    8 10   
    9 11  namespace NETworkManager.Models.Network
    skipped 43 lines
    53 55   #endregion
    54 56   
    55 57   #region Methods
    56  - public void GetV1V2CAsync(SNMPVersion version, IPAddress ipAddress, string community, string oid)
     58 + public void GetV1V2CAsync(SNMPVersion version, IPAddress ipAddress, SecureString community, string oid)
    57 59   {
    58 60   Task.Run(() =>
    59 61   {
    60 62   try
    61 63   {
    62  - foreach (var result in Messenger.Get(version == SNMPVersion.V1 ? VersionCode.V1 : VersionCode.V2, new IPEndPoint(ipAddress, Port), new OctetString(community), new List<Variable> { new Variable(new ObjectIdentifier(oid)) }, Timeout))
     64 + foreach (var result in Messenger.Get(version == SNMPVersion.V1 ? VersionCode.V1 : VersionCode.V2, new IPEndPoint(ipAddress, Port), new OctetString(SecureStringHelper.ConvertToString(community)), new List<Variable> { new Variable(new ObjectIdentifier(oid)) }, Timeout))
    63 65   OnReceived(new SNMPReceivedArgs(result.Id, result.Data));
    64 66   
    65 67   OnComplete();
    skipped 9 lines
    75 77   });
    76 78   }
    77 79   
    78  - public void WalkV1V2CAsync(SNMPVersion version, IPAddress ipAddress, string community, string oid, WalkMode walkMode)
     80 + public void WalkV1V2CAsync(SNMPVersion version, IPAddress ipAddress, SecureString community, string oid, WalkMode walkMode)
    79 81   {
    80 82   Task.Run(() =>
    81 83   {
    skipped 1 lines
    83 85   {
    84 86   IList<Variable> results = new List<Variable>();
    85 87   
    86  - Messenger.Walk(version == SNMPVersion.V1 ? VersionCode.V1 : VersionCode.V2, new IPEndPoint(ipAddress, Port), new OctetString(community), new ObjectIdentifier(oid), results, Timeout, walkMode);
     88 + Messenger.Walk(version == SNMPVersion.V1 ? VersionCode.V1 : VersionCode.V2, new IPEndPoint(ipAddress, Port), new OctetString(SecureStringHelper.ConvertToString(community)), new ObjectIdentifier(oid), results, Timeout, walkMode);
    87 89   
    88 90   foreach (var result in results)
    89 91   OnReceived(new SNMPReceivedArgs(result.Id, result.Data));
    skipped 11 lines
    101 103   });
    102 104   }
    103 105   
    104  - public void SetV1V2CAsync(SNMPVersion version, IPAddress ipAddress, string communtiy, string oid, string data)
     106 + public void SetV1V2CAsync(SNMPVersion version, IPAddress ipAddress, SecureString communtiy, string oid, string data)
    105 107   {
    106 108   Task.Run(() =>
    107 109   {
    108 110   try
    109 111   {
    110  - Messenger.Set(version == SNMPVersion.V1 ? VersionCode.V1 : VersionCode.V2, new IPEndPoint(ipAddress, Port), new OctetString(communtiy), new List<Variable> { new Variable(new ObjectIdentifier(oid), new OctetString(data)) }, Timeout);
     112 + Messenger.Set(version == SNMPVersion.V1 ? VersionCode.V1 : VersionCode.V2, new IPEndPoint(ipAddress, Port), new OctetString(SecureStringHelper.ConvertToString(communtiy)), new List<Variable> { new Variable(new ObjectIdentifier(oid), new OctetString(data)) }, Timeout);
    111 113   
    112 114   OnComplete();
    113 115   }
    skipped 8 lines
    122 124   });
    123 125   }
    124 126   
    125  - public void Getv3Async(IPAddress ipAddress, string oid, SNMPV3Security security, string username, SNMPV3AuthenticationProvider authProvider, string auth, SNMPV3PrivacyProvider privProvider, string priv)
     127 + public void Getv3Async(IPAddress ipAddress, string oid, SNMPV3Security security, string username, SNMPV3AuthenticationProvider authProvider, SecureString auth, SNMPV3PrivacyProvider privProvider, SecureString priv)
    126 128   {
    127 129   Task.Run(() =>
    128 130   {
    skipped 10 lines
    139 141   switch (security)
    140 142   {
    141 143   case SNMPV3Security.AuthPriv:
    142  - privacy = GetPrivacy(authProvider, auth, privProvider, priv);
     144 + privacy = GetPrivacy(authProvider, SecureStringHelper.ConvertToString(auth), privProvider, SecureStringHelper.ConvertToString(priv));
    143 145   break;
    144 146   // noAuthNoPriv
    145 147   case SNMPV3Security.AuthNoPriv:
    146  - privacy = GetPrivacy(authProvider, auth);
     148 + privacy = GetPrivacy(authProvider, SecureStringHelper.ConvertToString(auth));
    147 149   break;
    148 150   default:
    149 151   privacy = GetPrivacy();
    skipped 20 lines
    170 172   });
    171 173   }
    172 174   
    173  - public void WalkV3Async(IPAddress ipAddress, string oid, SNMPV3Security security, string username, SNMPV3AuthenticationProvider authProvider, string auth, SNMPV3PrivacyProvider privProvider, string priv, WalkMode walkMode)
     175 + public void WalkV3Async(IPAddress ipAddress, string oid, SNMPV3Security security, string username, SNMPV3AuthenticationProvider authProvider, SecureString auth, SNMPV3PrivacyProvider privProvider, SecureString priv, WalkMode walkMode)
    174 176   {
    175 177   Task.Run(() =>
    176 178   {
    skipped 10 lines
    187 189   switch (security)
    188 190   {
    189 191   case SNMPV3Security.AuthPriv:
    190  - privacy = GetPrivacy(authProvider, auth, privProvider, priv);
     192 + privacy = GetPrivacy(authProvider, SecureStringHelper.ConvertToString(auth), privProvider, SecureStringHelper.ConvertToString(priv));
    191 193   break;
    192 194   // noAuthNoPriv
    193 195   case SNMPV3Security.AuthNoPriv:
    194  - privacy = GetPrivacy(authProvider, auth);
     196 + privacy = GetPrivacy(authProvider, SecureStringHelper.ConvertToString(auth));
    195 197   break;
    196 198   default:
    197 199   privacy = GetPrivacy();
    skipped 20 lines
    218 220   });
    219 221   }
    220 222   
    221  - public void SetV3Async(IPAddress ipAddress, string oid, SNMPV3Security security, string username, SNMPV3AuthenticationProvider authProvider, string auth, SNMPV3PrivacyProvider privProvider, string priv, string data)
     223 + public void SetV3Async(IPAddress ipAddress, string oid, SNMPV3Security security, string username, SNMPV3AuthenticationProvider authProvider, SecureString auth, SNMPV3PrivacyProvider privProvider, SecureString priv, string data)
    222 224   {
    223 225   Task.Run(() =>
    224 226   {
    skipped 10 lines
    235 237   switch (security)
    236 238   {
    237 239   case SNMPV3Security.AuthPriv:
    238  - privacy = GetPrivacy(authProvider, auth, privProvider, priv);
     240 + privacy = GetPrivacy(authProvider, SecureStringHelper.ConvertToString(auth), privProvider, SecureStringHelper.ConvertToString(priv));
    239 241   break;
    240 242   // noAuthNoPriv
    241 243   case SNMPV3Security.AuthNoPriv:
    242  - privacy = GetPrivacy(authProvider, auth);
     244 + privacy = GetPrivacy(authProvider, SecureStringHelper.ConvertToString(auth));
    243 245   break;
    244 246   default:
    245 247   privacy = GetPrivacy();
    skipped 95 lines
  • ■ ■ ■ ■ ■ ■
    Source/NETworkManager.Validators/PrivacyAESValidator.cs
    1  -using System.Globalization;
    2  -using System.Windows.Controls;
    3  - 
    4  -namespace NETworkManager.Validators
    5  -{
    6  - public class PrivacyAESValidator : ValidationRule
    7  - {
    8  - public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    9  - {
    10  - return value != null && ((string) value).Length < 8 ? new ValidationResult(false, Localization.Resources.Strings.KeyMustHave8CharactersOrMore) : ValidationResult.ValidResult;
    11  - }
    12  - }
    13  -}
    14  - 
  • ■ ■ ■ ■ ■ ■
    docs/04_Changelog.md
    skipped 19 lines
    20 20  - Korean language added [#584](https://github.com/BornToBeRoot/NETworkManager/issues/584){:target="_blank"}
    21 21   
    22 22  ## Improvements
     23 +- SNMP Community/Priv/Auth text boxes replaced with password boxes [#128](https://github.com/BornToBeRoot/NETworkManager/issues/128){:target="_blank"}
    23 24   
    24 25  ## Bugfixes
    25 26  - Profile dialog height fixed [#594](https://github.com/BornToBeRoot/NETworkManager/issues/594){:target="_blank"}
    26 27  - Dialog button FontSize fixed [MahApps/MahApps.Metro#594](https://github.com/MahApps/MahApps.Metro/issues/4069){:target="_blank"}
    27 28  - ContextMenu sub menu border brush fixed [#324](https://github.com/BornToBeRoot/NETworkManager/issues/324){:target="_blank"}
    28 29  - Design of some buttons fixed [#591](https://github.com/BornToBeRoot/NETworkManager/issues/591){:target="_blank"}
     30 +- SNMP v3 priv min length removed due to a change in the lib [#128](https://github.com/BornToBeRoot/NETworkManager/issues/128){:target="_blank"}
    29 31   
    30 32  ## Other
    31 33  - Code refactored / cleanup
    skipped 488 lines
Please wait...
Page is in error, reload to recover