Skip to content

Commit

Permalink
Merge pull request #34 from prettyokay-software/password-change
Browse files Browse the repository at this point in the history
Add password change functionality
  • Loading branch information
krisdb2009 authored May 24, 2024
2 parents 24b2bc8 + a5e3845 commit 586e6ac
Show file tree
Hide file tree
Showing 11 changed files with 346 additions and 9 deletions.
106 changes: 106 additions & 0 deletions SuperLauncher/AccountInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using System;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;

namespace SuperLauncher
{
public static class AccountInfo
{
// When was last notification sent?
private static DateTime lastExpirationNotify = DateTime.MinValue;
// Save this to avoid polling every time the tooltip is opened
public static DateTime ExpirationDate;

/// <summary>
/// Get date from Active Directory when password expires
/// </summary>
/// <returns></returns>
public static DateTime GetPasswordExpirationDate()
{
using (var userEntry = new DirectoryEntry("WinNT://" + Environment.UserDomainName + '/' + Environment.UserName + ",user"))
{

DateTime time = (DateTime)userEntry.InvokeGet("PasswordExpirationDate");
return time.ToLocalTime();
}
}

// This gets the account expiration, not the password expiration
//public static DateTime GetPasswordExpirationDate()
//{
// using PrincipalContext pc = new PrincipalContext(ContextType.Domain);
// using UserPrincipal user = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, Environment.UserName);

// DateTime time = (DateTime)user.AccountExpirationDate;
// return time.ToLocalTime();
//}

/// <summary>
/// Get the number of whole days until the password of the user running the application expires
/// </summary>
public static int GetPasswordExpirationDays()
{
return (GetPasswordExpirationDate() - DateTime.Now).Days;
}

/// <summary>
/// Check whether the provided password is correct for the current user
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
///
// Unneeded when using System.DirectoryServices.AccountManagement.ChangePassword below
public static bool ValidatePassword(string password)
{
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain))
{
// validate the credentials
bool isValid = pc.ValidateCredentials(Environment.UserName, password);
return isValid;
}
}

public static string ChangePassword(string currentPassword, string newPassword)
{
try
{
using PrincipalContext pc = new PrincipalContext(ContextType.Domain);
using UserPrincipal user = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, Environment.UserName);
user.ChangePassword(currentPassword, newPassword);
user.Save();

return "Success";
}
catch (PasswordException ep)
{
return ep.Message;
}
catch (Exception ex)
{
return ex.Message;
}
}

public static void AccountMonitorTask(Object source, System.Timers.ElapsedEventArgs e)
{
// Update saved expiration date
ExpirationDate = GetPasswordExpirationDate();

NotifyExpiration(GetPasswordExpirationDays());
}

