11import electron from 'electron' ;
22import { autoUpdater , type ProgressInfo , type UpdateCheckResult } from 'electron-updater' ;
33import path from 'node:path' ;
4- import process from 'node:process' ;
54
6- import type { ISettings } from '../renderer/src/common/common' ;
5+ import { isHttpUrl , type ISettings } from '../renderer/src/common/common' ;
76import { FULL_URI_SCHEME , LONG_DELAY , SHORT_DELAY } from '../renderer/src/common/constants' ;
87import { isLinux , isMacOs , isPackaged , isWindows } from '../renderer/src/common/electron' ;
8+ import { deleteGitHubAccessToken } from '../renderer/src/common/gitHubIntegration' ;
99
1010import icon from './assets/icon.png?asset' ;
1111import { ApplicationWindow } from './ApplicationWindow' ;
@@ -75,6 +75,8 @@ let _resetAll = false;
7575export function resetAll ( ) : void {
7676 _resetAll = true ;
7777
78+ deleteGitHubAccessToken ( ) ;
79+
7880 electron . app . relaunch ( ) ;
7981 electron . app . quit ( ) ;
8082}
@@ -140,7 +142,7 @@ export class MainWindow extends ApplicationWindow {
140142
141143 // Constructor.
142144
143- constructor ( commandLine : string [ ] , splashScreenWindow : SplashScreenWindow ) {
145+ constructor ( commandLine : string [ ] , splashScreenWindow : SplashScreenWindow , rendererUrl : string ) {
144146 // Initialise ourselves.
145147
146148 const state : IElectronConfState = electronConf . get ( 'app.state' ) ;
@@ -212,7 +214,7 @@ export class MainWindow extends ApplicationWindow {
212214
213215 commandLine . shift ( ) ;
214216
215- if ( ! isPackaged ( ) ) {
217+ if ( ! isPackaged ( ) && commandLine . length > 0 ) {
216218 commandLine . shift ( ) ;
217219 }
218220 }
@@ -238,10 +240,18 @@ export class MainWindow extends ApplicationWindow {
238240 // Main window state.
239241
240242 if ( ! this . isMaximized ( ) && ! this . isMinimized ( ) && ! this . isFullScreen ( ) ) {
241- state . x = this . getPosition ( ) [ 0 ] ;
242- state . y = this . getPosition ( ) [ 1 ] ;
243- state . width = this . getContentSize ( ) [ 0 ] ;
244- state . height = this . getContentSize ( ) [ 1 ] ;
243+ const [ stateX , stateY ] = this . getPosition ( ) ;
244+ const [ stateWidth , stateHeight ] = this . getContentSize ( ) ;
245+
246+ if ( typeof stateX === 'number' && typeof stateY === 'number' ) {
247+ state . x = stateX ;
248+ state . y = stateY ;
249+ }
250+
251+ if ( typeof stateWidth === 'number' && typeof stateHeight === 'number' ) {
252+ state . width = stateWidth ;
253+ state . height = stateHeight ;
254+ }
245255 }
246256
247257 state . isMaximized = this . isMaximized ( ) ;
@@ -269,30 +279,64 @@ export class MainWindow extends ApplicationWindow {
269279 this . setAutoHideMenuBar ( false ) ;
270280 this . setMenuBarVisibility ( true ) ;
271281
272- // Open external links in the default browser.
282+ // Open links in the default browser, unless it is a Firebase OAuth popup in which case we open it in a new window
283+ // so that the OAuth flow can proceed.
273284
274285 this . webContents . setWindowOpenHandler ( ( details ) => {
275- electron . shell . openExternal ( details . url ) . catch ( ( error : unknown ) => {
276- console . error ( 'Failed to open external URL:' , error ) ;
277- } ) ;
286+ function isFirebaseOauthPopup ( url : string ) : boolean {
287+ try {
288+ const parsedUrl = new URL ( url ) ;
289+
290+ return (
291+ ( parsedUrl . protocol === 'http:' || parsedUrl . protocol === 'https:' ) &&
292+ parsedUrl . host === 'opencorapp.firebaseapp.com' &&
293+ parsedUrl . pathname === '/__/auth/handler'
294+ ) ;
295+ } catch {
296+ return false ;
297+ }
298+ }
299+
300+ if ( isFirebaseOauthPopup ( details . url ) ) {
301+ return {
302+ action : 'allow' ,
303+ overrideBrowserWindowOptions : {
304+ parent : this ,
305+ modal : false ,
306+ autoHideMenuBar : true ,
307+ width : 600 ,
308+ height : 700 ,
309+ backgroundColor : electron . nativeTheme . shouldUseDarkColors ? '#18181b' : '#ffffff' ,
310+ // Note: use the same colours as the ones used by --p-content-background in PrimeVue, i.e. what we are using
311+ // as a background for our app (see src/renderer/src/assets/app.css).
312+ webPreferences : {
313+ preload : undefined ,
314+ sandbox : true ,
315+ contextIsolation : true ,
316+ nodeIntegration : false
317+ }
318+ }
319+ } ;
320+ }
321+
322+ if ( isHttpUrl ( details . url ) ) {
323+ electron . shell . openExternal ( details . url ) . catch ( ( error : unknown ) => {
324+ console . error ( `Failed to open external URL (${ details . url } ):` , error ) ;
325+ } ) ;
326+ } else {
327+ console . warn ( `Blocked attempt to open unsupported URL (${ details . url } ).` ) ;
328+ }
278329
279330 return {
280331 action : 'deny'
281332 } ;
282333 } ) ;
283334
284- // Load the remote URL when ELECTRON_RENDERER_URL is provided (i.e. if we are not packaged), otherwise load the
285- // local HTML file.
335+ // Load the renderer URL.
286336
287- if ( process . env . ELECTRON_RENDERER_URL ) {
288- this . loadURL ( process . env . ELECTRON_RENDERER_URL ) . catch ( ( error : unknown ) => {
289- console . error ( 'Failed to load URL:' , error ) ;
290- } ) ;
291- } else {
292- this . loadFile ( './out/renderer/index.html' ) . catch ( ( error : unknown ) => {
293- console . error ( 'Failed to load file:' , error ) ;
294- } ) ;
295- }
337+ this . loadURL ( rendererUrl ) . catch ( ( error : unknown ) => {
338+ console . error ( `Failed to load URL (${ rendererUrl } ):` , error ) ;
339+ } ) ;
296340 }
297341
298342 // Reopen previously opened files, if any, and select the previously selected file.
@@ -321,7 +365,11 @@ export class MainWindow extends ApplicationWindow {
321365
322366 // Handle our command line arguments.
323367
324- isAction ( argument : string ) : boolean {
368+ isAction ( argument : string | undefined ) : boolean {
369+ if ( argument === undefined ) {
370+ return false ;
371+ }
372+
325373 return argument . startsWith ( FULL_URI_SCHEME ) ;
326374 }
327375
0 commit comments