2021-10-01 18:57:22 -07:00
const remoteMain = require ( '@electron/remote/main' )
remoteMain . initialize ( )
2021-03-07 08:17:23 -08:00
2018-06-04 16:34:47 -07:00
// Requirements
2022-03-03 21:02:52 -08:00
const { app , BrowserWindow , ipcMain , Menu , shell } = require ( 'electron' )
2022-02-11 16:51:28 -08:00
const autoUpdater = require ( 'electron-updater' ) . autoUpdater
const ejse = require ( 'ejs-electron' )
const fs = require ( 'fs' )
const isDev = require ( './app/assets/js/isdev' )
const path = require ( 'path' )
const semver = require ( 'semver' )
const { pathToFileURL } = require ( 'url' )
2022-03-03 21:02:52 -08:00
const { AZURE _CLIENT _ID , MSFT _OPCODE , MSFT _REPLY _TYPE , MSFT _ERROR , SHELL _OPCODE } = require ( './app/assets/js/ipcconstants' )
2017-05-16 23:26:46 -07:00
2018-04-28 15:45:19 -07:00
// Setup auto updater.
2018-06-04 17:06:34 -07:00
function initAutoUpdater ( event , data ) {
if ( data ) {
2018-06-04 16:34:47 -07:00
autoUpdater . allowPrerelease = true
} else {
// Defaults to true if application version contains prerelease components (e.g. 0.12.1-alpha.1)
// autoUpdater.allowPrerelease = true
}
2018-04-28 13:26:38 -07:00
if ( isDev ) {
autoUpdater . autoInstallOnAppQuit = false
autoUpdater . updateConfigPath = path . join ( _ _dirname , 'dev-app-update.yml' )
}
2018-11-18 18:51:48 -08:00
if ( process . platform === 'darwin' ) {
autoUpdater . autoDownload = false
}
2018-04-28 13:26:38 -07:00
autoUpdater . on ( 'update-available' , ( info ) => {
event . sender . send ( 'autoUpdateNotification' , 'update-available' , info )
} )
autoUpdater . on ( 'update-downloaded' , ( info ) => {
event . sender . send ( 'autoUpdateNotification' , 'update-downloaded' , info )
} )
autoUpdater . on ( 'update-not-available' , ( info ) => {
event . sender . send ( 'autoUpdateNotification' , 'update-not-available' , info )
} )
autoUpdater . on ( 'checking-for-update' , ( ) => {
event . sender . send ( 'autoUpdateNotification' , 'checking-for-update' )
2018-11-01 14:37:05 -07:00
} )
2018-11-08 22:03:28 -08:00
autoUpdater . on ( 'error' , ( err ) => {
2018-11-01 14:37:05 -07:00
event . sender . send ( 'autoUpdateNotification' , 'realerror' , err )
} )
2018-04-28 13:26:38 -07:00
}
2018-04-28 15:45:19 -07:00
// Open channel to listen for update actions.
2018-06-04 16:34:47 -07:00
ipcMain . on ( 'autoUpdateAction' , ( event , arg , data ) => {
2018-04-28 13:26:38 -07:00
switch ( arg ) {
case 'initAutoUpdater' :
console . log ( 'Initializing auto updater.' )
2018-06-04 17:06:34 -07:00
initAutoUpdater ( event , data )
2018-04-28 13:26:38 -07:00
event . sender . send ( 'autoUpdateNotification' , 'ready' )
break
case 'checkForUpdate' :
autoUpdater . checkForUpdates ( )
. catch ( err => {
2018-04-28 15:45:19 -07:00
event . sender . send ( 'autoUpdateNotification' , 'realerror' , err )
2018-04-28 13:26:38 -07:00
} )
break
2018-06-04 16:34:47 -07:00
case 'allowPrereleaseChange' :
if ( ! data ) {
const preRelComp = semver . prerelease ( app . getVersion ( ) )
if ( preRelComp != null && preRelComp . length > 0 ) {
autoUpdater . allowPrerelease = true
} else {
autoUpdater . allowPrerelease = data
}
} else {
autoUpdater . allowPrerelease = data
}
break
2018-04-28 13:26:38 -07:00
case 'installUpdateNow' :
autoUpdater . quitAndInstall ( )
break
default :
console . log ( 'Unknown argument' , arg )
break
}
} )
2018-05-06 22:34:57 -07:00
// Redirect distribution index event from preloader to renderer.
2018-07-22 08:40:15 -07:00
ipcMain . on ( 'distributionIndexDone' , ( event , res ) => {
event . sender . send ( 'distributionIndexDone' , res )
2018-05-06 22:34:57 -07:00
} )
2018-04-28 13:26:38 -07:00
2022-03-03 21:02:52 -08:00
// Handle trash item.
ipcMain . handle ( SHELL _OPCODE . TRASH _ITEM , async ( event , ... args ) => {
try {
await shell . trashItem ( args [ 0 ] )
return {
result : true
}
} catch ( error ) {
return {
result : false ,
error : error
}
}
} )
2018-04-06 09:33:20 -07:00
// Disable hardware acceleration.
// https://electronjs.org/docs/tutorial/offscreen-rendering
app . disableHardwareAcceleration ( )
2022-02-11 16:51:28 -08:00
2022-12-07 10:59:10 -08:00
2022-02-11 16:51:28 -08:00
2017-05-16 23:26:46 -07:00
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win
function createWindow ( ) {
2018-04-06 09:33:20 -07:00
2017-12-01 23:59:25 -08:00
win = new BrowserWindow ( {
2022-12-07 10:59:10 -08:00
width : 1143 ,
height : 700 ,
2019-03-05 21:37:31 -08:00
icon : getPlatformIcon ( 'SealCircle' ) ,
2017-12-01 23:59:25 -08:00
frame : false ,
webPreferences : {
2018-12-21 03:51:08 -08:00
preload : path . join ( _ _dirname , 'app' , 'assets' , 'js' , 'preloader.js' ) ,
nodeIntegration : true ,
2021-10-01 18:57:22 -07:00
contextIsolation : false
2018-04-29 15:05:59 -07:00
} ,
2018-05-08 03:34:16 -07:00
backgroundColor : '#171614'
2017-12-01 23:59:25 -08:00
} )
2021-10-01 18:57:22 -07:00
remoteMain . enable ( win . webContents )
2017-05-16 23:26:46 -07:00
2017-11-22 02:48:40 -08:00
ejse . data ( 'bkid' , Math . floor ( ( Math . random ( ) * fs . readdirSync ( path . join ( _ _dirname , 'app' , 'assets' , 'images' , 'backgrounds' ) ) . length ) ) )
2017-11-19 12:08:52 -08:00
2021-06-23 17:27:04 -07:00
win . loadURL ( pathToFileURL ( path . join ( _ _dirname , 'app' , 'app.ejs' ) ) . toString ( ) )
2017-05-16 23:26:46 -07:00
2018-04-29 15:05:59 -07:00
/ * w i n . o n c e ( ' r e a d y - t o - s h o w ' , ( ) = > {
win . show ( )
} ) * /
2019-06-02 13:15:57 -07:00
win . removeMenu ( )
2017-05-16 23:26:46 -07:00
2020-01-01 12:37:07 -08:00
win . resizable = true
2017-08-26 22:13:48 -07:00
2017-05-16 23:26:46 -07:00
win . on ( 'closed' , ( ) => {
win = null
} )
}
2018-11-25 19:06:33 -08:00
function createMenu ( ) {
if ( process . platform === 'darwin' ) {
// Extend default included application menu to continue support for quit keyboard shortcut
let applicationSubMenu = {
label : 'Application' ,
submenu : [ {
label : 'About Application' ,
selector : 'orderFrontStandardAboutPanel:'
} , {
type : 'separator'
} , {
label : 'Quit' ,
accelerator : 'Command+Q' ,
click : ( ) => {
app . quit ( )
}
} ]
}
// New edit menu adds support for text-editing keyboard shortcuts
let editSubMenu = {
label : 'Edit' ,
submenu : [ {
label : 'Undo' ,
accelerator : 'CmdOrCtrl+Z' ,
selector : 'undo:'
} , {
label : 'Redo' ,
accelerator : 'Shift+CmdOrCtrl+Z' ,
selector : 'redo:'
} , {
type : 'separator'
} , {
label : 'Cut' ,
accelerator : 'CmdOrCtrl+X' ,
selector : 'cut:'
} , {
label : 'Copy' ,
accelerator : 'CmdOrCtrl+C' ,
selector : 'copy:'
} , {
label : 'Paste' ,
accelerator : 'CmdOrCtrl+V' ,
selector : 'paste:'
} , {
label : 'Select All' ,
accelerator : 'CmdOrCtrl+A' ,
selector : 'selectAll:'
} ]
}
// Bundle submenus into a single template and build a menu object with it
let menuTemplate = [ applicationSubMenu , editSubMenu ]
let menuObject = Menu . buildFromTemplate ( menuTemplate )
// Assign it to the application
Menu . setApplicationMenu ( menuObject )
}
}
2017-05-16 23:26:46 -07:00
function getPlatformIcon ( filename ) {
2020-05-23 19:21:51 -07:00
let ext
switch ( process . platform ) {
case 'win32' :
ext = 'ico'
break
case 'darwin' :
case 'linux' :
default :
ext = 'png'
break
2017-05-16 23:26:46 -07:00
}
2020-05-23 19:21:51 -07:00
return path . join ( _ _dirname , 'app' , 'assets' , 'images' , ` ${ filename } . ${ ext } ` )
2017-05-16 23:26:46 -07:00
}
2018-07-22 10:31:15 -07:00
app . on ( 'ready' , createWindow )
2018-11-25 19:06:33 -08:00
app . on ( 'ready' , createMenu )
2017-05-16 23:26:46 -07:00
app . on ( 'window-all-closed' , ( ) => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if ( process . platform !== 'darwin' ) {
app . quit ( )
}
} )
app . on ( 'activate' , ( ) => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if ( win === null ) {
createWindow ( )
}
2022-12-07 10:59:10 -08:00
} )
const REDIRECT _URI _PREFIX = 'https://login.microsoftonline.com/common/oauth2/nativeclient?'
// Microsoft Auth Login
let msftAuthWindow
let msftAuthSuccess
let msftAuthViewSuccess
let msftAuthViewOnClose
ipcMain . on ( MSFT _OPCODE . OPEN _LOGIN , ( ipcEvent , ... arguments _ ) => {
/ *
Clear cookies from live . com and github . com from Microsoft Login , since there isn ' t an actual way to invalidate Microsoft access token
* /
session . defaultSession . cookies . get ( { domain : 'live.com' } ) . then ( ( cookies ) => {
for ( let cookie of cookies ) {
let urlcookie = ` http ${ cookie . secure ? "s" : "" } :// ${ cookie . domain . replace ( /$\./ , "" ) + cookie . path } ` ;
session . defaultSession . cookies . remove ( urlcookie , cookie . name )
}
} )
session . defaultSession . cookies . get ( { domain : 'github.com' } ) . then ( ( cookies ) => {
for ( let cookie of cookies ) {
let urlcookie = ` http ${ cookie . secure ? "s" : "" } :// ${ cookie . domain . replace ( /$\./ , "" ) + cookie . path } ` ;
session . defaultSession . cookies . remove ( urlcookie , cookie . name )
}
} )
if ( msftAuthWindow ) {
ipcEvent . reply ( MSFT _OPCODE . REPLY _LOGIN , MSFT _REPLY _TYPE . ERROR , MSFT _ERROR . ALREADY _OPEN , msftAuthViewOnClose )
return
}
msftAuthSuccess = false
msftAuthViewSuccess = arguments _ [ 0 ]
msftAuthViewOnClose = arguments _ [ 1 ]
msftAuthWindow = new BrowserWindow ( {
parent : win ,
modal : true ,
resizable : false ,
title : 'Microsoft Login' ,
backgroundColor : '#222222' ,
width : 520 ,
height : 700 ,
frame : true ,
icon : getPlatformIcon ( 'SealCircle' )
} )
msftAuthWindow . on ( 'closed' , ( ) => {
msftAuthWindow = undefined
} )
msftAuthWindow . on ( 'close' , ( ) => {
if ( ! msftAuthSuccess ) {
ipcEvent . reply ( MSFT _OPCODE . REPLY _LOGIN , MSFT _REPLY _TYPE . ERROR , MSFT _ERROR . NOT _FINISHED , msftAuthViewOnClose )
}
} )
msftAuthWindow . webContents . on ( 'did-navigate' , ( _ , uri ) => {
if ( uri . startsWith ( REDIRECT _URI _PREFIX ) ) {
let queries = uri . substring ( REDIRECT _URI _PREFIX . length ) . split ( '#' , 1 ) . toString ( ) . split ( '&' )
let queryMap = { }
queries . forEach ( query => {
const [ name , value ] = query . split ( '=' )
queryMap [ name ] = decodeURI ( value )
} )
ipcEvent . reply ( MSFT _OPCODE . REPLY _LOGIN , MSFT _REPLY _TYPE . SUCCESS , queryMap , msftAuthViewSuccess )
msftAuthSuccess = true
msftAuthWindow . close ( )
msftAuthWindow = null
}
} )
msftAuthWindow . removeMenu ( )
msftAuthWindow . loadURL ( ` https://login.live.com/oauth20_authorize.srf?prompt=select_account&client_id= ${ AZURE _CLIENT _ID } &response_type=code&scope=XboxLive.signin%20offline_access&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient&cobrandid=8058f65d-ce06-4c30-9559-473c9275a65d ` ) //Cobrandid adds the Minecraft branding on the login page
} )
// Microsoft Auth Logout
ipcMain . on ( MSFT _OPCODE . OPEN _LOGOUT , ( ipcEvent , uuid , isLastAccount ) => {
ipcEvent . reply ( MSFT _OPCODE . REPLY _LOGOUT , MSFT _REPLY _TYPE . SUCCESS , uuid , isLastAccount ) //Just reply to the event, since logout pop up isn't that much useful
2017-05-16 23:26:46 -07:00
} )