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