/// <summary>
/// Notify at startup and every 12 hours
/// </summary>
/// <param name="daysRemain">number of days before password expires</param>
public static void NotifyExpiration(int daysRemain)
{
//(daysRemain <= 10) &&
if ((daysRemain <= 10) && (lastExpirationNotify.AddHours(12) < DateTime.Now))
{
Shared.SendDesktopToast("Password Expiration", $"The password for {Environment.UserName} expires in {daysRemain} days");
lastExpirationNotify = DateTime.Now;
}
}
}
}
6 changes: 3 additions & 3 deletions SuperLauncher/ModernLauncher.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<Grid Background="{DynamicResource AcrylicNoise}">
<Label HorizontalAlignment="Left" Foreground="{DynamicResource TextColorBrush}" Margin="4,3,0,2" Width="26" Content="0" FontSize="16" FontFamily="{DynamicResource SLIcons}" RenderTransformOrigin="0.471,0.46" />
<Label Content="Super Launcher" Foreground="{DynamicResource TextColorBrush}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="29,0,0,0" Width="94" />
<Label x:Name="ElevateUser" Content="domain\user" Foreground="{DynamicResource TextColorBrush}" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,30,0" />
<Label x:Name="ElevateUser" Content="domain\user" Foreground="{DynamicResource TextColorBrush}" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,30,0" Focusable="True" MouseLeftButtonUp="ElevateUser_MouseLeftButtonUp" WindowChrome.IsHitTestVisibleInChrome="True"/>
<Label x:Name="ElevateIcon" Content="" Foreground="{DynamicResource TextColorBrush}" FontFamily="{DynamicResource Icons}" VerticalAlignment="Center" HorizontalAlignment="Right" FontSize="16" Margin="0,0,5,0" />
</Grid>
</Border>
Expand All @@ -59,8 +59,8 @@
<TextBox x:Name="Filter" Tag="" VerticalAlignment="Center" Height="28" Margin="15,0,187,0" TextChanged="Filter_TextChanged" KeyDown="Filter_KeyDown" />
<Button x:Name="BtnAdd" Content="" Margin="0,15,144,0" VerticalAlignment="Top" HorizontalAlignment="Right" Width="28" FontFamily="{DynamicResource Icons}" Height="28" FontSize="16" Click="BtnAdd_Click"/>
<Button x:Name="BtnExplorer" Content="" Margin="0,15,101,0" VerticalAlignment="Top" HorizontalAlignment="Right" Width="28" FontFamily="{DynamicResource Icons}" Height="28" FontSize="16" Click="BtnExplorer_Click"/>
<Button x:Name="BtnRun" Content="" Margin="0,15,58,0" VerticalAlignment="Top" HorizontalAlignment="Right" Width="28" FontFamily="{DynamicResource Icons}" Height="28" FontSize="16" Click="BtnRun_Click"/>
<Button x:Name="BtnMore" Content="" Margin="0,15,15,0" VerticalAlignment="Top" HorizontalAlignment="Right" Width="28" FontFamily="{DynamicResource Icons}" Height="28" FontSize="16" Click="BtnMore_Click"/>
<Button x:Name="BtnRun" Content="" Margin="0,15,58,0" VerticalAlignment="Top" HorizontalAlignment="Right" Width="28" FontFamily="{DynamicResource Icons}" Height="28" FontSize="16" Click="BtnRun_Click" ToolTip="Run"/>
<Button x:Name="BtnMore" Content="" Margin="0,15,15,0" VerticalAlignment="Top" HorizontalAlignment="Right" Width="28" FontFamily="{DynamicResource Icons}" Height="28" FontSize="16" Click="BtnMore_Click" ToolTip="More"/>
</Grid>
</Border>
</Grid>
Expand Down
18 changes: 17 additions & 1 deletion SuperLauncher/ModernLauncher.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media.Animation;
using System.Diagnostics;

namespace SuperLauncher
{
Expand Down Expand Up @@ -129,13 +130,20 @@ private void UpdateAnimations(bool Center = false)
OpenTopAnimation.To = (DPI.ScalePixelsDown(mi.rcWork.bottom) - Height - 10);
}
}
private void SetExpirationToolTip()
{
ToolTip elevateUserTT = new ToolTip();
elevateUserTT.Content = $"Password expires {AccountInfo.ExpirationDate}";
ElevateUser.ToolTip = elevateUserTT;
}
private void SetElevateLabels()
{
ElevateUser.Content = RunAsHelper.GetCurrentDomainWithUserName();
if (RunAsHelper.IsElevated())
{
ElevateIcon.Content = "";
}

}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Expand All @@ -154,6 +162,8 @@ private void Window_Loaded(object sender, RoutedEventArgs e)
HWND.AddHook(HwndSourceHook);
_ = Win32Interop.SetWindowLong(WIH.Handle, Win32Interop.SetWindowLongIndex.GWL_EXSTYLE, Win32Interop.ExtendedWindowStyles.WS_EX_TOOLWINDOW);
SetElevateLabels();
// Trigger the monitor task once right away
AccountInfo.AccountMonitorTask(null, null);
}
public void OpenWindow(bool Center = false)
{
Expand All @@ -167,7 +177,7 @@ public void OpenWindow(bool Center = false)
RenderBoost.BeginAnimation(OpacityProperty, RenderBoostAnimation);
Filter.Text = "";
Filter.Focus();
SetTopPosition();
SetExpirationToolTip();
Activate();
}
public void CloseWindow()
Expand Down Expand Up @@ -283,5 +293,11 @@ private void BtnAdd_Click(object sender, RoutedEventArgs e)
((ModernLauncher)Program.ModernApplication.MainWindow).MLI.PopulateIcons();
((ModernLauncher)Program.ModernApplication.MainWindow).OpenWindow();
}

