UNPKG

nucypher-experimental-taco-storage

Version:

TypeScript SDK for encrypted data storage with TACo (Threshold Access Control), supporting multiple storage providers including IPFS and SQLite

264 lines 10.5 kB
"use strict"; /** * Main TACo Storage SDK class */ Object.defineProperty(exports, "__esModule", { value: true }); exports.TacoStorage = void 0; const uuid_1 = require("uuid"); const taco_1 = require("@nucypher/taco"); const encryption_1 = require("./encryption"); const types_1 = require("../types"); /** * Main TACo Storage SDK class providing encrypted storage and retrieval */ class TacoStorage { constructor(adapter, tacoConfig, provider) { this.adapter = adapter; this.encryptionService = new encryption_1.TacoEncryptionService(tacoConfig); this.provider = provider; } /** * Initialize the TacoStorage instance and its components * @returns Promise that resolves when initialization is complete */ async initialize() { // Initialize the storage adapter await this.adapter.initialize(); // Initialize the encryption service await this.encryptionService.initialize(); } /** * Store data with encryption and access control * @param data - Data to store * @param signer - Ethereum signer for encryption * @param options - Storage options * @returns Promise resolving to storage result */ async store(data, signer, options = {}) { if (!data || data.length === 0) { throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.INVALID_CONFIG, 'Data cannot be empty'); } try { const id = options.id || (0, uuid_1.v4)(); const contentType = options.contentType || 'application/octet-stream'; const now = new Date(); // Create access conditions let accessConditions = options.condition; if (!accessConditions) { const expiresAt = options.expiresAt || new Date(now.getTime() + 24 * 60 * 60 * 1000); // 24 hours from now accessConditions = this.encryptionService.createTimeCondition(expiresAt); } // Encrypt the data const encryptionResult = await this.encryptionService.encrypt(data, accessConditions, this.provider, signer); // Serialize the ThresholdMessageKit for storage const serializedMessageKit = encryptionResult.messageKit.toBytes(); // Create metadata const metadata = { id, contentType, size: data.length, createdAt: now, ...(options.metadata && { metadata: options.metadata }), encryptionMetadata: { messageKit: Array.from(serializedMessageKit), conditions: encryptionResult.conditions, }, }; // Store encrypted data using the adapter const result = await this.adapter.store(serializedMessageKit, metadata); return result; } catch (error) { if (error instanceof types_1.TacoStorageError) { throw error; } throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.STORAGE_ERROR, `Failed to store data: ${error.message}`, error); } } /** * Retrieve and decrypt data * @param id - Unique identifier for the data * @param signer - Ethereum signer for decryption * @returns Promise resolving to decrypted data and metadata */ async retrieve(id, signer) { if (!id || typeof id !== 'string') { throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.INVALID_CONFIG, 'ID must be a non-empty string'); } try { // Retrieve encrypted data and metadata from adapter const { encryptedData, metadata } = await this.adapter.retrieve(id); // Reconstruct ThresholdMessageKit from stored data const messageKitBytes = new Uint8Array(metadata.encryptionMetadata.messageKit); const messageKit = taco_1.ThresholdMessageKit.fromBytes(messageKitBytes); // Decrypt the data const decryptedData = await this.encryptionService.decrypt(messageKit, this.provider); return { data: decryptedData, metadata, }; } catch (error) { if (error instanceof types_1.TacoStorageError) { throw error; } throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.RETRIEVAL_ERROR, `Failed to retrieve data: ${error.message}`, error); } } /** * Delete stored data * @param id - Unique identifier for the data * @returns Promise resolving to success status */ async delete(id) { if (!id || typeof id !== 'string') { throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.INVALID_CONFIG, 'ID must be a non-empty string'); } try { return await this.adapter.delete(id); } catch (error) { throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.STORAGE_ERROR, `Failed to delete data: ${error.message}`, error); } } /** * Check if data exists * @param id - Unique identifier for the data * @returns Promise resolving to existence status */ async exists(id) { if (!id || typeof id !== 'string') { throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.INVALID_CONFIG, 'ID must be a non-empty string'); } try { return await this.adapter.exists(id); } catch (error) { throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.STORAGE_ERROR, `Failed to check existence: ${error.message}`, error); } } /** * Get metadata for stored data without decrypting * @param id - Unique identifier for the data * @returns Promise resolving to storage metadata */ async getMetadata(id) { if (!id || typeof id !== 'string') { throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.INVALID_CONFIG, 'ID must be a non-empty string'); } try { const { metadata } = await this.adapter.retrieve(id); return metadata; } catch (error) { if (error instanceof types_1.TacoStorageError) { throw error; } throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.RETRIEVAL_ERROR, `Failed to get metadata: ${error.message}`, error); } } /** * List stored data IDs (if supported by adapter) * @param limit - Maximum number of IDs to return * @param offset - Number of IDs to skip * @returns Promise resolving to array of IDs */ async list(limit, offset) { if (!this.adapter.list) { throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.ADAPTER_ERROR, 'List operation not supported by this adapter'); } try { return await this.adapter.list(limit, offset); } catch (error) { throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.RETRIEVAL_ERROR, `Failed to list data: ${error.message}`, error); } } /** * Get health status of the storage system * @returns Promise resolving to health information */ async getHealth() { try { return await this.adapter.getHealth(); } catch (error) { return { healthy: false, details: { error: error.message, }, }; } } /** * Clean up resources */ async cleanup() { try { await this.adapter.cleanup(); } catch (error) { throw new types_1.TacoStorageError(types_1.TacoStorageErrorType.ADAPTER_ERROR, `Failed to cleanup: ${error.message}`, error); } } /** * Create a new TacoStorage instance with IPFS adapter * @param config - TACo configuration * @param provider - Ethereum provider * @param ipfsConfig - IPFS adapter configuration * @returns Promise resolving to initialized TacoStorage instance */ static async createWithIPFS(config, provider, ipfsConfig) { const { IPFSAdapter } = require('../adapters/ipfs/index'); const adapter = new IPFSAdapter(ipfsConfig); const storage = new TacoStorage(adapter, config, provider); await storage.initialize(); return storage; } /** * Create a new TacoStorage instance with Kubo IPFS adapter * @param config - TACo configuration * @param provider - Ethereum provider * @param kuboConfig - Kubo adapter configuration * @returns Promise resolving to initialized TacoStorage instance */ static async createWithKubo(config, provider, kuboConfig) { const { KuboAdapter } = require('../adapters/ipfs/index'); const adapter = new KuboAdapter(kuboConfig); const storage = new TacoStorage(adapter, config, provider); await storage.initialize(); return storage; } /** * Create a new TacoStorage instance with Helia IPFS adapter * @param config - TACo configuration * @param provider - Ethereum provider * @param heliaConfig - Helia adapter configuration * @returns Promise resolving to initialized TacoStorage instance */ static async createWithHelia(config, provider, heliaConfig) { const { HeliaAdapter } = require('../adapters/ipfs/index'); const adapter = new HeliaAdapter(heliaConfig); const storage = new TacoStorage(adapter, config, provider); await storage.initialize(); return storage; } /** * Create a new TacoStorage instance with SQLite adapter * @param config - TACo configuration * @param provider - Ethereum provider * @param sqliteConfig - SQLite adapter configuration * @returns Promise resolving to initialized TacoStorage instance */ static async createWithSQLite(config, provider, sqliteConfig) { const { SQLiteAdapter } = require('../adapters/sqlite'); const adapter = new SQLiteAdapter(sqliteConfig); const storage = new TacoStorage(adapter, config, provider); await storage.initialize(); return storage; } } exports.TacoStorage = TacoStorage; //# sourceMappingURL=storage.js.map