Root cause: electron.safeStorage was undefined (not null) when the property doesn't exist, causing "Cannot read properties of undefined" error when accessing isEncryptionAvailable. Fix: Normalize undefined to null with `|| null` operator when importing safeStorage, ensuring consistent null checks throughout the code. Changes: - Set safeStorage to null if electron.safeStorage is undefined - Remove all diagnostic try-catch blocks from settings UI - Remove console.log debugging statements - Restore clean code that now works correctly This resolves the settings UI crash that prevented the API key management section from displaying.
77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
// Safely import safeStorage - may not be available in all environments
|
|
let safeStorage: any = null;
|
|
try {
|
|
const electron = require('electron');
|
|
safeStorage = electron.safeStorage || null;
|
|
} catch (error) {
|
|
console.warn('Electron safeStorage not available, API keys will be stored in plaintext');
|
|
}
|
|
|
|
/**
|
|
* Checks if encryption is available on the current platform
|
|
* @returns true if safeStorage encryption is available
|
|
*/
|
|
export function isEncryptionAvailable(): boolean {
|
|
return safeStorage !== null &&
|
|
typeof safeStorage.isEncryptionAvailable === 'function' &&
|
|
safeStorage.isEncryptionAvailable();
|
|
}
|
|
|
|
/**
|
|
* Encrypts an API key using Electron's safeStorage API
|
|
* Falls back to plaintext if encryption is not available (e.g., Linux without keyring)
|
|
* @param apiKey The plaintext API key to encrypt
|
|
* @returns Encrypted API key with "encrypted:" prefix, or plaintext if encryption unavailable
|
|
*/
|
|
export function encryptApiKey(apiKey: string): string {
|
|
if (!apiKey) {
|
|
return '';
|
|
}
|
|
|
|
// Check if safeStorage is available and encryption is enabled
|
|
if (!isEncryptionAvailable()) {
|
|
console.warn('Encryption not available, storing API key in plaintext');
|
|
return apiKey;
|
|
}
|
|
|
|
try {
|
|
const encrypted = safeStorage.encryptString(apiKey);
|
|
return `encrypted:${encrypted.toString('base64')}`;
|
|
} catch (error) {
|
|
console.error('Failed to encrypt API key, falling back to plaintext:', error);
|
|
return apiKey;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Decrypts an API key encrypted with encryptApiKey
|
|
* @param stored The stored API key (encrypted or plaintext)
|
|
* @returns Decrypted API key
|
|
*/
|
|
export function decryptApiKey(stored: string): string {
|
|
if (!stored) {
|
|
return '';
|
|
}
|
|
|
|
// Check if this is an encrypted key
|
|
if (!stored.startsWith('encrypted:')) {
|
|
// Legacy plaintext key or fallback
|
|
return stored;
|
|
}
|
|
|
|
// If safeStorage is not available, we can't decrypt
|
|
if (!safeStorage) {
|
|
console.error('Cannot decrypt API key: safeStorage not available');
|
|
throw new Error('Failed to decrypt API key. You may need to regenerate it.');
|
|
}
|
|
|
|
try {
|
|
const encryptedData = stored.substring(10); // Remove "encrypted:" prefix
|
|
const buffer = Buffer.from(encryptedData, 'base64');
|
|
return safeStorage.decryptString(buffer);
|
|
} catch (error) {
|
|
console.error('Failed to decrypt API key:', error);
|
|
throw new Error('Failed to decrypt API key. You may need to regenerate it.');
|
|
}
|
|
}
|