Files
obsidian-mcp-server/src/main.ts
Bill bbd5f6ae92 feat: auto-generate and encrypt API keys, migrate legacy CORS settings
Update main.ts to automatically generate API keys on first load,
encrypt them when saving to disk, and decrypt them when loading.
Also migrate legacy settings by removing enableCORS and
allowedOrigins fields.

Changes:
- Auto-generate API key if empty on plugin load
- Encrypt API key before saving to data.json
- Decrypt API key after loading from data.json
- Migrate legacy settings by removing CORS-related fields
- Add imports for generateApiKey, encryptApiKey, decryptApiKey
- Add comprehensive migration tests in main-migration.test.ts

This implements Task 4 of the CORS simplification plan.
2025-10-25 22:14:29 -04:00

227 lines
6.1 KiB
TypeScript

import { Notice, Plugin } from 'obsidian';
import { MCPServer } from './server/mcp-server';
import { MCPPluginSettings, DEFAULT_SETTINGS } from './types/settings-types';
import { MCPServerSettingTab } from './settings';
import { NotificationManager } from './ui/notifications';
import { NotificationHistoryModal } from './ui/notification-history';
import { generateApiKey } from './utils/auth-utils';
import { encryptApiKey, decryptApiKey } from './utils/encryption-utils';
export default class MCPServerPlugin extends Plugin {
settings!: MCPPluginSettings;
mcpServer: MCPServer | null = null;
statusBarItem: HTMLElement | null = null;
notificationManager: NotificationManager | null = null;
async onload() {
await this.loadSettings();
// Auto-generate API key if not set
if (!this.settings.apiKey || this.settings.apiKey.trim() === '') {
console.log('Generating new API key...');
this.settings.apiKey = generateApiKey();
await this.saveSettings();
}
// Migrate legacy settings (remove enableCORS and allowedOrigins)
const legacySettings = this.settings as any;
if ('enableCORS' in legacySettings || 'allowedOrigins' in legacySettings) {
console.log('Migrating legacy CORS settings...');
delete legacySettings.enableCORS;
delete legacySettings.allowedOrigins;
await this.saveSettings();
}
// Initialize notification manager
this.updateNotificationManager();
// Add status bar item
this.statusBarItem = this.addStatusBarItem();
this.updateStatusBar();
// Add ribbon icon to toggle server
this.addRibbonIcon('server', 'Toggle MCP Server', async () => {
if (this.mcpServer?.isRunning()) {
await this.stopServer();
} else {
await this.startServer();
}
});
// Register commands
this.addCommand({
id: 'start-mcp-server',
name: 'Start MCP Server',
callback: async () => {
await this.startServer();
}
});
this.addCommand({
id: 'stop-mcp-server',
name: 'Stop MCP Server',
callback: async () => {
await this.stopServer();
}
});
this.addCommand({
id: 'restart-mcp-server',
name: 'Restart MCP Server',
callback: async () => {
await this.stopServer();
await this.startServer();
}
});
this.addCommand({
id: 'view-notification-history',
name: 'View MCP Notification History',
callback: () => {
this.showNotificationHistory();
}
});
// Add settings tab
this.addSettingTab(new MCPServerSettingTab(this.app, this));
// Auto-start if enabled
if (this.settings.autoStart) {
await this.startServer();
}
}
async onunload() {
await this.stopServer();
}
async startServer() {
if (this.mcpServer?.isRunning()) {
new Notice('MCP Server is already running');
return;
}
// Validate authentication configuration
if (this.settings.enableAuth && (!this.settings.apiKey || this.settings.apiKey.trim() === '')) {
new Notice('⚠️ Cannot start server: Authentication is enabled but no API key is set. Please set an API key in settings or disable authentication.');
return;
}
try {
this.mcpServer = new MCPServer(this.app, this.settings);
// Set notification manager if notifications are enabled
if (this.notificationManager) {
this.mcpServer.setNotificationManager(this.notificationManager);
}
await this.mcpServer.start();
new Notice(`MCP Server started on port ${this.settings.port}`);
this.updateStatusBar();
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
new Notice(`Failed to start MCP Server: ${message}`);
console.error('MCP Server start error:', error);
}
}
async stopServer() {
if (!this.mcpServer?.isRunning()) {
new Notice('MCP Server is not running');
return;
}
try {
await this.mcpServer.stop();
new Notice('MCP Server stopped');
this.updateStatusBar();
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
new Notice(`Failed to stop MCP Server: ${message}`);
console.error('MCP Server stop error:', error);
}
}
updateStatusBar() {
if (this.statusBarItem) {
const isRunning = this.mcpServer?.isRunning() ?? false;
this.statusBarItem.setText(
isRunning
? `MCP: Running (${this.settings.port})`
: 'MCP: Stopped'
);
this.statusBarItem.addClass('mcp-status-bar');
}
}
async loadSettings() {
const data = await this.loadData();
this.settings = Object.assign({}, DEFAULT_SETTINGS, data);
// Decrypt API key if encrypted
if (this.settings.apiKey) {
try {
this.settings.apiKey = decryptApiKey(this.settings.apiKey);
} catch (error) {
console.error('Failed to decrypt API key:', error);
new Notice('⚠️ Failed to decrypt API key. Please regenerate in settings.');
this.settings.apiKey = '';
}
}
}
async saveSettings() {
// Create a copy of settings for saving
const settingsToSave = { ...this.settings };
// Encrypt API key before saving
if (settingsToSave.apiKey) {
settingsToSave.apiKey = encryptApiKey(settingsToSave.apiKey);
}
await this.saveData(settingsToSave);
// Update server settings if running
if (this.mcpServer) {
this.mcpServer.updateSettings(this.settings);
}
}
/**
* Update or create notification manager based on settings
*/
updateNotificationManager() {
if (this.settings.notificationsEnabled) {
if (!this.notificationManager) {
this.notificationManager = new NotificationManager(this.app, this.settings);
} else {
this.notificationManager.updateSettings(this.settings);
}
// Update server's tool registry if server is running
if (this.mcpServer) {
this.mcpServer.setNotificationManager(this.notificationManager);
}
} else {
this.notificationManager = null;
// Clear notification manager from server if running
if (this.mcpServer) {
this.mcpServer.setNotificationManager(null);
}
}
}
/**
* Show notification history modal
*/
showNotificationHistory() {
if (!this.notificationManager) {
new Notice('Notifications are not enabled. Enable them in settings to view history.');
return;
}
const history = this.notificationManager.getHistory();
const modal = new NotificationHistoryModal(this.app, history);
modal.open();
}
}