private void ElevateUser_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
ModernLauncherPasswordChangeUI modernLauncherPasswordChangeUI = new ModernLauncherPasswordChangeUI();
modernLauncherPasswordChangeUI.ShowDialog();
}
}
}
50 changes: 50 additions & 0 deletions SuperLauncher/ModernLauncherPasswordChangeUI.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<Window x:Class="SuperLauncher.ModernLauncherPasswordChangeUI"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SuperLauncher"
mc:Ignorable="d"
Title="Super Launcher - Update Password"
WindowStartupLocation="CenterScreen"
WindowStyle="None"
FontFamily="{DynamicResource Font}"
Loaded="Window_Loaded"
Height="379"
Width="347"
Topmost="True" >
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Themes/WinUI.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<WindowChrome.WindowChrome>
<WindowChrome
CaptionHeight="0"
GlassFrameThickness="-1"
ResizeBorderThickness="0"
UseAeroCaptionButtons="true"
/>
</WindowChrome.WindowChrome>
<Grid Background="{DynamicResource PanelColorBrush}">
<Grid x:Name="Grid" Background="{DynamicResource AcrylicNoise}">
<Label Content="Change Password" Foreground="{DynamicResource TextColorBrush}" FontSize="20" FontWeight="Normal" FontStyle="Normal" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="17,46,0,0" />
<Label Content="Super Launcher - Update Password" Foreground="{DynamicResource TextColorBrush}" FontWeight="Normal" FontStyle="Normal" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="32,6,0,0" />
<Label x:Name="LBUser" Content="Enter the current and new password for " Foreground="{DynamicResource TextColorBrush}" FontWeight="Normal" FontStyle="Normal" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="18,93,0,0" />
<Label Content="" Foreground="{DynamicResource TextColorBrush}" FontFamily="{DynamicResource Icons}" FontWeight="Normal" FontStyle="Normal" FontSize="16" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="6,6,0,0" />
<PasswordBox x:Name="TBCurrentPassword" Tag="" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="23,138,0,0" Width="298" Height="34" ToolTip="Current Password" />
<PasswordBox x:Name="TBNewPassword" Tag="" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="23,185,0,0" Width="298" Height="34" KeyDown="TBPassword_KeyDown" PasswordChanged="TB_PasswordChanged" />
<PasswordBox x:Name="TBConfirmPassword" Tag="" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,233,0,0" Width="298" Height="34" KeyDown="TBPassword_KeyDown" PasswordChanged="TB_PasswordChanged" BorderThickness="1,1,1,17"/>
<Button x:Name="BtnOK" IsEnabled="False" Content="Apply" HorizontalAlignment="Left" Margin="23,315,0,0" VerticalAlignment="Top" Height="35" Width="141" Click="BtnOK_Click" />
<Button x:Name="BtnCancel" Content="Cancel" HorizontalAlignment="Left" Margin="180,315,0,0" VerticalAlignment="Top" Height="35" Width="141" Click="BtnCancel_Click" />
<Border Name="TBConfirm_Border" BorderThickness="2,2,2,2" Margin="24,236,26,115" Opacity="0.85" />
<Label Name="LBError" Content="Error:" FontWeight="Normal" FontStyle="Normal" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="23,272,0,0" Visibility="Hidden">
<Label.Foreground>
<SolidColorBrush Color="#FFAB0202"/>
</Label.Foreground>
</Label>
</Grid>
</Grid>
</Window>
84 changes: 84 additions & 0 deletions SuperLauncher/ModernLauncherPasswordChangeUI.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System.Windows;
using System.Windows.Input;
using System;

