/** * Content Processing Service * Implements the content processing pipeline as described in the specs * Uses Blake hashing for content integrity and encryption key generation */ import { cryptoService } from './crypto.service'; import { ipfsService } from './ipfs.service'; /** * Interface for processed content metadata */ interface ProcessedContentMetadata { originalFilename: string; normalizedFilename: string; blakeHash: string; ipfsCid: string; combinedKey: string; contentType: string; size: number; timestamp: number; } /** * Service for processing content files * Implements the content processing pipeline: * 1. File discovery * 2. Filename normalization * 3. Original content hashing (Blake) * 4. Content encryption * 5. Encrypted content upload to IPFS */ class ContentProcessorService { /** * Process a file through the content processing pipeline * @param file - File to process * @returns Promise - Metadata of the processed content */ async processFile(file: File): Promise { try { // Step 1: Get file information const originalFilename = file.name; // Step 2: Normalize filename (lowercase and snake_case) const normalizedFilename = this.normalizeFilename(originalFilename); // Step 3: Hash the original content using Blake3 const blakeHash = await cryptoService.hashFileBlake3AsHex(file); // Step 4: Encrypt the content using the Blake hash as the key // Note: This is a placeholder for actual encryption implementation const encryptedContent = await this.encryptContent(file, blakeHash); // Step 5: Upload the encrypted content to IPFS const ipfsCid = await ipfsService.uploadContent(encryptedContent); // Create the combined key (Blake hash + IPFS CID) const combinedKey = cryptoService.combineBlakeHashAndIpfsCid(blakeHash, ipfsCid); // Return the metadata return { originalFilename, normalizedFilename, blakeHash, ipfsCid, combinedKey, contentType: file.type, size: file.size, timestamp: Date.now() }; } catch (error) { console.error('Error processing file:', error); throw error; } } /** * Normalize a filename to lowercase and snake_case * @param filename - Original filename * @returns Normalized filename */ normalizeFilename(filename: string): string { // Remove file extension const parts = filename.split('.'); const extension = parts.pop() || ''; let name = parts.join('.'); // Convert to lowercase name = name.toLowerCase(); // Replace spaces and special characters with underscores name = name.replace(/[^a-z0-9]/g, '_'); // Replace multiple underscores with a single one name = name.replace(/_+/g, '_'); // Remove leading and trailing underscores name = name.replace(/^_+|_+$/g, ''); // Add extension back if it exists if (extension) { name = `${name}.${extension.toLowerCase()}`; } return name; } /** * Encrypt content using the Blake hash as the key * This is a placeholder for actual encryption implementation * @param file - File to encrypt * @param key - Encryption key (Blake hash) * @returns Promise - Encrypted content as string */ async encryptContent(file: File, key: string): Promise { // TODO: Implement actual encryption // For now, we'll just return a mock encrypted content // This should be replaced with actual encryption using the Blake hash as the key // Convert the file to a string const arrayBuffer = await file.arrayBuffer(); const contentBytes = new Uint8Array(arrayBuffer); // Mock encryption by XORing with the key bytes // This is NOT secure and is only for demonstration purposes const keyBytes = cryptoService.hexToBytes(key); const encryptedBytes = new Uint8Array(contentBytes.length); for (let i = 0; i < contentBytes.length; i++) { encryptedBytes[i] = contentBytes[i] ^ keyBytes[i % keyBytes.length]; } // Convert to base64 for storage return btoa(String.fromCharCode.apply(null, Array.from(encryptedBytes))); } /** * Decrypt content using the Blake hash as the key * This is a placeholder for actual decryption implementation * @param encryptedContent - Encrypted content as string * @param key - Decryption key (Blake hash) * @returns Promise - Decrypted content as Uint8Array */ async decryptContent(encryptedContent: string, key: string): Promise { // TODO: Implement actual decryption // For now, we'll just return a mock decrypted content // This should be replaced with actual decryption using the Blake hash as the key // Convert the base64 string to bytes const encryptedBytes = new Uint8Array( atob(encryptedContent).split('').map(c => c.charCodeAt(0)) ); // Mock decryption by XORing with the key bytes // This is NOT secure and is only for demonstration purposes const keyBytes = cryptoService.hexToBytes(key); const decryptedBytes = new Uint8Array(encryptedBytes.length); for (let i = 0; i < encryptedBytes.length; i++) { decryptedBytes[i] = encryptedBytes[i] ^ keyBytes[i % keyBytes.length]; } return decryptedBytes; } } // Create a singleton instance export const contentProcessorService = new ContentProcessorService();