@@ -6,6 +6,8 @@ import { ChangePasswordSchema, type ChangePasswordInput } from './schemas';
66import { requireAuthHook } from '../../hooks/authHook' ;
77import { z } from 'zod' ;
88import { zodToJsonSchema } from 'zod-to-json-schema' ;
9+ import { EmailService } from '../../email' ;
10+ import { GlobalSettingsService } from '../../services/globalSettingsService' ;
911
1012// Response schemas
1113const changePasswordSuccessResponseSchema = z . object ( {
@@ -160,6 +162,56 @@ export default async function changePasswordRoute(fastify: FastifyInstance) {
160162
161163 fastify . log . info ( `Password changed successfully for user: ${ userId } ` ) ;
162164
165+ // Send password change notification email if email sending is enabled
166+ try {
167+ // Check if email sending is enabled in global settings
168+ const emailSettings = await GlobalSettingsService . getByGroup ( 'global' ) ;
169+ const sendMailSetting = emailSettings ?. find ( s => s . key === 'global.send_mail' ) ;
170+ const isEmailEnabled = sendMailSetting ?. value === 'true' ;
171+
172+ if ( isEmailEnabled ) {
173+ // Get user's IP address and user agent for security info
174+ const ipAddress = request . ip || request . headers [ 'x-forwarded-for' ] as string || 'Unknown' ;
175+ const userAgent = request . headers [ 'user-agent' ] || 'Unknown' ;
176+ const changeTime = new Date ( ) . toLocaleString ( 'en-US' , {
177+ timeZone : 'UTC' ,
178+ year : 'numeric' ,
179+ month : 'long' ,
180+ day : 'numeric' ,
181+ hour : '2-digit' ,
182+ minute : '2-digit' ,
183+ timeZoneName : 'short'
184+ } ) ;
185+
186+ // Get frontend URL for login link
187+ const frontendUrlSetting = emailSettings ?. find ( s => s . key === 'global.frontend_url' ) ;
188+ const frontendUrl = frontendUrlSetting ?. value || process . env . DEPLOYSTACK_FRONTEND_URL || 'https://app.deploystack.com' ;
189+ const loginUrl = `${ frontendUrl } /login` ;
190+
191+ // Send password change notification email
192+ const emailResult = await EmailService . sendPasswordChangedEmail ( {
193+ to : user . email ,
194+ userName : user . first_name ? `${ user . first_name } ${ user . last_name || '' } ` . trim ( ) : user . username ,
195+ userEmail : user . email ,
196+ changeTime,
197+ ipAddress,
198+ userAgent,
199+ loginUrl,
200+ } ) ;
201+
202+ if ( emailResult . success ) {
203+ fastify . log . info ( `Password change notification email sent to: ${ user . email } ` ) ;
204+ } else {
205+ fastify . log . warn ( `Failed to send password change notification email: ${ emailResult . error } ` ) ;
206+ }
207+ } else {
208+ fastify . log . debug ( 'Email sending is disabled, skipping password change notification' ) ;
209+ }
210+ } catch ( emailError ) {
211+ // Don't fail the password change if email fails
212+ fastify . log . warn ( 'Failed to send password change notification email:' , emailError ) ;
213+ }
214+
163215 // Optional: Invalidate all other sessions for security
164216 // This would require additional implementation to track and invalidate sessions
165217 // For now, we'll just log this as a security consideration
0 commit comments