farmcontrol-ui/public/electron.js
Tom Butcher 78dc567a8f
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
Implemented software update installation.
2026-06-21 15:18:04 +01:00

160 lines
4.0 KiB
JavaScript

import { app, ipcMain, shell, globalShortcut, safeStorage } from 'electron'
import Store from 'electron-store'
import { Buffer } from 'buffer'
import process from 'process'
import {
registerGlobalShortcuts,
setupSpotlightIPC
} from './spotlightWindow.js'
import {
createWindow,
setupMainWindowIPC,
setupMainWindowAppEvents,
setupDevAuthServer,
setupSingleInstanceLock,
handleDeepLinkFromArgv
} from './mainWindow.js'
import { setupAppUpdateIPC } from './appupdate.js'
// --- Auth session storage (main process) ---
const authStore = new Store({
name: 'auth-session'
})
const AUTH_SESSION_KEY = 'authSession'
const appSettingsStore = new Store({
name: 'settings'
})
const APP_SETTINGS_KEY = 'appSettings'
const serializeAuthSession = (session) => {
const sessionJson = JSON.stringify(session)
if (safeStorage.isEncryptionAvailable()) {
const encrypted = safeStorage.encryptString(sessionJson).toString('base64')
return {
encrypted: true,
value: encrypted
}
}
return {
encrypted: false,
value: sessionJson
}
}
const deserializeAuthSession = (storedValue) => {
if (!storedValue) return null
if (typeof storedValue === 'object' && storedValue.encrypted === true) {
if (!safeStorage.isEncryptionAvailable()) {
console.warn(
'[auth-session] Encrypted auth session exists but encryption is unavailable on this system.'
)
return null
}
const decrypted = safeStorage.decryptString(
Buffer.from(storedValue.value, 'base64')
)
return JSON.parse(decrypted)
}
if (typeof storedValue === 'object' && typeof storedValue.value === 'string') {
return JSON.parse(storedValue.value)
}
if (typeof storedValue === 'string') {
return JSON.parse(storedValue)
}
// Legacy safety net if the object shape already matches the session structure.
if (typeof storedValue === 'object' && storedValue.token) {
return storedValue
}
return null
}
const gotTheLock = setupSingleInstanceLock(app)
if (gotTheLock) {
app.whenReady().then(() => {
createWindow()
registerGlobalShortcuts()
setupSpotlightIPC()
setupMainWindowIPC()
setupAppUpdateIPC(app)
setupMainWindowAppEvents(app)
setupDevAuthServer()
handleDeepLinkFromArgv()
})
}
app.on('will-quit', () => {
globalShortcut.unregisterAll()
})
// IPC handler to get OS
ipcMain.handle('os-info', () => {
return {
platform: process.platform
}
})
ipcMain.handle('auth-session-get', async () => {
try {
const storedValue = authStore.get(AUTH_SESSION_KEY)
return deserializeAuthSession(storedValue)
} catch (e) {
console.warn('[auth-session] Failed to read auth session.', e?.message || e)
return null
}
})
ipcMain.handle('auth-session-set', async (event, session) => {
try {
if (!session || typeof session !== 'object') return false
authStore.set(AUTH_SESSION_KEY, serializeAuthSession(session))
return true
} catch (e) {
console.warn('[auth-session] Failed to write auth session.', e?.message || e)
return false
}
})
ipcMain.handle('auth-session-clear', async () => {
try {
authStore.delete(AUTH_SESSION_KEY)
return true
} catch (e) {
console.warn('[auth-session] Failed to clear auth session.', e?.message || e)
return false
}
})
ipcMain.handle('app-settings-get', async () => {
try {
const settings = appSettingsStore.get(APP_SETTINGS_KEY)
return settings && typeof settings === 'object' ? settings : {}
} catch (e) {
console.warn('[app-settings] Failed to read settings.', e?.message || e)
return {}
}
})
ipcMain.handle('app-settings-set', async (event, settings) => {
try {
if (!settings || typeof settings !== 'object') return false
appSettingsStore.set(APP_SETTINGS_KEY, settings)
return true
} catch (e) {
console.warn('[app-settings] Failed to write settings.', e?.message || e)
return false
}
})
// IPC handler for opening external URLs
ipcMain.handle('open-external-url', (event, url) => {
shell.openExternal(url)
})