From 779b3d6e8c8f15c3842c6d1530fc60930ae76fc9 Mon Sep 17 00:00:00 2001 From: Bill Date: Sun, 26 Oct 2025 00:16:35 -0400 Subject: [PATCH] fix: handle undefined safeStorage and remove diagnostic logging 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. --- src/settings.ts | 136 ++++++++++++++-------------------- src/utils/encryption-utils.ts | 2 +- 2 files changed, 57 insertions(+), 81 deletions(-) diff --git a/src/settings.ts b/src/settings.ts index 61b16c7..8fe43ba 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -61,94 +61,70 @@ export class MCPServerSettingTab extends PluginSettingTab { // Authentication (Always Enabled) containerEl.createEl('h3', {text: 'Authentication'}); - try { - const authDesc = containerEl.createEl('p', { - text: 'Authentication is required for all requests. Your API key is encrypted and stored securely using your system\'s credential storage.' - }); - authDesc.style.fontSize = '0.9em'; - authDesc.style.color = 'var(--text-muted)'; - authDesc.style.marginBottom = '16px'; + const authDesc = containerEl.createEl('p', { + text: 'Authentication is required for all requests. Your API key is encrypted and stored securely using your system\'s credential storage.' + }); + authDesc.style.fontSize = '0.9em'; + authDesc.style.color = 'var(--text-muted)'; + authDesc.style.marginBottom = '16px'; - // Show encryption status - const encryptionAvailable = isEncryptionAvailable(); - console.log('[Settings] Encryption available:', encryptionAvailable); - - const encryptionStatus = containerEl.createEl('p', { - text: encryptionAvailable - ? '🔒 Encryption: Available (using system keychain)' - : '⚠️ Encryption: Unavailable (API key stored in plaintext)' - }); - encryptionStatus.style.fontSize = '0.85em'; - encryptionStatus.style.marginBottom = '12px'; - encryptionStatus.style.fontStyle = 'italic'; - } catch (error) { - console.error('[Settings] Error in auth description section:', error); - containerEl.createEl('p', { - text: '⚠️ Error displaying authentication section: ' + (error instanceof Error ? error.message : String(error)), - cls: 'mod-error' - }); - } + // Show encryption status + const encryptionStatus = containerEl.createEl('p', { + text: isEncryptionAvailable() + ? '🔒 Encryption: Available (using system keychain)' + : '⚠️ Encryption: Unavailable (API key stored in plaintext)' + }); + encryptionStatus.style.fontSize = '0.85em'; + encryptionStatus.style.marginBottom = '12px'; + encryptionStatus.style.fontStyle = 'italic'; // API Key Display (always show - auth is always enabled) - console.log('[Settings] About to render API key section'); - console.log('[Settings] API key length:', (this.plugin.settings.apiKey || '').length); + new Setting(containerEl) + .setName('API Key Management') + .setDesc('Use this key in the Authorization header as Bearer token'); - try { - new Setting(containerEl) - .setName('API Key Management') - .setDesc('Use this key in the Authorization header as Bearer token'); + // Create a full-width container for buttons and key display + const apiKeyContainer = containerEl.createDiv({cls: 'mcp-api-key-section'}); + apiKeyContainer.style.marginBottom = '20px'; + apiKeyContainer.style.marginLeft = '0'; - // Create a full-width container for buttons and key display - const apiKeyContainer = containerEl.createDiv({cls: 'mcp-api-key-section'}); - apiKeyContainer.style.marginBottom = '20px'; - apiKeyContainer.style.marginLeft = '0'; + // Create button container + const apiKeyButtonContainer = apiKeyContainer.createDiv({cls: 'mcp-api-key-buttons'}); + apiKeyButtonContainer.style.display = 'flex'; + apiKeyButtonContainer.style.gap = '8px'; + apiKeyButtonContainer.style.marginBottom = '12px'; - // Create button container - const apiKeyButtonContainer = apiKeyContainer.createDiv({cls: 'mcp-api-key-buttons'}); - apiKeyButtonContainer.style.display = 'flex'; - apiKeyButtonContainer.style.gap = '8px'; - apiKeyButtonContainer.style.marginBottom = '12px'; + // Copy button + const copyButton = apiKeyButtonContainer.createEl('button', {text: '📋 Copy Key'}); + copyButton.addEventListener('click', async () => { + await navigator.clipboard.writeText(this.plugin.settings.apiKey || ''); + new Notice('✅ API key copied to clipboard'); + }); - // Copy button - const copyButton = apiKeyButtonContainer.createEl('button', {text: '📋 Copy Key'}); - copyButton.addEventListener('click', async () => { - await navigator.clipboard.writeText(this.plugin.settings.apiKey || ''); - new Notice('✅ API key copied to clipboard'); - }); + // Regenerate button + const regenButton = apiKeyButtonContainer.createEl('button', {text: '🔄 Regenerate Key'}); + regenButton.addEventListener('click', async () => { + this.plugin.settings.apiKey = generateApiKey(); + await this.plugin.saveSettings(); + new Notice('✅ New API key generated'); + if (this.plugin.mcpServer?.isRunning()) { + new Notice('⚠️ Server restart required for API key changes to take effect'); + } + this.display(); + }); - // Regenerate button - const regenButton = apiKeyButtonContainer.createEl('button', {text: '🔄 Regenerate Key'}); - regenButton.addEventListener('click', async () => { - this.plugin.settings.apiKey = generateApiKey(); - await this.plugin.saveSettings(); - new Notice('✅ New API key generated'); - if (this.plugin.mcpServer?.isRunning()) { - new Notice('⚠️ Server restart required for API key changes to take effect'); - } - this.display(); - }); - - // API Key display (static, copyable text) - const keyDisplayContainer = apiKeyContainer.createDiv({cls: 'mcp-api-key-display'}); - keyDisplayContainer.style.padding = '12px'; - keyDisplayContainer.style.backgroundColor = 'var(--background-secondary)'; - keyDisplayContainer.style.borderRadius = '4px'; - keyDisplayContainer.style.fontFamily = 'monospace'; - keyDisplayContainer.style.fontSize = '0.9em'; - keyDisplayContainer.style.wordBreak = 'break-all'; - keyDisplayContainer.style.userSelect = 'all'; - keyDisplayContainer.style.cursor = 'text'; - keyDisplayContainer.style.marginBottom = '16px'; - keyDisplayContainer.textContent = this.plugin.settings.apiKey || ''; - - console.log('[Settings] API key section rendered successfully'); - } catch (error) { - console.error('[Settings] Error rendering API key section:', error); - containerEl.createEl('p', { - text: '⚠️ Error displaying API key: ' + (error instanceof Error ? error.message : String(error)), - cls: 'mod-error' - }); - } + // API Key display (static, copyable text) + const keyDisplayContainer = apiKeyContainer.createDiv({cls: 'mcp-api-key-display'}); + keyDisplayContainer.style.padding = '12px'; + keyDisplayContainer.style.backgroundColor = 'var(--background-secondary)'; + keyDisplayContainer.style.borderRadius = '4px'; + keyDisplayContainer.style.fontFamily = 'monospace'; + keyDisplayContainer.style.fontSize = '0.9em'; + keyDisplayContainer.style.wordBreak = 'break-all'; + keyDisplayContainer.style.userSelect = 'all'; + keyDisplayContainer.style.cursor = 'text'; + keyDisplayContainer.style.marginBottom = '16px'; + keyDisplayContainer.textContent = this.plugin.settings.apiKey || ''; // MCP Client Configuration (show always, regardless of auth) containerEl.createEl('h3', {text: 'MCP Client Configuration'}); diff --git a/src/utils/encryption-utils.ts b/src/utils/encryption-utils.ts index b047345..39c8c4e 100644 --- a/src/utils/encryption-utils.ts +++ b/src/utils/encryption-utils.ts @@ -2,7 +2,7 @@ let safeStorage: any = null; try { const electron = require('electron'); - safeStorage = electron.safeStorage; + safeStorage = electron.safeStorage || null; } catch (error) { console.warn('Electron safeStorage not available, API keys will be stored in plaintext'); }