diff --git a/SuperLauncher/CredentialExpirationService.cs b/SuperLauncher/CredentialExpirationService.cs index a2a905f..f2b1b16 100644 --- a/SuperLauncher/CredentialExpirationService.cs +++ b/SuperLauncher/CredentialExpirationService.cs @@ -8,14 +8,18 @@ namespace SuperLauncher { public static class CredentialExpirationService { - private static Timer Timer = new(); + private static Timer CheckTimer = new(); + private static Timer NotifyTimer = new(); public static DateTime PasswordLastSet = DateTime.MaxValue; - public static TimeSpan MaxPasswordAge = TimeSpan.MaxValue; + public static TimeSpan MaxPasswordAge = TimeSpan.Zero; + private static ExpStat Status = ExpStat.Unknown; public static string PasswordExpirationMessage { get { - return + if (Status == ExpStat.NeverExpires) return "Password never expires."; + if (Status == ExpStat.DCNotResponding) return "Could not determine password expiration date, Active Directory is offline."; + if (Status == ExpStat.Expires) return "Password expires in " + ExpirationTimeSpan.Days + " day(s), " + @@ -23,6 +27,7 @@ public static string PasswordExpirationMessage " hour(s) and " + ExpirationTimeSpan.Seconds + " second(s)."; + return "An un-known error occured when determining your password expiration date."; } } public static DateTime PasswordExpirationDate @@ -41,45 +46,68 @@ public static TimeSpan ExpirationTimeSpan } public static void Initialize() { - Timer.Elapsed += CheckExpiration; - Timer.Enabled = true; - Timer.Interval = 10800000; //3 hours - Timer.Start(); - CheckExpiration(); + Task.Run(() => { + CheckTimer.Elapsed += CheckTimer_Elapsed; + CheckTimer.Enabled = true; + CheckTimer.Interval = TimeSpan.FromMinutes(5).TotalMilliseconds; + CheckTimer.Start(); + CheckTimer_Elapsed(null, null); + if (Settings.Default.CredentialExpirationWarningIntervalMinutes <= 0) return; + NotifyTimer.Elapsed += NotifyTimer_Elapsed; + NotifyTimer.Enabled = true; + NotifyTimer.Interval = TimeSpan.FromMinutes(Settings.Default.CredentialExpirationWarningIntervalMinutes).TotalMilliseconds; + NotifyTimer.Start(); + NotifyTimer_Elapsed(null, null); + }); } - public static void CheckExpiration(object s = null, object e = null) + private static void NotifyTimer_Elapsed(object sender, ElapsedEventArgs e) { - Task.Run(() => { - try - { - DirectorySearcher ds = new(); - ds.SearchScope = SearchScope.Base; - ds.PropertiesToLoad.Clear(); - ds.PropertiesToLoad.Add("maxPwdAge"); - ds.Filter = ""; - SearchResult root = ds.FindOne(); - ds.SearchScope = SearchScope.Subtree; - ds.PropertiesToLoad.Clear(); - ds.PropertiesToLoad.Add("userAccountControl"); - ds.PropertiesToLoad.Add("pwdLastSet"); - ds.Filter = "(objectSid=" + WindowsIdentity.GetCurrent().User.Value + ")"; - SearchResult user = ds.FindOne(); - bool pwdNeverExpires = (((int)user.Properties["userAccountControl"][0]) & 0x00010000) == 0x00010000; //https://learn.microsoft.com/en-us/windows/win32/api/iads/ne-iads-ads_user_flag_enum - PasswordLastSet = DateTime.FromFileTime((long)user.Properties["pwdLastSet"][0]); - MaxPasswordAge = TimeSpan.FromMicroseconds((long)root.Properties["maxPwdAge"][0] / 10 * -1); - ModernLauncherNotifyIcon.Icon.BalloonTipTitle = RunAsHelper.GetCurrentDomainWithUserName(); - ModernLauncherNotifyIcon.Icon.BalloonTipText = PasswordExpirationMessage; - ModernLauncherNotifyIcon.Icon.ShowBalloonTip(0); - } - catch + if (PasswordExpirationDate.CompareTo(DateTime.Now.AddDays(Settings.Default.CredentialExpirationWarningDays)) <= 0) + { + ModernLauncherNotifyIcon.Icon.BalloonTipTitle = RunAsHelper.GetCurrentDomainWithUserName(); + ModernLauncherNotifyIcon.Icon.BalloonTipText = PasswordExpirationMessage; + ModernLauncherNotifyIcon.Icon.ShowBalloonTip(0); + } + } + private static void CheckTimer_Elapsed(object sender, ElapsedEventArgs e) + { + try + { + DirectorySearcher ds = new(); + ds.SearchScope = SearchScope.Base; + ds.PropertiesToLoad.Clear(); + ds.PropertiesToLoad.Add("maxPwdAge"); + ds.Filter = ""; + SearchResult root = ds.FindOne(); + MaxPasswordAge = TimeSpan.FromMicroseconds((long)root.Properties["maxPwdAge"][0] / 10 * -1); + if (MaxPasswordAge == TimeSpan.Zero) { Status = ExpStat.NeverExpires; return; } + ds.SearchScope = SearchScope.Subtree; + ds.PropertiesToLoad.Clear(); + ds.PropertiesToLoad.Add("userAccountControl"); + ds.PropertiesToLoad.Add("pwdLastSet"); + ds.Filter = "(objectSid=" + WindowsIdentity.GetCurrent().User.Value + ")"; + SearchResult user = ds.FindOne(); + PasswordLastSet = DateTime.FromFileTime((long)user.Properties["pwdLastSet"][0]); + bool pwdNeverExpires = (((int)user.Properties["userAccountControl"][0]) & 0x00010000) == 0x00010000; //https://learn.microsoft.com/en-us/windows/win32/api/iads/ne-iads-ads_user_flag_enum + if (pwdNeverExpires == true) { Status = ExpStat.NeverExpires; return; } + Status = ExpStat.Expires; + } + catch (Exception ex) + { + if (ex.Source == "System.DirectoryServices") { - //Just give up + Status = ExpStat.DCNotResponding; + return; } - }); + Status = ExpStat.Unknown; + } + } + private enum ExpStat + { + Expires = 0, + NeverExpires = 1, + DCNotResponding = 2, + Unknown = -1 } - //private static datetime convertfromadtime() - //{ - - //} } -} +} \ No newline at end of file diff --git a/SuperLauncher/Settings.cs b/SuperLauncher/Settings.cs index df0d5c6..e7098ae 100644 --- a/SuperLauncher/Settings.cs +++ b/SuperLauncher/Settings.cs @@ -28,6 +28,7 @@ class SettingsDefault " 390" + " 230" + " 7" + + " 60" + ""; public bool AutoElevate { @@ -117,6 +118,17 @@ public int CredentialExpirationWarningDays Write("CredentialExpirationWarningDays", value); } } + public int CredentialExpirationWarningIntervalMinutes + { + get + { + return ReadInt("CredentialExpirationWarningIntervalMinutes"); + } + set + { + Write("CredentialExpirationWarningIntervalMinutes", value); + } + } public string Read(string NodeName) { XmlNode node = XDoc.SelectSingleNode("/SuperLauncher/" + NodeName);