5bbbbc5cf1
Desktop Client Build / Resolve Build Metadata (push) Successful in 49s
Frontend CI / Frontend (push) Successful in 5m47s
Desktop Client Build / Build Desktop Client (push) Successful in 42m28s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 2m38s
88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
import { existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
|
|
import { app, safeStorage } from 'electron/main'
|
|
|
|
export interface DesktopLoginCredentials {
|
|
identifier: string
|
|
password: string
|
|
}
|
|
|
|
interface PersistedLoginCredentials {
|
|
version?: number
|
|
identifier?: unknown
|
|
encryptedPassword?: unknown
|
|
}
|
|
|
|
function credentialsPath(): string {
|
|
return join(app.getPath('userData'), 'login-credentials.json')
|
|
}
|
|
|
|
function normalizeCredentials(input: unknown): PersistedLoginCredentials {
|
|
if (!input || typeof input !== 'object') {
|
|
return {}
|
|
}
|
|
return input as PersistedLoginCredentials
|
|
}
|
|
|
|
export function getSavedLoginCredentials(): DesktopLoginCredentials | null {
|
|
try {
|
|
if (!existsSync(credentialsPath())) {
|
|
return null
|
|
}
|
|
|
|
const persisted = normalizeCredentials(JSON.parse(readFileSync(credentialsPath(), 'utf8')))
|
|
const identifier = typeof persisted.identifier === 'string' ? persisted.identifier : ''
|
|
const encryptedPassword =
|
|
typeof persisted.encryptedPassword === 'string' ? persisted.encryptedPassword : ''
|
|
|
|
if (!identifier || !encryptedPassword || !safeStorage.isEncryptionAvailable()) {
|
|
return null
|
|
}
|
|
|
|
const password = safeStorage.decryptString(Buffer.from(encryptedPassword, 'base64'))
|
|
return password ? { identifier, password } : null
|
|
} catch (error) {
|
|
console.warn('[login-credentials] read failed', {
|
|
message: error instanceof Error ? error.message : String(error),
|
|
})
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function saveLoginCredentials(credentials: DesktopLoginCredentials): DesktopLoginCredentials {
|
|
const identifier = credentials.identifier.trim()
|
|
if (!identifier || !credentials.password) {
|
|
clearSavedLoginCredentials()
|
|
return { identifier: '', password: '' }
|
|
}
|
|
|
|
if (!safeStorage.isEncryptionAvailable()) {
|
|
throw new Error('login_credentials_encryption_unavailable')
|
|
}
|
|
|
|
const encryptedPassword = safeStorage.encryptString(credentials.password).toString('base64')
|
|
writeFileSync(
|
|
credentialsPath(),
|
|
JSON.stringify({
|
|
version: 1,
|
|
identifier,
|
|
encryptedPassword,
|
|
updatedAt: new Date().toISOString(),
|
|
}),
|
|
'utf8',
|
|
)
|
|
return { identifier, password: credentials.password }
|
|
}
|
|
|
|
export function clearSavedLoginCredentials(): null {
|
|
try {
|
|
rmSync(credentialsPath(), { force: true })
|
|
} catch (error) {
|
|
console.warn('[login-credentials] clear failed', {
|
|
message: error instanceof Error ? error.message : String(error),
|
|
})
|
|
}
|
|
return null
|
|
}
|