dev-1.7.0 #294

Merged
ZacharyZcR merged 73 commits from main into dev-1.7.0 2025-09-25 04:56:32 +00:00
2 changed files with 56 additions and 16 deletions
Showing only changes of commit c6819d3a4b - Show all commits
+49 -12
View File
@@ -7,6 +7,7 @@ import { databaseLogger } from "../../utils/logger.js";
import { DatabaseFileEncryption } from "../../utils/database-file-encryption.js"; import { DatabaseFileEncryption } from "../../utils/database-file-encryption.js";
import { SystemCrypto } from "../../utils/system-crypto.js"; import { SystemCrypto } from "../../utils/system-crypto.js";
import { DatabaseMigration } from "../../utils/database-migration.js"; import { DatabaseMigration } from "../../utils/database-migration.js";
import { DatabaseSaveTrigger } from "../../utils/database-save-trigger.js";
const dataDir = process.env.DATA_DIR || "./db/data"; const dataDir = process.env.DATA_DIR || "./db/data";
const dbDir = path.resolve(dataDir); const dbDir = path.resolve(dataDir);
1
@@ -494,25 +495,47 @@ const migrateSchema = () => {
}); });
}; };
// Function to save in-memory database to encrypted file // Function to save in-memory database to file (encrypted or unencrypted fallback)
async function saveMemoryDatabaseToFile() { async function saveMemoryDatabaseToFile() {
if (!memoryDatabase || !enableFileEncryption) return; if (!memoryDatabase) return;
try { try {
// Export in-memory database to buffer // Export in-memory database to buffer
const buffer = memoryDatabase.serialize(); const buffer = memoryDatabase.serialize();
// Encrypt and save to file (now async) // Ensure data directory exists
await DatabaseFileEncryption.encryptDatabaseFromBuffer(buffer, encryptedDbPath); if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });
databaseLogger.info("Created data directory", {
operation: "data_dir_create",
path: dataDir,
});
}
databaseLogger.debug("In-memory database saved to encrypted file", { if (enableFileEncryption) {
operation: "memory_db_save", // Save as encrypted file
bufferSize: buffer.length, await DatabaseFileEncryption.encryptDatabaseFromBuffer(buffer, encryptedDbPath);
encryptedPath: encryptedDbPath,
}); databaseLogger.debug("In-memory database saved to encrypted file", {
operation: "memory_db_save_encrypted",
bufferSize: buffer.length,
encryptedPath: encryptedDbPath,
});
} else {
// Fallback: save as unencrypted SQLite file to prevent data loss
fs.writeFileSync(dbPath, buffer);
databaseLogger.debug("In-memory database saved to unencrypted file", {
operation: "memory_db_save_unencrypted",
bufferSize: buffer.length,
unencryptedPath: dbPath,
warning: "File encryption disabled - data saved unencrypted",
});
}
} catch (error) { } catch (error) {
databaseLogger.error("Failed to save in-memory database", error, { databaseLogger.error("Failed to save in-memory database", error, {
operation: "memory_db_save_failed", operation: "memory_db_save_failed",
enableFileEncryption,
}); });
} }
} }
@@ -545,11 +568,14 @@ async function handlePostInitFileEncryption() {
databaseLogger.info("Setting up periodic database saves", { databaseLogger.info("Setting up periodic database saves", {
operation: "db_periodic_save_setup", operation: "db_periodic_save_setup",
interval: "5 minutes", interval: "15 seconds",
}); });
// Set up periodic saves every 5 minutes // Set up periodic saves every 15 seconds for real-time persistence
setInterval(saveMemoryDatabaseToFile, 5 * 60 * 1000); setInterval(saveMemoryDatabaseToFile, 15 * 1000);
// Initialize database save trigger for real-time saves
DatabaseSaveTrigger.initialize(saveMemoryDatabaseToFile);
} }
// Perform migration cleanup on startup (remove old backup files) // Perform migration cleanup on startup (remove old backup files)
@@ -692,6 +718,14 @@ export function getDb(): ReturnType<typeof drizzle<typeof schema>> {
return db; return db;
} }
// Export raw SQLite instance for migrations
export function getSqlite(): Database.Database {
if (!sqlite) {
throw new Error("SQLite not initialized. Ensure databaseReady promise is awaited before accessing sqlite.");
}
return sqlite;
}
// Legacy export for compatibility - will throw if accessed before initialization // Legacy export for compatibility - will throw if accessed before initialization
export { db }; export { db };
export { DatabaseFileEncryption }; export { DatabaseFileEncryption };
@@ -732,3 +766,6 @@ function getMemoryDatabaseBuffer(): Buffer {
// Export save function for manual saves and buffer access // Export save function for manual saves and buffer access
export { saveMemoryDatabaseToFile, getMemoryDatabaseBuffer }; export { saveMemoryDatabaseToFile, getMemoryDatabaseBuffer };
// Export database save trigger for real-time saves
export { DatabaseSaveTrigger };
+7 -4
View File
@@ -97,11 +97,11 @@ class AuthManager {
} }
// Import database connection - need to access raw SQLite for migration // Import database connection - need to access raw SQLite for migration
const { getDb } = await import("../database/db/index.js"); const { getSqlite, saveMemoryDatabaseToFile, databaseReady } = await import("../database/db/index.js");
const db = getDb();
// Get the underlying SQLite instance // Ensure database is fully initialized before accessing SQLite
const sqlite = (db as any)._.session.db; await databaseReady;
const sqlite = getSqlite();
// Perform the migration // Perform the migration
const migrationResult = await DataCrypto.migrateUserSensitiveFields( const migrationResult = await DataCrypto.migrateUserSensitiveFields(
@@ -111,6 +111,9 @@ class AuthManager {
); );
if (migrationResult.migrated) { if (migrationResult.migrated) {
// Save the in-memory database to disk to persist the migration
await saveMemoryDatabaseToFile();
databaseLogger.success("Lazy encryption migration completed for user", { databaseLogger.success("Lazy encryption migration completed for user", {
operation: "lazy_encryption_migration_success", operation: "lazy_encryption_migration_success",
userId, userId,