namespace SuperLauncher
{
/// <summary>
/// Interaction logic for ModernLauncherPasswordChangeUI.xaml
/// </summary>
public partial class ModernLauncherPasswordChangeUI : Window
{
public ModernLauncherPasswordChangeUI()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Shared.EnableAcrylic(this);
Shared.SetWindowColor(this);
LBUser.Content += Environment.UserName;
TBCurrentPassword.Focus();
}
private void BtnCancel_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void BtnOK_Click(object sender, RoutedEventArgs e)
{

string result = AccountInfo.ChangePassword(TBCurrentPassword.Password, TBConfirmPassword.Password);

if (result != "Success")
{
LBError.Content = result;
LBError.Visibility = Visibility.Visible;
return;
}

if (Settings.Default.RememberMe)
{
CredentialManager.CREDENTIAL cred = new()
{
TargetName = "Super Launcher",
Type = CredentialManager.CredType.CRED_TYPE_GENERIC,
Persist = CredentialManager.CredPersist.CRED_PERSIST_LOCAL_MACHINE,
UserName = RunAsHelper.GetOriginalInvokerDomainWithUserName(),
Password = TBConfirmPassword.Password
};
CredentialManager.CredWriteA(cred, CredentialManager.CredWriteFlags.NONE);
}
Program.ModernApplicationShutdown();
}
private void TBPassword_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter) BtnOK_Click(null, null);

}

// This highlights the textbox if they didn't match
private void TB_PasswordChanged(object sender, RoutedEventArgs e)
{
if (TBNewPassword.Password.Length <= 1)
{
BtnOK.IsEnabled = false;
TBConfirm_Border.BorderBrush = System.Windows.Media.Brushes.Transparent;
return;
}

if (TBNewPassword.Password != TBConfirmPassword.Password)
{
TBConfirm_Border.BorderBrush = System.Windows.Media.Brushes.Red;
BtnOK.IsEnabled = false;
LBError.Content = "New and confirm passwords don't match";
LBError.Visibility = Visibility.Visible;
}
else
{
BtnOK.IsEnabled = true;
TBConfirm_Border.BorderBrush = System.Windows.Media.Brushes.Green;
LBError.Visibility = Visibility.Hidden;
}
}
}
}
52 changes: 51 additions & 1 deletion SuperLauncher/ModernLauncherShared.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using Microsoft.Win32;
using Microsoft.Toolkit.Uwp.Notifications;
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows.Media;

Expand Down Expand Up @@ -99,5 +101,53 @@ public static void StartProcess(string FilePath, string[] Arguments = null)
catch { }
});
}

/// <summary>
/// Send a tost notification
/// </summary>
/// <param name="title">Title of the notification</param>
/// <param name="msg">Message to user</param>
///
// This is the native notification implementation. Which doesn't work because the toast is sent to the run-as user
// Instead of the desktop user we're actually viewing it as
public static void SendDesktopToast_Native(string title, string msg)
{
// Round logo
//Uri logoUri = new Uri(System.IO.Path.GetFullPath("48.png"));
// Rocket
Uri logoUri = new Uri(System.IO.Path.GetFullPath("sl_logo_big.png"));

try
{
new ToastContentBuilder()
.AddText(title)
.AddText(msg)
.AddAppLogoOverride(logoUri, hintCrop: ToastGenericAppLogoCrop.Circle)
.Show(toast =>
{
toast.ExpirationTime = DateTime.Now.AddDays(1);
});
}
catch (Exception ex)
{
//Debug.WriteLine(ex.ToString());
//throw;
}
}

/// <summary>
/// Send a tost notification
/// </summary>
/// <param name="title">Title of the notification</param>
/// <param name="msg">Message to user</param>
///
public static void SendDesktopToast(string title, string msg)
{
NotifyIcon notifyIcon = ModernLauncherNotifyIcon.Icon;
notifyIcon.BalloonTipTitle = title;
notifyIcon.BalloonTipText = msg;
notifyIcon.BalloonTipIcon = ToolTipIcon.None;
notifyIcon.ShowBalloonTip(15000);
}
}
}
Loading

0 comments on commit 586e6ac

Please sign in to comment.