UNPKG

strata-storage

Version:

Zero-dependency universal storage plugin providing a unified API for all storage operations across web, Android, and iOS platforms

215 lines (214 loc) 6.21 kB
/** * Secure Adapter - Native secure storage * iOS: Keychain, Android: EncryptedSharedPreferences */ import { BaseAdapter } from "../../core/BaseAdapter.js"; import { StrataStorage } from "../../plugin/index.js"; import { StorageError } from "../../utils/errors.js"; import { isCapacitor } from "../../utils/index.js"; /** * Native secure storage adapter using Capacitor plugin */ export class SecureAdapter extends BaseAdapter { name = 'secure'; capabilities = { persistent: true, synchronous: false, observable: false, transactional: false, queryable: true, maxSize: -1, // Platform dependent binary: false, // String data only encrypted: true, // Native encryption crossTab: true, }; /** * Check if secure storage is available */ async isAvailable() { if (!isCapacitor()) return false; try { const result = await StrataStorage.isAvailable({ storage: 'secure' }); return result.available; } catch { return false; } } /** * Initialize the adapter */ async initialize() { this.startTTLCleanup(); } /** * Get a value from secure storage */ async get(key) { try { const result = await StrataStorage.get({ key, storage: 'secure', }); if (!result.value) return null; const value = result.value; // Check TTL if (this.isExpired(value)) { await this.remove(key); return null; } return value; } catch (error) { console.error(`Failed to get key ${key} from secure storage:`, error); return null; } } /** * Set a value in secure storage */ async set(key, value) { const oldValue = await this.get(key); try { await StrataStorage.set({ key, value, storage: 'secure', }); this.emitChange(key, oldValue?.value, value.value, 'local'); } catch (error) { throw new StorageError(`Failed to set key ${key} in secure storage: ${error}`); } } /** * Remove a value from secure storage */ async remove(key) { const oldValue = await this.get(key); try { await StrataStorage.remove({ key, storage: 'secure', }); if (oldValue) { this.emitChange(key, oldValue.value, undefined, 'local'); } } catch (error) { throw new StorageError(`Failed to remove key ${key} from secure storage: ${error}`); } } /** * Clear secure storage */ async clear(options) { if (!options || (!options.pattern && !options.tags && !options.expiredOnly)) { try { await StrataStorage.clear({ storage: 'secure', }); this.emitChange('*', undefined, undefined, 'local'); return; } catch (error) { throw new StorageError(`Failed to clear secure storage: ${error}`); } } // Use base implementation for filtered clear await super.clear(options); } /** * Get all keys */ async keys(pattern) { try { const result = await StrataStorage.keys({ storage: 'secure', pattern: pattern instanceof RegExp ? pattern.source : pattern, }); const keys = result.keys; // Check for expired keys const validKeys = []; for (const key of keys) { const value = await this.get(key); if (value) { validKeys.push(key); } } return this.filterKeys(validKeys, pattern); } catch (error) { throw new StorageError(`Failed to get keys from secure storage: ${error}`); } } /** * Get storage size */ async size(detailed) { try { const result = await StrataStorage.size({ storage: 'secure', detailed, }); return result; } catch (error) { throw new StorageError(`Failed to get size of secure storage: ${error}`); } } /** * iOS-specific: Store in Keychain with options */ async setKeychainItem(key, value, options) { if (!StrataStorage.setKeychain) { throw new StorageError('Keychain not available on this platform'); } await StrataStorage.setKeychain({ key, value, ...options, }); } /** * iOS-specific: Get from Keychain */ async getKeychainItem(key, options) { if (!StrataStorage.getKeychain) { throw new StorageError('Keychain not available on this platform'); } const result = await StrataStorage.getKeychain({ key, ...options, }); return result.value; } /** * Android-specific: Store encrypted preference */ async setEncryptedPreference(key, value, fileName) { if (!StrataStorage.setEncryptedPreference) { throw new StorageError('Encrypted preferences not available on this platform'); } await StrataStorage.setEncryptedPreference({ key, value, fileName, }); } /** * Android-specific: Get encrypted preference */ async getEncryptedPreference(key, fileName) { if (!StrataStorage.getEncryptedPreference) { throw new StorageError('Encrypted preferences not available on this platform'); } const result = await StrataStorage.getEncryptedPreference({ key, fileName, }); return result.value; } }