@@ -56,6 +56,10 @@ export default class AppUpdater {
5656
5757 autoUpdater . on ( "update-available" , ( releaseInfo : UpdateInfo ) => {
5858 logger . info ( "update ready:" , releaseInfo ) ;
59+ // Validate update info when received
60+ if ( ! this . isValidUpdateInfo ( releaseInfo ) ) {
61+ logger . error ( "Received invalid update info" ) ;
62+ }
5963 } ) ;
6064
6165 autoUpdater . on ( "update-not-available" , ( ) => {
@@ -67,8 +71,13 @@ export default class AppUpdater {
6771 } ) ;
6872
6973 autoUpdater . on ( "update-downloaded" , ( releaseInfo : UpdateInfo ) => {
70- this . releaseInfo = releaseInfo ;
71- logger . info ( "update downloaded:" , releaseInfo ) ;
74+ // Validate before storing
75+ if ( this . isValidUpdateInfo ( releaseInfo ) ) {
76+ this . releaseInfo = releaseInfo ;
77+ logger . info ( "update downloaded:" , releaseInfo ) ;
78+ } else {
79+ logger . error ( "Downloaded update has invalid info, refusing to store" ) ;
80+ }
7281 } ) ;
7382
7483 this . autoUpdater = autoUpdater ;
@@ -121,12 +130,45 @@ export default class AppUpdater {
121130 }
122131 }
123132
133+ /**
134+ * Validates update info structure
135+ * @param info The update info to validate
136+ * @returns True if valid, false otherwise
137+ */
138+ private isValidUpdateInfo ( info : UpdateInfo | undefined ) : boolean {
139+ if ( ! info ) return false ;
140+
141+ // Check required fields
142+ if ( ! info . version || typeof info . version !== "string" ) {
143+ logger . error ( "Invalid update info: missing or invalid version" ) ;
144+ return false ;
145+ }
146+
147+ // Validate version format (basic semver check)
148+ const semverRegex = / ^ \d + \. \d + \. \d + ( - [ a - z A - Z 0 - 9 . - ] + ) ? ( \+ [ a - z A - Z 0 - 9 . - ] + ) ? $ / ;
149+ if ( ! semverRegex . test ( info . version ) ) {
150+ logger . error (
151+ `Invalid update info: invalid version format ${ info . version } ` ,
152+ ) ;
153+ return false ;
154+ }
155+
156+ return true ;
157+ }
158+
124159 /**
125160 * Show update dialog to the user
126161 * @param mainWindow The window to show the dialog on
127162 */
128163 public async showUpdateDialog ( mainWindow : BrowserWindow ) {
129164 if ( ! this . releaseInfo ) {
165+ logger . warn ( "No release info available for update dialog" ) ;
166+ return ;
167+ }
168+
169+ // Validate update info before processing
170+ if ( ! this . isValidUpdateInfo ( this . releaseInfo ) ) {
171+ logger . error ( "Invalid update info, refusing to show dialog" ) ;
130172 return ;
131173 }
132174
@@ -146,26 +188,32 @@ export default class AppUpdater {
146188 defaultId : 1 ,
147189 cancelId : 0 ,
148190 } )
149- . then ( ( { response } ) => {
191+ . then ( async ( { response } ) => {
150192 if ( response === 1 ) {
151- app . isQuitting = true ;
152193 logger . info ( "User clicked install, starting update installation..." ) ;
153194
154- // Close all windows first
155- // Note: Data persistence is handled by the app's gracefulShutdown mechanism
156- BrowserWindow . getAllWindows ( ) . forEach ( win => {
157- try {
158- win . close ( ) ;
159- } catch ( e ) {
160- logger . error ( "Error closing window:" , e ) ;
161- }
162- } ) ;
195+ // Set flag to indicate we're installing an update
196+ app . isQuitting = true ;
197+
198+ // The app's before-quit handler will trigger gracefulShutdown
199+ // which properly cleans up all resources. After that completes,
200+ // we'll install the update.
163201
164- // Add delay to ensure windows are closed
165- setTimeout ( ( ) => {
166- logger . info ( "Calling quitAndInstall ..." ) ;
202+ // Store reference to quitAndInstall to be called after shutdown
203+ const performUpdate = ( ) => {
204+ logger . info ( "Graceful shutdown complete, installing update ..." ) ;
167205 autoUpdater . quitAndInstall ( false , true ) ;
168- } , 100 ) ;
206+ } ;
207+
208+ // Listen for app ready to quit after graceful shutdown
209+ app . once ( "will-quit" , event => {
210+ event . preventDefault ( ) ;
211+ // Small delay to ensure all cleanup is complete
212+ setTimeout ( performUpdate , 100 ) ;
213+ } ) ;
214+
215+ // Trigger the shutdown sequence
216+ app . quit ( ) ;
169217 } else {
170218 mainWindow . webContents . send ( "update-downloaded-cancelled" ) ;
171219 }
0 commit comments