diff --git a/README.md b/README.md index 4ca5b91..c59eaff 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ open http://localhost:8000 ## 🗺️ Development Roadmap -**Current:** v4.01.222 — PWA & File Transfer Edition ✅ +**Current:** v4.01.412 — PWA & File Transfer Edition ✅ * Progressive Web App installation * Secure P2P file transfer system @@ -551,6 +551,6 @@ SecureBit.chat: --- -**Latest Release: v4.01.222** — PWA & Secure File Transfer +**Latest Release: v4.01.412** — PWA & Secure File Transfer diff --git a/SECURITY_DISCLAIMER.md b/SECURITY_DISCLAIMER.md index 6601c86..5bd97a9 100644 --- a/SECURITY_DISCLAIMER.md +++ b/SECURITY_DISCLAIMER.md @@ -1,6 +1,6 @@ # Security Disclaimer and Terms of Use -## 🔒 SecureBit.chat Enhanced Security Edition v4.01.222 +## 🔒 SecureBit.chat Enhanced Security Edition v4.01.412 ### Important Legal Notice @@ -203,6 +203,6 @@ This software is created to: --- *Last Updated: 08.07.2025* -*Version: Enhanced Security Edition v4.01.222* +*Version: Enhanced Security Edition v4.01.412* **USE AT YOUR OWN RISK AND RESPONSIBILITY** \ No newline at end of file diff --git a/index.html b/index.html index e3e6884..d40f953 100644 --- a/index.html +++ b/index.html @@ -161,7 +161,7 @@ icon: "fas fa-shield-halved", color: "orange", title: "12-Layer Military Security", - description: "Revolutionary defense system with ECDH P-384 + AES-GCM 256 + ECDSA. Enhanced Security Edition v4.01.222 provides military-grade protection exceeding government standards." + description: "Revolutionary defense system with ECDH P-384 + AES-GCM 256 + ECDSA. Enhanced Security Edition v4.01.412 provides military-grade protection exceeding government standards." }, { icon: "fas fa-bolt", @@ -511,7 +511,7 @@ Enhanced Security Edition Comparison
- SecureBit.chat v4.01.222 Enhanced Security Edition vs leading secure messengers + SecureBit.chat v4.01.412 Enhanced Security Edition vs leading secure messengers
SecureBit.chat dominates in 11 out of 15 security categories, establishing itself as the most secure P2P messenger available. @@ -3195,7 +3195,7 @@ const downloadMessage = React.createElement('div', { className: 'flex items-center space-x-2' }, [ - React.createElement('span', { key: 'label' }, `📥 Файл получен: ${fileData.fileName} (${sizeMb} MB)`), + React.createElement('span', { key: 'label' }, `📥 File received: ${fileData.fileName} (${sizeMb} MB)`), React.createElement('button', { key: 'btn', className: 'px-3 py-1 rounded bg-blue-600 hover:bg-blue-700 text-white text-xs', @@ -3210,7 +3210,7 @@ setTimeout(() => fileData.revokeObjectURL(url), 15000); } catch (e) { console.error('Download failed:', e); - addMessageWithAutoScroll(`❌ Ошибка загрузки файла: ${String(e?.message || e)}`, 'system'); + addMessageWithAutoScroll(`❌ File upload error: ${String(e?.message || e)}`, 'system'); } } }, 'Скачать') @@ -3221,15 +3221,14 @@ // Error callback (error) => { - // Более мягкая обработка ошибок файлового трансфера - не закрываем сессию console.error('File transfer error:', error); if (error.includes('Connection not ready')) { - addMessageWithAutoScroll(`⚠️ Ошибка передачи файла: соединение не готово. Попробуйте позже.`, 'system'); + addMessageWithAutoScroll(`⚠️ File transfer error: connection not ready. Try again later.`, 'system'); } else if (error.includes('File too large')) { - addMessageWithAutoScroll(`⚠️ Файл слишком большой. Максимальный размер: 100 МБ`, 'system'); + addMessageWithAutoScroll(`⚠️ File is too big. Maximum size: 100 MB`, 'system'); } else { - addMessageWithAutoScroll(`❌ Ошибка передачи файла: ${error}`, 'system'); + addMessageWithAutoScroll(`❌ File transfer error: ${error}`, 'system'); } } ); diff --git a/src/components/ui/FileTransfer.jsx b/src/components/ui/FileTransfer.jsx index 2bd963f..5221405 100644 --- a/src/components/ui/FileTransfer.jsx +++ b/src/components/ui/FileTransfer.jsx @@ -25,8 +25,6 @@ const FileTransferComponent = ({ webrtcManager, isConnected }) => { webrtcManager.setFileTransferCallbacks( // Progress callback - ТОЛЬКО обновляем UI, НЕ отправляем в чат (progress) => { - console.log(`📁 UI Progress: ${progress.fileName}: ${progress.progress.toFixed(1)}% (${progress.status})`); - // Обновляем только локальное состояние const currentTransfers = webrtcManager.getFileTransfers(); setTransfers(currentTransfers); @@ -36,7 +34,6 @@ const FileTransferComponent = ({ webrtcManager, isConnected }) => { // File received callback - добавляем кнопку скачивания в UI (fileData) => { - console.log(`📥 File received in UI: ${fileData.fileName}`); // Добавляем в список готовых к скачиванию setReadyFiles(prev => { // избегаем дублей по fileId @@ -59,7 +56,6 @@ const FileTransferComponent = ({ webrtcManager, isConnected }) => { // Error callback (error) => { - console.error('File transfer error in UI:', error); const currentTransfers = webrtcManager.getFileTransfers(); setTransfers(currentTransfers); @@ -83,19 +79,27 @@ const FileTransferComponent = ({ webrtcManager, isConnected }) => { for (const file of files) { try { - console.log(`🚀 Starting file upload from UI: ${file.name}`); + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Валидация файла перед отправкой + const validation = webrtcManager.validateFile(file); + if (!validation.isValid) { + const errorMessage = validation.errors.join('. '); + alert(`Файл ${file.name} не может быть отправлен: ${errorMessage}`); + continue; + } + await webrtcManager.sendFile(file); } catch (error) { // Более мягкая обработка ошибок - не закрываем сессию - console.error(`Failed to send ${file.name}:`, error); // Показываем пользователю ошибку, но не закрываем соединение if (error.message.includes('Connection not ready')) { alert(`Файл ${file.name} не может быть отправлен сейчас. Проверьте соединение и попробуйте снова.`); - } else if (error.message.includes('File too large')) { - alert(`Файл ${file.name} слишком большой. Максимальный размер: 100 MB`); + } else if (error.message.includes('File too large') || error.message.includes('exceeds maximum')) { + alert(`Файл ${file.name} слишком большой: ${error.message}`); } else if (error.message.includes('Maximum concurrent transfers')) { alert(`Достигнут лимит одновременных передач. Дождитесь завершения текущих передач.`); + } else if (error.message.includes('File type not allowed')) { + alert(`Тип файла ${file.name} не поддерживается: ${error.message}`); } else { alert(`Ошибка отправки файла ${file.name}: ${error.message}`); } diff --git a/src/components/ui/Header.jsx b/src/components/ui/Header.jsx index 35568e8..56c5427 100644 --- a/src/components/ui/Header.jsx +++ b/src/components/ui/Header.jsx @@ -497,7 +497,7 @@ const EnhancedMinimalHeader = ({ React.createElement('p', { key: 'subtitle', className: 'text-xs sm:text-sm text-muted hidden sm:block' - }, 'End-to-end freedom. v4.01.222') + }, 'End-to-end freedom. v4.01.412') ]) ]), diff --git a/src/network/EnhancedSecureWebRTCManager.js b/src/network/EnhancedSecureWebRTCManager.js index 8a44441..d033262 100644 --- a/src/network/EnhancedSecureWebRTCManager.js +++ b/src/network/EnhancedSecureWebRTCManager.js @@ -449,9 +449,20 @@ _initializeMutexSystem() { } // Initialization this.initializeFileTransfer(); - // Small delay for initialization - await new Promise(r => setTimeout(r, 300)); - return !!this.fileTransferSystem; + + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Ждем инициализации с таймаутом + let attempts = 0; + const maxAttempts = 50; // 5 секунд максимум + while (!this.fileTransferSystem && attempts < maxAttempts) { + await new Promise(r => setTimeout(r, 100)); + attempts++; + } + + if (!this.fileTransferSystem) { + throw new Error('File transfer system initialization timeout'); + } + + return true; } catch (e) { console.error('❌ _ensureFileTransferReady failed:', e?.message || e); return false; @@ -1510,6 +1521,12 @@ _initializeMutexSystem() { try { console.log('🔧 Initializing Enhanced Secure File Transfer system...'); + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Проверяем, не инициализирована ли уже система + if (this.fileTransferSystem) { + console.log('✅ File transfer system already initialized'); + return; + } + // CRITICAL FIX: Step-by-step readiness check const channelReady = !!(this.dataChannel && this.dataChannel.readyState === 'open'); if (!channelReady) { @@ -3274,17 +3291,43 @@ async processMessage(data) { await this.fileTransferSystem.handleFileMessage(parsed); return; } - // Attempt lazy initialization on the receiver side - console.warn('⚠️ File transfer system not available, attempting lazy init...'); + + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Автоматическая инициализация файловой системы + console.warn('⚠️ File transfer system not available, attempting automatic initialization...'); try { - await this._ensureFileTransferReady(); - if (this.fileTransferSystem && typeof this.fileTransferSystem.handleFileMessage === 'function') { - await this.fileTransferSystem.handleFileMessage(parsed); + // Проверяем готовность соединения + if (!this.isVerified) { + console.warn('⚠️ Connection not verified, cannot initialize file transfer'); return; } + + if (!this.dataChannel || this.dataChannel.readyState !== 'open') { + console.warn('⚠️ Data channel not open, cannot initialize file transfer'); + return; + } + + // Инициализируем файловую систему + this.initializeFileTransfer(); + + // Ждем инициализации + let attempts = 0; + const maxAttempts = 30; // 3 секунды максимум + while (!this.fileTransferSystem && attempts < maxAttempts) { + await new Promise(resolve => setTimeout(resolve, 100)); + attempts++; + } + + if (this.fileTransferSystem && typeof this.fileTransferSystem.handleFileMessage === 'function') { + console.log('✅ File transfer system initialized, processing message:', parsed.type); + await this.fileTransferSystem.handleFileMessage(parsed); + return; + } else { + console.error('❌ File transfer system initialization failed'); + } } catch (e) { - console.error('❌ Lazy init of file transfer failed:', e?.message || e); + console.error('❌ Automatic file transfer initialization failed:', e?.message || e); } + console.error('❌ File transfer system not available for:', parsed.type); return; // IMPORTANT: Exit after handling } @@ -4134,8 +4177,8 @@ handleSystemMessage(message) { try { await this.establishConnection(); - // CRITICAL: Initialize file transfer immediately - this.initializeFileTransfer(); + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Инициализируем файловую систему для обеих сторон + this.initializeFileTransfer(); } catch (error) { console.error('❌ Error in establishConnection:', error); @@ -4214,6 +4257,26 @@ handleSystemMessage(message) { if (parsed.type && fileMessageTypes.includes(parsed.type)) { console.log('📁 File message intercepted at WebRTC level:', parsed.type); + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Инициализируем файловую систему при получении файловых сообщений + if (!this.fileTransferSystem) { + try { + // Проверяем готовность соединения + if (this.isVerified && this.dataChannel && this.dataChannel.readyState === 'open') { + this.initializeFileTransfer(); + + // Ждем инициализации + let attempts = 0; + const maxAttempts = 30; + while (!this.fileTransferSystem && attempts < maxAttempts) { + await new Promise(resolve => setTimeout(resolve, 100)); + attempts++; + } + } + } catch (initError) { + console.error('❌ Failed to initialize file transfer system for receiver:', initError); + } + } + // Handle directly WITHOUT extra checks if (window.fileTransferSystem) { console.log('📁 Forwarding to global file transfer system:', parsed.type); @@ -6930,14 +6993,14 @@ _getMutexSystemDiagnostics() { console.log('✅ Session verified - setting isVerified to true'); } - // Initialize file transfer system with a delay - setTimeout(() => { - try { - this.initializeFileTransfer(); - } catch (error) { - console.warn('⚠️ File transfer initialization failed during session activation:', error.message); - } - }, 1000); + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Инициализируем файловую систему для обеих сторон + setTimeout(() => { + try { + this.initializeFileTransfer(); + } catch (error) { + console.warn('⚠️ File transfer initialization failed during session activation:', error.message); + } + }, 1000); console.log('✅ Session activation handled successfully'); @@ -7011,11 +7074,20 @@ checkFileTransferReadiness() { dataChannelState: this.dataChannel?.readyState, isConnected: this.isConnected(), isVerified: this.isVerified, + isInitiator: this.isInitiator, hasEncryptionKey: !!this.encryptionKey, hasMacKey: !!this.macKey, - hasMetadataKey: !!this.metadataKey + hasMetadataKey: !!this.metadataKey, + hasKeyFingerprint: !!this.keyFingerprint, + hasSessionSalt: !!this.sessionSalt }, - fileTransferSystem: null + fileTransferSystem: null, + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Дополнительная диагностика + globalState: { + fileTransferActive: window.FILE_TRANSFER_ACTIVE, + hasGlobalFileTransferSystem: !!window.fileTransferSystem, + globalFileTransferSystemType: window.fileTransferSystem?.constructor?.name + } }; if (this.fileTransferSystem) { @@ -7028,6 +7100,103 @@ checkFileTransferReadiness() { return diagnostics; } + + getSupportedFileTypes() { + if (!this.fileTransferSystem) { + return { error: 'File transfer system not initialized' }; + } + + try { + return this.fileTransferSystem.getSupportedFileTypes(); + } catch (error) { + return { error: error.message }; + } + } + + validateFile(file) { + if (!this.fileTransferSystem) { + return { + isValid: false, + errors: ['File transfer system not initialized'], + fileType: null, + fileSize: file?.size || 0, + formattedSize: '0 B' + }; + } + + try { + return this.fileTransferSystem.validateFile(file); + } catch (error) { + return { + isValid: false, + errors: [error.message], + fileType: null, + fileSize: file?.size || 0, + formattedSize: '0 B' + }; + } + } + + getFileTypeInfo() { + if (!this.fileTransferSystem) { + return { error: 'File transfer system not initialized' }; + } + + try { + return this.fileTransferSystem.getFileTypeInfo(); + } catch (error) { + return { error: error.message }; + } + } + + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Метод для принудительной инициализации файловой системы + forceInitializeFileTransfer() { + try { + // Проверяем готовность соединения + if (!this.isVerified) { + throw new Error('Connection not verified'); + } + + if (!this.dataChannel || this.dataChannel.readyState !== 'open') { + throw new Error('Data channel not open'); + } + + if (!this.encryptionKey || !this.macKey) { + throw new Error('Encryption keys not ready'); + } + + // Очищаем существующую систему + if (this.fileTransferSystem) { + this.fileTransferSystem.cleanup(); + this.fileTransferSystem = null; + } + + // Инициализируем новую систему + this.initializeFileTransfer(); + + // Ждем инициализации + let attempts = 0; + const maxAttempts = 50; + while (!this.fileTransferSystem && attempts < maxAttempts) { + // Синхронное ожидание + const start = Date.now(); + while (Date.now() - start < 100) { + // busy wait + } + attempts++; + } + + if (this.fileTransferSystem) { + return true; + } else { + throw new Error('Force initialization timeout'); + } + + } catch (error) { + console.error('❌ Force file transfer initialization failed:', error); + return false; + } + } } export { EnhancedSecureWebRTCManager }; \ No newline at end of file diff --git a/src/pwa/pwa-manager.js b/src/pwa/pwa-manager.js index 75a9d42..90190e8 100644 --- a/src/pwa/pwa-manager.js +++ b/src/pwa/pwa-manager.js @@ -1,5 +1,5 @@ // PWA Offline Manager for SecureBit.chat -// Enhanced Security Edition v4.01.222 +// Enhanced Security Edition v4.01.412 // Handles offline functionality, data synchronization, and user experience class PWAOfflineManager { diff --git a/src/transfer/EnhancedSecureFileTransfer.js b/src/transfer/EnhancedSecureFileTransfer.js index eef24b4..3d623c6 100644 --- a/src/transfer/EnhancedSecureFileTransfer.js +++ b/src/transfer/EnhancedSecureFileTransfer.js @@ -15,13 +15,7 @@ class EnhancedSecureFileTransfer { window.FILE_TRANSFER_ACTIVE = true; window.fileTransferSystem = this; - console.log('🔍 Debug: webrtcManager in constructor:', { - hasWebrtcManager: !!webrtcManager, - webrtcManagerType: webrtcManager.constructor?.name, - hasEncryptionKey: !!webrtcManager.encryptionKey, - hasMacKey: !!webrtcManager.macKey, - hasEcdhKeyPair: !!webrtcManager.ecdhKeyPair - }); + // Transfer settings // Размер чанка по умолчанию (баланс нагрузки и стабильности очереди) @@ -31,6 +25,89 @@ class EnhancedSecureFileTransfer { this.CHUNK_TIMEOUT = 30000; // 30 seconds per chunk this.RETRY_ATTEMPTS = 3; + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Система ограничений по типам файлов + this.FILE_TYPE_RESTRICTIONS = { + // Документы + documents: { + extensions: ['.pdf', '.doc', '.docx', '.txt', '.md', '.rtf', '.odt'], + mimeTypes: [ + 'application/pdf', + 'application/msword', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'text/plain', + 'text/markdown', + 'application/rtf', + 'application/vnd.oasis.opendocument.text' + ], + maxSize: 50 * 1024 * 1024, // 50 MB + category: 'Documents', + description: 'PDF, DOC, TXT, MD, RTF, ODT' + }, + + // Изображения + images: { + extensions: ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.svg', '.ico'], + mimeTypes: [ + 'image/jpeg', + 'image/png', + 'image/gif', + 'image/webp', + 'image/bmp', + 'image/svg+xml', + 'image/x-icon' + ], + maxSize: 25 * 1024 * 1024, // 25 MB + category: 'Images', + description: 'JPG, PNG, GIF, WEBP, BMP, SVG, ICO' + }, + + // Архивы + archives: { + extensions: ['.zip', '.rar', '.7z', '.tar', '.gz', '.bz2', '.xz'], + mimeTypes: [ + 'application/zip', + 'application/x-rar-compressed', + 'application/x-7z-compressed', + 'application/x-tar', + 'application/gzip', + 'application/x-bzip2', + 'application/x-xz' + ], + maxSize: 100 * 1024 * 1024, // 100 MB + category: 'Archives', + description: 'ZIP, RAR, 7Z, TAR, GZ, BZ2, XZ' + }, + + // Медиа файлы + media: { + extensions: ['.mp3', '.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm', '.ogg', '.wav'], + mimeTypes: [ + 'audio/mpeg', + 'video/mp4', + 'video/x-msvideo', + 'video/x-matroska', + 'video/quicktime', + 'video/x-ms-wmv', + 'video/x-flv', + 'video/webm', + 'audio/ogg', + 'audio/wav' + ], + maxSize: 100 * 1024 * 1024, // 100 MB + category: 'Media', + description: 'MP3, MP4, AVI, MKV, MOV, WMV, FLV, WEBM, OGG, WAV' + }, + + // Общие файлы (любые другие типы) + general: { + extensions: [], // Пустой массив означает "все остальные" + mimeTypes: [], // Пустой массив означает "все остальные" + maxSize: 50 * 1024 * 1024, // 50 MB + category: 'General', + description: 'Any file type up to size limits' + } + }; + // Active transfers tracking this.activeTransfers = new Map(); // fileId -> transfer state this.receivingTransfers = new Map(); // fileId -> receiving state @@ -48,7 +125,125 @@ class EnhancedSecureFileTransfer { // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Регистрируем обработчик сообщений this.setupFileMessageHandlers(); - console.log('🔒 Enhanced Secure File Transfer initialized'); + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Устанавливаем ссылку в WebRTC менеджере + if (this.webrtcManager) { + this.webrtcManager.fileTransferSystem = this; + } + } + + // ============================================ + // FILE TYPE VALIDATION SYSTEM + // ============================================ + + // Определяем тип файла по расширению и MIME типу + getFileType(file) { + const fileName = file.name.toLowerCase(); + const fileExtension = fileName.substring(fileName.lastIndexOf('.')); + const mimeType = file.type.toLowerCase(); + + // Проверяем каждый тип файла + for (const [typeKey, typeConfig] of Object.entries(this.FILE_TYPE_RESTRICTIONS)) { + if (typeKey === 'general') continue; // Пропускаем общий тип + + // Проверяем расширение + if (typeConfig.extensions.includes(fileExtension)) { + return { + type: typeKey, + category: typeConfig.category, + description: typeConfig.description, + maxSize: typeConfig.maxSize, + allowed: true + }; + } + + // Проверяем MIME тип + if (typeConfig.mimeTypes.includes(mimeType)) { + return { + type: typeKey, + category: typeConfig.category, + description: typeConfig.description, + maxSize: typeConfig.maxSize, + allowed: true + }; + } + } + + // Если не найден в специфических типах, используем общий + const generalConfig = this.FILE_TYPE_RESTRICTIONS.general; + return { + type: 'general', + category: generalConfig.category, + description: generalConfig.description, + maxSize: generalConfig.maxSize, + allowed: true + }; + } + + // Проверяем, разрешен ли файл для передачи + validateFile(file) { + const fileType = this.getFileType(file); + const errors = []; + + // Проверяем размер файла + if (file.size > fileType.maxSize) { + errors.push(`File size (${this.formatFileSize(file.size)}) exceeds maximum allowed for ${fileType.category} (${this.formatFileSize(fileType.maxSize)})`); + } + + // Проверяем, разрешен ли тип файла + if (!fileType.allowed) { + errors.push(`File type not allowed. Supported types: ${fileType.description}`); + } + + // Проверяем общий лимит размера + if (file.size > this.MAX_FILE_SIZE) { + errors.push(`File size (${this.formatFileSize(file.size)}) exceeds general limit (${this.formatFileSize(this.MAX_FILE_SIZE)})`); + } + + return { + isValid: errors.length === 0, + errors: errors, + fileType: fileType, + fileSize: file.size, + formattedSize: this.formatFileSize(file.size) + }; + } + + // Форматируем размер файла для отображения + formatFileSize(bytes) { + if (bytes === 0) return '0 B'; + const k = 1024; + const sizes = ['B', 'KB', 'MB', 'GB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; + } + + // Получаем список поддерживаемых типов файлов + getSupportedFileTypes() { + const supportedTypes = {}; + + for (const [typeKey, typeConfig] of Object.entries(this.FILE_TYPE_RESTRICTIONS)) { + if (typeKey === 'general') continue; + + supportedTypes[typeKey] = { + category: typeConfig.category, + description: typeConfig.description, + extensions: typeConfig.extensions, + maxSize: this.formatFileSize(typeConfig.maxSize), + maxSizeBytes: typeConfig.maxSize + }; + } + + return supportedTypes; + } + + // Получаем общую информацию о поддерживаемых типах + getFileTypeInfo() { + return { + supportedTypes: this.getSupportedFileTypes(), + generalMaxSize: this.formatFileSize(this.MAX_FILE_SIZE), + generalMaxSizeBytes: this.MAX_FILE_SIZE, + restrictions: this.FILE_TYPE_RESTRICTIONS + }; } // ============================================ @@ -104,16 +299,12 @@ class EnhancedSecureFileTransfer { // ============================================ setupFileMessageHandlers() { - console.log('🔧 Setting up file message handlers'); - // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Ждем готовности dataChannel if (!this.webrtcManager.dataChannel) { - console.log('⏰ DataChannel not ready, deferring setup...'); // Попытаемся настроить через небольшой интервал const setupRetry = setInterval(() => { if (this.webrtcManager.dataChannel) { clearInterval(setupRetry); - console.log('🔄 DataChannel ready, setting up handlers...'); this.setupMessageInterception(); } }, 100); @@ -121,7 +312,6 @@ class EnhancedSecureFileTransfer { // Timeout для предотвращения бесконечного ожидания setTimeout(() => { clearInterval(setupRetry); - console.warn('⚠️ DataChannel setup timeout'); }, 5000); return; @@ -129,15 +319,12 @@ class EnhancedSecureFileTransfer { // Если dataChannel уже готов, сразу настраиваем this.setupMessageInterception(); - - console.log('✅ File message handlers configured'); } // В методе setupMessageInterception(), замените весь метод на: setupMessageInterception() { try { if (!this.webrtcManager.dataChannel) { - console.warn('⚠️ WebRTC manager data channel not available yet'); return; } @@ -145,10 +332,14 @@ class EnhancedSecureFileTransfer { window.FILE_TRANSFER_ACTIVE = true; window.fileTransferSystem = this; + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Устанавливаем ссылку в WebRTC менеджере + if (this.webrtcManager) { + this.webrtcManager.fileTransferSystem = this; + } + // 1. ПЕРЕХВАТ НА УРОВНЕ dataChannel.onmessage if (this.webrtcManager.dataChannel.onmessage) { this.originalOnMessage = this.webrtcManager.dataChannel.onmessage; - console.log('💾 Original onmessage handler saved'); } this.webrtcManager.dataChannel.onmessage = async (event) => { @@ -159,7 +350,6 @@ class EnhancedSecureFileTransfer { const parsed = JSON.parse(event.data); if (this.isFileTransferMessage(parsed)) { - console.log('🛑 FILE MESSAGE BLOCKED FROM CHAT:', parsed.type); await this.handleFileMessage(parsed); return; // КРИТИЧЕСКИ ВАЖНО: НЕ передаем дальше } @@ -179,8 +369,6 @@ class EnhancedSecureFileTransfer { } } }; - - console.log('✅ Message interception set up successfully'); } catch (error) { console.error('❌ Failed to set up message interception:', error); } @@ -201,22 +389,48 @@ class EnhancedSecureFileTransfer { 'file_transfer_error' ]; - const isFileMessage = fileMessageTypes.includes(message.type); - - if (isFileMessage) { - console.log(`🎯 CONFIRMED FILE MESSAGE: ${message.type} - WILL BE BLOCKED FROM CHAT`); - } - - return isFileMessage; + return fileMessageTypes.includes(message.type); } // Обрабатываем файловые сообщения async handleFileMessage(message) { try { - console.log(`🔄 Handling file message: ${message.type}`, { - fileId: message.fileId, - type: message.type - }); + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Проверяем готовность файловой системы + if (!this.webrtcManager.fileTransferSystem) { + try { + // Попытка инициализации файловой системы + if (typeof this.webrtcManager.initializeFileTransfer === 'function') { + this.webrtcManager.initializeFileTransfer(); + + // Ждем инициализации + let attempts = 0; + const maxAttempts = 50; // 5 секунд максимум + while (!this.webrtcManager.fileTransferSystem && attempts < maxAttempts) { + await new Promise(resolve => setTimeout(resolve, 100)); + attempts++; + } + + if (!this.webrtcManager.fileTransferSystem) { + throw new Error('File transfer system initialization timeout'); + } + } else { + throw new Error('initializeFileTransfer method not available'); + } + } catch (initError) { + console.error('❌ Failed to initialize file transfer system:', initError); + // Отправляем ошибку отправителю + if (message.fileId) { + const errorMessage = { + type: 'file_transfer_error', + fileId: message.fileId, + error: 'File transfer system not available', + timestamp: Date.now() + }; + await this.sendSecureMessage(errorMessage); + } + return; + } + } switch (message.type) { case 'file_transfer_start': @@ -269,8 +483,6 @@ class EnhancedSecureFileTransfer { async deriveFileSessionKey(fileId) { try { - console.log('🔑 Deriving file session key for:', fileId); - // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Используем keyFingerprint и sessionSalt // которые уже согласованы между пирами @@ -323,7 +535,6 @@ class EnhancedSecureFileTransfer { created: Date.now() }); - console.log('✅ File session key derived successfully for:', fileId); return { key: fileSessionKey, salt: Array.from(fileSalt) }; } catch (error) { @@ -334,8 +545,6 @@ class EnhancedSecureFileTransfer { async deriveFileSessionKeyFromSalt(fileId, saltArray) { try { - console.log('🔑 Deriving session key from salt for receiver:', fileId); - // Проверка соли if (!saltArray || !Array.isArray(saltArray) || saltArray.length !== 32) { throw new Error(`Invalid salt: ${saltArray?.length || 0} bytes`); @@ -389,7 +598,6 @@ class EnhancedSecureFileTransfer { created: Date.now() }); - console.log('✅ Session key derived successfully for receiver:', fileId); return fileSessionKey; } catch (error) { @@ -409,22 +617,16 @@ class EnhancedSecureFileTransfer { throw new Error('WebRTC Manager not initialized'); } - console.log('🔍 Debug: webrtcManager in sendFile:', { - hasWebrtcManager: !!this.webrtcManager, - webrtcManagerType: this.webrtcManager.constructor?.name, - hasEncryptionKey: !!this.webrtcManager.encryptionKey, - hasMacKey: !!this.webrtcManager.macKey, - isConnected: this.webrtcManager.isConnected?.(), - isVerified: this.webrtcManager.isVerified - }); - - // Validate file + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Валидация файла с новой системой типов if (!file || !file.size) { throw new Error('Invalid file object'); } - if (file.size > this.MAX_FILE_SIZE) { - throw new Error(`File too large. Maximum size: ${this.MAX_FILE_SIZE / 1024 / 1024} MB`); + // Проверяем тип и размер файла + const validation = this.validateFile(file); + if (!validation.isValid) { + const errorMessage = validation.errors.join('. '); + throw new Error(errorMessage); } if (this.activeTransfers.size >= this.MAX_CONCURRENT_TRANSFERS) { @@ -492,16 +694,10 @@ class EnhancedSecureFileTransfer { version: '2.0' }; - console.log('📁 Sending file metadata for:', transferState.file.name); - // Send metadata through secure channel await this.sendSecureMessage(metadata); transferState.status = 'metadata_sent'; - - // ИСПРАВЛЕНИЕ: НЕ отправляем системные сообщения в чат - // Только логируем - console.log(`📁 File metadata sent: ${transferState.file.name} (5% progress)`); } catch (error) { console.error('❌ Failed to send file metadata:', error); @@ -531,23 +727,17 @@ class EnhancedSecureFileTransfer { transferState.sentChunks++; const progress = Math.round((transferState.sentChunks / totalChunks) * 95) + 5; // 5-100% - // ИСПРАВЛЕНИЕ: НЕ отправляем каждый чанк в чат - // Только логируем - console.log(`📤 Chunk sent ${transferState.sentChunks}/${totalChunks} (${progress}%)`); - // Backpressure: ждём разгрузки очереди перед следующим чанком await this.waitForBackpressure(); } transferState.status = 'waiting_confirmation'; - console.log('✅ All chunks sent, waiting for completion confirmation'); // Timeout for completion confirmation setTimeout(() => { if (this.activeTransfers.has(transferState.fileId)) { const state = this.activeTransfers.get(transferState.fileId); if (state.status === 'waiting_confirmation') { - console.log('⏰ Transfer completion timeout, cleaning up'); this.cleanupTransfer(transferState.fileId); } } @@ -689,8 +879,6 @@ class EnhancedSecureFileTransfer { async handleFileTransferStart(metadata) { try { - console.log('📥 Receiving file transfer:', metadata.fileName); - // Validate metadata if (!metadata.fileId || !metadata.fileName || !metadata.fileSize) { throw new Error('Invalid file transfer metadata'); @@ -698,7 +886,6 @@ class EnhancedSecureFileTransfer { // Check if we already have this transfer if (this.receivingTransfers.has(metadata.fileId)) { - console.warn('⚠️ File transfer already in progress:', metadata.fileId); return; } @@ -737,18 +924,12 @@ class EnhancedSecureFileTransfer { }; await this.sendSecureMessage(response); - - // ИСПРАВЛЕНИЕ: НЕ отправляем уведомления в чат - // Только логируем - console.log(`📥 Started receiving file: ${receivingState.fileName} (${(receivingState.fileSize / 1024 / 1024).toFixed(2)} MB)`); // Process buffered chunks if any if (this.pendingChunks.has(metadata.fileId)) { - console.log('🔄 Processing buffered chunks for:', metadata.fileId); const bufferedChunks = this.pendingChunks.get(metadata.fileId); for (const [chunkIndex, chunkMessage] of bufferedChunks.entries()) { - console.log('📦 Processing buffered chunk:', chunkIndex); await this.handleFileChunk(chunkMessage); } @@ -776,8 +957,6 @@ class EnhancedSecureFileTransfer { // Buffer early chunks if transfer not yet initialized if (!receivingState) { - console.log('📦 Buffering early chunk for:', chunkMessage.fileId, 'chunk:', chunkMessage.chunkIndex); - if (!this.pendingChunks.has(chunkMessage.fileId)) { this.pendingChunks.set(chunkMessage.fileId, new Map()); } @@ -791,7 +970,6 @@ class EnhancedSecureFileTransfer { // Check if chunk already received if (receivingState.receivedChunks.has(chunkMessage.chunkIndex)) { - console.log('⚠️ Duplicate chunk received:', chunkMessage.chunkIndex); return; } @@ -812,8 +990,6 @@ class EnhancedSecureFileTransfer { throw new Error('Missing encrypted data'); } - console.log('🔓 Decrypting chunk:', chunkMessage.chunkIndex); - const decryptedChunk = await crypto.subtle.decrypt( { name: 'AES-GCM', @@ -832,14 +1008,6 @@ class EnhancedSecureFileTransfer { receivingState.receivedChunks.set(chunkMessage.chunkIndex, decryptedChunk); receivingState.receivedCount++; - // Update progress - const progress = Math.round((receivingState.receivedCount / receivingState.totalChunks) * 100); - - console.log(`📥 Received chunk ${chunkMessage.chunkIndex + 1}/${receivingState.totalChunks} (${progress}%)`); - - // ИСПРАВЛЕНИЕ: НЕ отправляем уведомления о прогрессе в чат - // Только логируем - // Send chunk confirmation const confirmation = { type: 'chunk_confirmation', @@ -881,8 +1049,6 @@ class EnhancedSecureFileTransfer { async assembleFile(receivingState) { try { - console.log('🔄 Assembling file:', receivingState.fileName); - receivingState.status = 'assembling'; // Verify we have all chunks @@ -979,8 +1145,6 @@ class EnhancedSecureFileTransfer { } this.receivingTransfers.delete(receivingState.fileId); - console.log('✅ File assembly completed:', receivingState.fileName); - } catch (error) { console.error('❌ File assembly failed:', error); receivingState.status = 'failed'; @@ -1017,20 +1181,15 @@ class EnhancedSecureFileTransfer { handleTransferResponse(response) { try { - console.log('📨 File transfer response:', response); - const transferState = this.activeTransfers.get(response.fileId); if (!transferState) { - console.warn('⚠️ Received response for unknown transfer:', response.fileId); return; } if (response.accepted) { - console.log('✅ File transfer accepted by peer'); transferState.status = 'accepted'; } else { - console.log('❌ File transfer rejected by peer:', response.error); transferState.status = 'rejected'; if (this.onError) { @@ -1048,14 +1207,11 @@ class EnhancedSecureFileTransfer { try { const transferState = this.activeTransfers.get(confirmation.fileId); if (!transferState) { - console.warn('⚠️ Received chunk confirmation for unknown transfer:', confirmation.fileId); return; } transferState.confirmedChunks++; transferState.lastChunkTime = Date.now(); - - console.log(`✅ Chunk ${confirmation.chunkIndex} confirmed for ${confirmation.fileId}`); } catch (error) { console.error('❌ Failed to handle chunk confirmation:', error); } @@ -1063,16 +1219,12 @@ class EnhancedSecureFileTransfer { handleTransferComplete(completion) { try { - console.log('🏁 Transfer completion:', completion); - const transferState = this.activeTransfers.get(completion.fileId); if (!transferState) { - console.warn('⚠️ Received completion for unknown transfer:', completion.fileId); return; } if (completion.success) { - console.log('✅ File transfer completed successfully'); transferState.status = 'completed'; transferState.endTime = Date.now(); @@ -1086,7 +1238,6 @@ class EnhancedSecureFileTransfer { }); } } else { - console.log('❌ File transfer failed:', completion.error); transferState.status = 'failed'; if (this.onError) { @@ -1103,8 +1254,6 @@ class EnhancedSecureFileTransfer { handleTransferError(errorMessage) { try { - console.error('❌ Transfer error received:', errorMessage); - const transferState = this.activeTransfers.get(errorMessage.fileId); if (transferState) { transferState.status = 'failed'; @@ -1241,32 +1390,37 @@ class EnhancedSecureFileTransfer { maxFileSize: this.MAX_FILE_SIZE, chunkSize: this.CHUNK_SIZE, hasWebrtcManager: !!this.webrtcManager, - isConnected: this.webrtcManager?.isConnected?.() || false + isConnected: this.webrtcManager?.isConnected?.() || false, + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Дополнительная диагностика + hasDataChannel: !!this.webrtcManager?.dataChannel, + dataChannelState: this.webrtcManager?.dataChannel?.readyState, + isVerified: this.webrtcManager?.isVerified, + hasEncryptionKey: !!this.webrtcManager?.encryptionKey, + hasMacKey: !!this.webrtcManager?.macKey, + linkedToWebRTCManager: this.webrtcManager?.fileTransferSystem === this, + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Информация о поддерживаемых типах файлов + supportedFileTypes: this.getSupportedFileTypes(), + fileTypeInfo: this.getFileTypeInfo() }; } cleanup() { - console.log('🧹 Cleaning up file transfer system'); - // ИСПРАВЛЕНИЕ: Очищаем глобальные флаги window.FILE_TRANSFER_ACTIVE = false; window.fileTransferSystem = null; // ИСПРАВЛЕНИЕ: Восстанавливаем ВСЕ перехваченные методы if (this.webrtcManager && this.webrtcManager.dataChannel && this.originalOnMessage) { - console.log('🔄 Restoring original onmessage handler'); this.webrtcManager.dataChannel.onmessage = this.originalOnMessage; this.originalOnMessage = null; } if (this.webrtcManager && this.originalProcessMessage) { - console.log('🔄 Restoring original processMessage handler'); this.webrtcManager.processMessage = this.originalProcessMessage; this.originalProcessMessage = null; } if (this.webrtcManager && this.originalRemoveSecurityLayers) { - console.log('🔄 Restoring original removeSecurityLayers handler'); this.webrtcManager.removeSecurityLayers = this.originalRemoveSecurityLayers; this.originalRemoveSecurityLayers = null; } @@ -1288,8 +1442,6 @@ class EnhancedSecureFileTransfer { this.sessionKeys.clear(); this.transferNonces.clear(); this.processedChunks.clear(); - - console.log('✅ File transfer system cleaned up'); } // ============================================ @@ -1297,38 +1449,67 @@ class EnhancedSecureFileTransfer { // ============================================ onSessionUpdate(sessionData) { - console.log('🔄 File transfer system: session updated', sessionData); - // Clear session keys cache for resync this.sessionKeys.clear(); - - console.log('✅ File transfer keys cache cleared for resync'); - - // If there are active transfers, log warning - if (this.activeTransfers.size > 0 || this.receivingTransfers.size > 0) { - console.warn('⚠️ Session updated during active file transfers - may cause issues'); - } } // ============================================ // DEBUGGING AND DIAGNOSTICS // ============================================ + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Метод для диагностики проблем с передачей файлов + diagnoseFileTransferIssue() { + const diagnosis = { + timestamp: new Date().toISOString(), + fileTransferSystem: { + initialized: !!this, + hasWebrtcManager: !!this.webrtcManager, + webrtcManagerType: this.webrtcManager?.constructor?.name, + linkedToWebRTCManager: this.webrtcManager?.fileTransferSystem === this + }, + webrtcManager: { + hasDataChannel: !!this.webrtcManager?.dataChannel, + dataChannelState: this.webrtcManager?.dataChannel?.readyState, + isConnected: this.webrtcManager?.isConnected?.() || false, + isVerified: this.webrtcManager?.isVerified, + hasEncryptionKey: !!this.webrtcManager?.encryptionKey, + hasMacKey: !!this.webrtcManager?.macKey, + hasKeyFingerprint: !!this.webrtcManager?.keyFingerprint, + hasSessionSalt: !!this.webrtcManager?.sessionSalt + }, + globalState: { + fileTransferActive: window.FILE_TRANSFER_ACTIVE, + hasGlobalFileTransferSystem: !!window.fileTransferSystem, + globalFileTransferSystemType: window.fileTransferSystem?.constructor?.name + }, + transfers: { + activeTransfers: this.activeTransfers.size, + receivingTransfers: this.receivingTransfers.size, + pendingChunks: this.pendingChunks.size, + sessionKeys: this.sessionKeys.size + }, + // КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Информация о поддерживаемых типах файлов + fileTypeSupport: { + supportedTypes: this.getSupportedFileTypes(), + generalMaxSize: this.formatFileSize(this.MAX_FILE_SIZE), + restrictions: Object.keys(this.FILE_TYPE_RESTRICTIONS) + } + }; + + return diagnosis; + } + async debugKeyDerivation(fileId) { try { - console.log('🔍 Debug: Testing key derivation for:', fileId); - if (!this.webrtcManager.keyFingerprint || !this.webrtcManager.sessionSalt) { throw new Error('Session data not available'); } // Test sender derivation const senderResult = await this.deriveFileSessionKey(fileId); - console.log('✅ Sender key derived successfully'); // Test receiver derivation with same salt const receiverKey = await this.deriveFileSessionKeyFromSalt(fileId, senderResult.salt); - console.log('✅ Receiver key derived successfully'); // Test encryption/decryption const testData = new TextEncoder().encode('test data'); @@ -1349,7 +1530,6 @@ class EnhancedSecureFileTransfer { const decryptedText = new TextDecoder().decode(decrypted); if (decryptedText === 'test data') { - console.log('✅ Cross-key encryption/decryption test successful'); return { success: true, message: 'All tests passed' }; } else { throw new Error('Decryption verification failed'); @@ -1368,8 +1548,6 @@ class EnhancedSecureFileTransfer { // Если переопределение processMessage не работает, // используйте этот метод для явной регистрации обработчика registerWithWebRTCManager() { - console.log('🔧 Registering file transfer handler with WebRTC manager'); - if (!this.webrtcManager) { throw new Error('WebRTC manager not available'); } @@ -1380,16 +1558,12 @@ class EnhancedSecureFileTransfer { // КРИТИЧЕСКИ ВАЖНО: Устанавливаем обработчик файловых сообщений this.webrtcManager.setFileMessageHandler = (handler) => { this.webrtcManager._fileMessageHandler = handler; - console.log('✅ File message handler registered in WebRTC manager'); }; // Регистрируем наш обработчик this.webrtcManager.setFileMessageHandler((message) => { - console.log('📁 File message via registered handler:', message.type); return this.handleFileMessage(message); }); - - console.log('✅ File transfer handler registered'); } // Метод для прямого вызова из WebRTC менеджера @@ -1400,7 +1574,6 @@ class EnhancedSecureFileTransfer { const parsed = JSON.parse(event.data); if (fileTransferSystem.isFileTransferMessage(parsed)) { - console.log('📁 File message filtered by static method:', parsed.type); await fileTransferSystem.handleFileMessage(parsed); return true; // Сообщение обработано } diff --git a/sw.js b/sw.js index f64f5ff..d7e32be 100644 --- a/sw.js +++ b/sw.js @@ -1,5 +1,5 @@ // SecureBit.chat Service Worker -// Enhanced Security Edition v4.01.222 +// Enhanced Security Edition v4.01.412 const CACHE_NAME = 'securebit-v4.0.3'; const STATIC_CACHE = 'securebit-static-v4.0.3'; @@ -352,4 +352,4 @@ self.addEventListener('unhandledrejection', (event) => { console.error('❌ Service Worker unhandled rejection:', event.reason); }); -console.log('🔧 SecureBit.chat Service Worker loaded - Enhanced Security Edition v4.01.222'); \ No newline at end of file +console.log('🔧 SecureBit.chat Service Worker loaded - Enhanced Security Edition v4.01.412'); \ No newline at end of file