diff --git a/doc/secure-storage-implementation.md b/doc/secure-storage-implementation.md index 17bacbdc..0395a3d1 100644 --- a/doc/secure-storage-implementation.md +++ b/doc/secure-storage-implementation.md @@ -5,7 +5,7 @@ This document outlines the implementation of secure storage for the TimeSafari app using Capacitor solutions. The implementation focuses on: 1. **Platform-Specific Storage Solutions**: - - Web: wa-sqlite with IndexedDB backend + - Web: absurd-sql with IndexedDB backend - iOS: SQLCipher with Keychain integration - Android: SQLCipher with Keystore integration - Electron: SQLite with secure storage @@ -23,8 +23,8 @@ This document outlines the implementation of secure storage for the TimeSafari a ```bash # Core dependencies npm install @capacitor-community/sqlite@6.0.0 -npm install @wa-sqlite/sql.js@0.8.12 -npm install @wa-sqlite/sql.js-httpvfs@0.8.12 +npm install absurd-sql@latest +npm install @jlongster/sql.js@latest # Platform-specific dependencies npm install @capacitor/preferences@6.0.2 @@ -218,13 +218,18 @@ try { ### 4. Platform-Specific Implementations -#### Web Platform (wa-sqlite) +#### Web Platform (absurd-sql) ```typescript // src/services/platforms/web/WebSQLiteService.ts +import { initSqlJs } from '@jlongster/sql.js'; +import { SQLiteFS } from 'absurd-sql'; +import IndexedDBBackend from 'absurd-sql/dist/indexeddb-backend'; +import { StorageError, StorageErrorCodes } from '../errors/StorageError'; + export class WebSQLiteService implements PlatformService { private db: SQLite.Database | null = null; - private vfs: IDBBatchAtomicVFS | null = null; + private vfs: SQLiteFS | null = null; private initialized = false; async initialize(): Promise { @@ -258,8 +263,8 @@ export class WebSQLiteService implements PlatformService { private async initializeSQLite(): Promise { try { - return await SQLite.init({ - locateFile: file => `https://cdn.jsdelivr.net/npm/@wa-sqlite/sql.js@0.8.12/dist/${file}` + return await initSqlJs({ + locateFile: file => `https://cdn.jsdelivr.net/npm/@jlongster/sql.js@latest/dist/${file}` }); } catch (error) { throw new StorageError( @@ -272,8 +277,14 @@ export class WebSQLiteService implements PlatformService { private async setupVFS(sqlite3: SQLite.SqlJsStatic): Promise { try { - this.vfs = new IDBBatchAtomicVFS('timesafari'); - await this.vfs.registerVFS(sqlite3); + // Initialize IndexedDB backend + const backend = new IndexedDBBackend(); + + // Create SQLiteFS instance + this.vfs = new SQLiteFS(backend, sqlite3); + + // Register the VFS + sqlite3.register_for_idb(this.vfs); } catch (error) { throw new StorageError( 'Failed to set up IndexedDB VFS', @@ -292,6 +303,7 @@ export class WebSQLiteService implements PlatformService { } try { + // Open database with absurd-sql this.db = await this.vfs.openDatabase('timesafari.db'); await this.setupPragmas(); } catch (error) { @@ -312,6 +324,8 @@ export class WebSQLiteService implements PlatformService { PRAGMA synchronous = NORMAL; PRAGMA foreign_keys = ON; PRAGMA busy_timeout = 5000; + PRAGMA temp_store = MEMORY; + PRAGMA mmap_size = 30000000000; `); } catch (error) { throw new StorageError( @@ -329,6 +343,34 @@ export class WebSQLiteService implements PlatformService { } this.initialized = false; } + + // Example query method + async query(sql: string, params: any[] = []): Promise { + if (!this.db) { + throw new StorageError( + 'Database not initialized', + StorageErrorCodes.INITIALIZATION_FAILED + ); + } + + try { + const stmt = this.db.prepare(sql); + const results: T[] = []; + + while (stmt.step()) { + results.push(stmt.getAsObject() as T); + } + + stmt.free(); + return results; + } catch (error) { + throw new StorageError( + 'Query failed', + StorageErrorCodes.QUERY_FAILED, + error + ); + } + } } // Migration strategy for web platform @@ -369,6 +411,14 @@ export class WebMigrationService { StorageErrorCodes.INITIALIZATION_FAILED ); } + + // Check absurd-sql compatibility + if (!window.indexedDB.databases) { + throw new StorageError( + 'Browser does not support required IndexedDB features', + StorageErrorCodes.INITIALIZATION_FAILED + ); + } } private async createBackup(): Promise { @@ -916,7 +966,7 @@ CREATE INDEX idx_settings_updated_at ON settings(updated_at); | Feature | Web | iOS | Android | Electron | |---------|-----|-----|---------|----------| -| SQLite | wa-sqlite | SQLCipher | SQLCipher | SQLite | +| SQLite | absurd-sql | SQLCipher | SQLCipher | SQLite | | Encryption | SQLCipher | SQLCipher | SQLCipher | SQLCipher | | Secure Storage | IndexedDB | Keychain | Keystore | Secure Storage | | Biometrics | No | Yes | Yes | No | @@ -924,6 +974,8 @@ CREATE INDEX idx_settings_updated_at ON settings(updated_at); | Background Sync | No | Yes | Yes | Yes | | Storage Quota | Yes | No | No | No | | Multi-tab Support | Yes | N/A | N/A | Yes | +| WAL Mode | Yes | Yes | Yes | Yes | +| Atomic Transactions | Yes | Yes | Yes | Yes | ### D. Usage Examples