#!/usr/bin/env node /** * Setup database script * Initializes the SQLite database with the schema */ const fs = require('fs'); const path = require('path'); const { initDatabase, getDatabase, closeDatabase } = require('../src/database/connection'); const { initEncryption } = require('../src/utils/encryption'); const { DB_PATH, KEY_FILE } = require('../src/database/config'); const crypto = require('crypto'); const DATABASE_PATH = DB_PATH; const DATABASE_ENCRYPTION_KEY = process.env.DATABASE_ENCRYPTION_KEY; const WAL_MODE = process.env.DATABASE_WAL_MODE !== '0' && process.env.DATABASE_WAL_MODE !== 'false'; const DATABASE_USE_SQLCIPHER = process.env.DATABASE_USE_SQLCIPHER !== '0' && process.env.DATABASE_USE_SQLCIPHER !== 'false'; async function setupDatabase() { console.log('🔧 Setting up database...'); console.log(' Database path:', DATABASE_PATH); // Ensure data directory exists const dataDir = path.dirname(DATABASE_PATH); if (!fs.existsSync(dataDir)) { fs.mkdirSync(dataDir, { recursive: true }); console.log(' Created data directory:', dataDir); } let encryptionKey = DATABASE_ENCRYPTION_KEY; // Check if encryption key is provided if (!encryptionKey) { if (fs.existsSync(KEY_FILE)) { encryptionKey = fs.readFileSync(KEY_FILE, 'utf8').trim(); if (encryptionKey) { process.env.DATABASE_ENCRYPTION_KEY = encryptionKey; console.log('✅ Loaded encryption key from file'); } } } if (!encryptionKey) { console.warn('⚠️ WARNING: No DATABASE_ENCRYPTION_KEY found!'); console.warn('⚠️ Generating a random key for this session (not persistent).'); console.warn('⚠️ For production, set DATABASE_ENCRYPTION_KEY environment variable.'); console.warn('⚠️ Generate one with: openssl rand -hex 32'); const generatedKey = crypto.randomBytes(32).toString('hex'); process.env.DATABASE_ENCRYPTION_KEY = generatedKey; encryptionKey = generatedKey; try { const keyDir = path.dirname(KEY_FILE); if (!fs.existsSync(keyDir)) fs.mkdirSync(keyDir, { recursive: true }); fs.writeFileSync(KEY_FILE, generatedKey, { mode: 0o600 }); console.log('⚠️ Saved generated key to:', KEY_FILE); } catch (err) { console.warn('⚠️ Failed to persist encryption key:', err.message); } console.log('✅ Generated temporary encryption key'); } else { console.log('✅ Using encryption key from environment'); } // Initialize encryption try { initEncryption(encryptionKey); console.log('✅ Encryption initialized'); } catch (error) { console.error('❌ Failed to initialize encryption:', error.message); process.exit(1); } // Initialize database try { initDatabase(DATABASE_PATH, { verbose: false, walMode: WAL_MODE, sqlcipherKey: DATABASE_USE_SQLCIPHER ? encryptionKey : null, cipherCompatibility: process.env.DATABASE_CIPHER_COMPAT || 4, kdfIter: process.env.DATABASE_KDF_ITER || 64000 }); console.log('✅ Database initialized'); } catch (error) { console.error('❌ Failed to initialize database:', error.message); process.exit(1); } // Load and execute schema try { const schemaPath = path.join(__dirname, '..', 'src', 'database', 'schema.sql'); const schema = fs.readFileSync(schemaPath, 'utf8'); const db = getDatabase(); // Execute the entire schema as one block // SQLite can handle multiple statements with exec() db.exec(schema); // Add missing columns if this is an upgraded database const userColumns = db.prepare('PRAGMA table_info(users)').all(); const userColumnNames = new Set(userColumns.map((c) => c.name)); if (!userColumnNames.has('data')) { db.exec('ALTER TABLE users ADD COLUMN data TEXT'); console.log('✅ Added users.data column'); } console.log('✅ Database schema created'); } catch (error) { console.error('❌ Failed to create schema:', error.message); closeDatabase(); process.exit(1); } // Verify tables try { const db = getDatabase(); const tables = db.prepare(` SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name `).all(); console.log('✅ Database tables created:'); tables.forEach(table => { console.log(` - ${table.name}`); }); } catch (error) { console.error('❌ Failed to verify tables:', error.message); } // Close database closeDatabase(); console.log(''); console.log('✅ Database setup complete!'); console.log(''); console.log('Next steps:'); console.log(' 1. Run migration: node scripts/migrate-to-database.js'); console.log(' 2. Verify migration: node scripts/verify-migration.js'); console.log(' 3. Switch to database mode: unset USE_JSON_DATABASE'); console.log(' 4. Start server: npm start'); } // Run setup setupDatabase().catch(error => { console.error('❌ Setup failed:', error); process.exit(1); });