import { BrowserWindow , ipcMain } from 'electron' ; import { app } from 'electron/main' ; import path from 'path' ; import { fromEvent , Subject } from 'rxjs' ; import { IClientObservable , IClientRequest , IFido2DeviceInfo } from '../client/client' ; import { Fido2EventSelectDevice , Fido2EventCancel , Fido2EventPinAvailable , Fido2EventResponse , Fido2EventDeviceAttach , Fido2EventDeviceSelected , Fido2EventKeepAlive , Fido2EventPinAuthBlocked , Fido2EventPinBlocked , Fido2EventPinInvalid , Fido2EventPinValid , Fido2EventRequest , Fido2EventNoCredentials , Fido2EventError , Fido2EventTimeout , Fido2EventDeviceDetach } from '../client/event' ; import { IFido2Device } from '../fido2/fido2-device-cli' ; import { logger } from '../log/debug' ; export class DefaultModal extends Subject < IClientObservable > { private browser ! : BrowserWindow ; private ready : boolean = false ; constructor ( ) { super ( ) ; this . subscribe ( value => { switch ( value . type ) { case 'fido2-event-request' : { let request = value . data as IClientRequest ; this . window . then ( x => x . webContents . send ( Fido2EventRequest , request ) ) ; break ; } case 'fido2-event-device-attach' : { this . window . then ( x => x . webContents . send ( Fido2EventDeviceAttach , value . data as IFido2Device ) ) ; break ; } case 'fido2-event-device-detach' : this . window . then ( x => x . webContents . send ( Fido2EventDeviceDetach , value . data as IFido2Device ) ) ; break ; case 'fido2-event-pin-invalid' : { this . window . then ( x => x . webContents . send ( Fido2EventPinInvalid , value . data as number ) ) ; break ; } case 'fido2-event-pin-valid' : { this . window . then ( x => x . webContents . send ( Fido2EventPinValid ) ) ; break ; } case 'fido2-event-device-selected' : { logger . debug ( value . data ) ; this . window . then ( x => x . webContents . send ( Fido2EventDeviceSelected , value . data as IFido2DeviceInfo ) ) ; break ; } case 'fido2-event-pin-auth-blocked' : { this . window . then ( x => x . webContents . send ( Fido2EventPinAuthBlocked ) ) ; break ; } case 'fido2-event-pin-blocked' : { this . window . then ( x => x . webContents . send ( Fido2EventPinBlocked ) ) ; break ; } case 'fido2-event-success' : { this . window . then ( x => x . closable && x . close ( ) ) ; break ; } case 'fido2-event-keep-alive' : { this . window . then ( x => x . webContents . send ( Fido2EventKeepAlive , value . data as number ) ) ; break ; } case 'fido2-event-timeout' : { this . window . then ( x => x . webContents . send ( Fido2EventTimeout ) ) ; break ; } case 'fido2-event-no-credentials' : this . window . then ( x => x . webContents . send ( Fido2EventNoCredentials ) ) ; break ; case 'fido2-event-error' : case 'fido2-event-cancel' : case 'fido2-event-response' : case 'fido2-event-select-device' : case 'fido2-event-pin-available' : case 'fido2-event-keep-alive-cancel' : case 'fido2-event-enter-pin' : case 'fido2-event-set-pin' : break ; default : /**
                     * Shouldn't go there.
                     */ logger . debug ( `drop unknown notify with type=${ value . type }, data=${ value . data }` ) ; break ; } } ) ; fromEvent < boolean > ( ipcMain , Fido2EventResponse , ( _ , status ) => status ) . subscribe ( status => { this . next ( { type : 'fido2-event-response' , data : status } ) ; } ) ; fromEvent < IFido2Device > ( ipcMain , Fido2EventSelectDevice , ( _ , device ) => device ) . subscribe ( device => { this . next ( { type : 'fido2-event-select-device' , data : device } ) ; } ) ; fromEvent < string > ( ipcMain , Fido2EventPinAvailable , ( _ , pin ) => pin ) . subscribe ( pin => { this . next ( { type : 'fido2-event-pin-available' , data : pin } ) ; } ) ; fromEvent < void > ( ipcMain , Fido2EventCancel , ( ) => void 0 ) . subscribe ( ( ) => { this . window . then ( x => x . closable && x . close ( ) ) ; this . next ( { type : 'fido2-event-cancel' } ) ; } ) ; fromEvent < string > ( ipcMain , Fido2EventError , ( _ , e ) => e ) . subscribe ( e => { this . window . then ( x => x . closable && x . close ( ) ) ; this . next ( { type : 'fido2-event-error' , data : e } ) ; } ) ; } private get window ( ) : Promise < BrowserWindow > { return new Promise ( ( resolve , reject ) => { if ( this . ready ) return resolve ( this . browser ) ; this . browser = new BrowserWindow ( { width : 480 , height : 320 , hasShadow : true , resizable : false , parent : BrowserWindow . getFocusedWindow ( ) || undefined , transparent : false , TODO frame : process . platform === 'darwin' ? true : false , useContentSize : true , modal : true , show : false , alwaysOnTop : true , webPreferences : { nodeIntegration : false , enableRemoteModule : false , contextIsolation : true , sandbox : true , webSecurity : true , experimentalFeatures : false , worldSafeExecuteJavaScript : false , preload : path . join ( __dirname , 'preload.js' ) } } ) ; this . browser . once ( 'closed' , ( ) => this . ready = false ) ; this . browser . loadFile ( path . join ( __dirname , '../../../assets/default/index.html' ) ) . then ( _ => { this . browser . show ( ) ; this . ready = true ; resolve ( this . browser ) ; } ) ; } ) ; } }