diff --git a/src/network/EnhancedSecureWebRTCManager.js b/src/network/EnhancedSecureWebRTCManager.js index 4c7fca0..0665dc1 100644 --- a/src/network/EnhancedSecureWebRTCManager.js +++ b/src/network/EnhancedSecureWebRTCManager.js @@ -2,7 +2,7 @@ class EnhancedSecureWebRTCManager { constructor(onMessage, onStatusChange, onKeyExchange, onVerificationRequired, onAnswerError = null) { // Проверяем доступность глобального объекта if (!window.EnhancedSecureCryptoUtils) { - throw new Error('EnhancedSecureCryptoUtils не загружен. Убедитесь, что модуль загружен первым.'); + throw new Error('EnhancedSecureCryptoUtils is not loaded. Please ensure the module is loaded first.'); } this.peerConnection = null; @@ -109,7 +109,7 @@ class EnhancedSecureWebRTCManager { return false; } - // Отправляем сигнал о ротации ключей партнеру + // Sending key rotation signal to partner. const rotationSignal = { type: 'key_rotation_signal', newVersion: this.currentKeyVersion + 1, @@ -118,14 +118,14 @@ class EnhancedSecureWebRTCManager { this.dataChannel.send(JSON.stringify(rotationSignal)); - // Ждем подтверждения от партнера перед ротацией + // Waiting for partner's confirmation before rotation. return new Promise((resolve) => { this.pendingRotation = { newVersion: this.currentKeyVersion + 1, resolve: resolve }; - // Таймаут на случай если партнер не ответит + // Timeout in case the partner doesn't respond. setTimeout(() => { if (this.pendingRotation) { this.pendingRotation.resolve(false); @@ -159,7 +159,7 @@ class EnhancedSecureWebRTCManager { // PFS: Get keys for specific version (for decryption) getKeysForVersion(version) { - // Сначала проверяем старые ключи (включая версию 0) + // First, we check the old keys (including version 0). const oldKeySet = this.oldKeys.get(version); if (oldKeySet && oldKeySet.encryptionKey && oldKeySet.macKey && oldKeySet.metadataKey) { return { @@ -169,7 +169,7 @@ class EnhancedSecureWebRTCManager { }; } - // Если это текущая версия, возвращаем текущие ключи + // If this is the current version, return the current keys. if (version === this.currentKeyVersion) { if (this.encryptionKey && this.macKey && this.metadataKey) { return { @@ -213,12 +213,12 @@ class EnhancedSecureWebRTCManager { } else if (state === 'connected' && this.isVerified) { this.onStatusChange('connected'); } else if (state === 'disconnected' || state === 'closed') { - // Если это намеренное отключение, сразу очищаем + // If this is an intentional disconnect, clear immediately. if (this.intentionalDisconnect) { this.onStatusChange('disconnected'); setTimeout(() => this.cleanupConnection(), 100); } else { - // Неожиданное отключение - пытаемся уведомить партнера + // Unexpected disconnection — attempting to notify partner. this.onStatusChange('reconnecting'); this.handleUnexpectedDisconnect(); } @@ -261,11 +261,11 @@ class EnhancedSecureWebRTCManager { if (!this.intentionalDisconnect) { this.onStatusChange('reconnecting'); - this.onMessage('🔄 Канал данных закрыт. Попытка восстановления...', 'system'); + this.onMessage('🔄 Data channel closed. Attempting recovery...', 'system'); this.handleUnexpectedDisconnect(); } else { this.onStatusChange('disconnected'); - this.onMessage('🔌 Соединение закрыто', 'system'); + this.onMessage('🔌 Connection closed', 'system'); } this.stopHeartbeat(); @@ -334,22 +334,22 @@ class EnhancedSecureWebRTCManager { throw new Error(`Invalid key types for version ${keyVersion}`); } - // Используем более гибкую проверку sequence number + // Using a more flexible sequence number check const decryptedData = await window.EnhancedSecureCryptoUtils.decryptMessage( payload.data, keys.encryptionKey, keys.macKey, keys.metadataKey, - null // Отключаем строгую проверку sequence number + null // Disabling strict sequence number verification ); - // Проверяем replay attack по messageId + // Checking for replay attack using messageId if (this.processedMessageIds.has(decryptedData.messageId)) { throw new Error('Duplicate message detected - possible replay attack'); } this.processedMessageIds.add(decryptedData.messageId); - // Обновляем ожидаемый sequence number более гибко + // Updating expected sequence number more flexibly if (decryptedData.sequenceNumber >= this.expectedSequenceNumber) { this.expectedSequenceNumber = decryptedData.sequenceNumber + 1; } @@ -411,13 +411,13 @@ class EnhancedSecureWebRTCManager { window.EnhancedSecureCryptoUtils.secureLog.log('error', 'Message processing error', { error: error.message }); - this.onMessage(`❌ Ошибка обработки: ${error.message}`, 'system'); + this.onMessage(`❌ Processing error: ${error.message}`, 'system'); } }; this.dataChannel.onerror = (error) => { console.error('Data channel error:', error); - this.onMessage('❌ Ошибка канала данных', 'system'); + this.onMessage('❌ Data channel error', 'system'); }; } @@ -546,7 +546,7 @@ class EnhancedSecureWebRTCManager { }); if (!this.validateEnhancedOfferData(offerData)) { - throw new Error('Неверный формат данных подключения'); + throw new Error('Invalid connection data format'); } // Check rate limiting @@ -602,7 +602,7 @@ class EnhancedSecureWebRTCManager { privateKeyType: typeof this.ecdhKeyPair?.privateKey, privateKeyAlgorithm: this.ecdhKeyPair?.privateKey?.algorithm?.name }); - throw new Error('Локальный ECDH приватный ключ не является CryptoKey'); + throw new Error('The local ECDH private key is not a valid CryptoKey.'); } if (!(peerECDHPublicKey instanceof CryptoKey)) { @@ -610,7 +610,7 @@ class EnhancedSecureWebRTCManager { publicKeyType: typeof peerECDHPublicKey, publicKeyAlgorithm: peerECDHPublicKey?.algorithm?.name }); - throw new Error('ECDH публичный ключ собеседника не является CryptoKey'); + throw new Error('The peer"s ECDH public key is not a valid CryptoKey'); } // Store peer's public key for PFS key rotation @@ -745,22 +745,22 @@ class EnhancedSecureWebRTCManager { async handleSecureAnswer(answerData) { try { if (!answerData || answerData.type !== 'enhanced_secure_answer' || !answerData.sdp) { - throw new Error('Неверный формат ответа'); + throw new Error('Invalid response format'); } // Import peer's ECDH public key from the signed package if (!answerData.ecdhPublicKey || !answerData.ecdhPublicKey.keyData) { - throw new Error('Отсутствуют данные ECDH публичного ключа'); + throw new Error('Missing ECDH public key data'); } // First, import and verify the ECDSA public key for signature verification if (!answerData.ecdsaPublicKey || !answerData.ecdsaPublicKey.keyData) { - throw new Error('Отсутствуют данные ECDSA публичного ключа для верификации подписи'); + throw new Error('Missing ECDSA public key data for signature verification'); } // Additional MITM protection: Validate answer data structure if (!answerData.timestamp || !answerData.version) { - throw new Error('Отсутствуют обязательные поля в данных ответа - возможная MITM атака'); + throw new Error('Missing required fields in response data – possible MITM attack'); } // MITM Protection: Verify session ID if present (for enhanced security) @@ -769,7 +769,7 @@ class EnhancedSecureWebRTCManager { expectedSessionId: this.sessionId, receivedSessionId: answerData.sessionId }); - throw new Error('Несоответствие идентификатора сессии - возможная MITM атака'); + throw new Error('Session ID mismatch – possible MITM attack'); } // Check for replay attacks (reject answers older than 1 hour) @@ -782,10 +782,10 @@ class EnhancedSecureWebRTCManager { // Уведомляем основной код о ошибке replay attack if (this.onAnswerError) { - this.onAnswerError('replay_attack', 'Данные ответа слишком старые - возможная атака повтора'); + this.onAnswerError('replay_attack', 'Response data is too old – possible replay attack'); } - throw new Error('Данные ответа слишком старые - возможная атака повтора'); + throw new Error('Response data is too old – possible replay attack'); } // Check protocol version compatibility @@ -823,7 +823,7 @@ class EnhancedSecureWebRTCManager { timestamp: answerData.timestamp, version: answerData.version }); - throw new Error('Недействительная подпись ECDSA ключа - возможная MITM атака'); + throw new Error('Invalid ECDSA key signature – possible MITM attack'); } window.EnhancedSecureCryptoUtils.secureLog.log('info', 'ECDSA signature verification passed', { @@ -842,7 +842,7 @@ class EnhancedSecureWebRTCManager { window.EnhancedSecureCryptoUtils.secureLog.log('error', 'Invalid session salt detected - possible session hijacking', { saltLength: this.sessionSalt ? this.sessionSalt.length : 0 }); - throw new Error('Недействительная сессионная соль - возможная атака перехвата сессии'); + throw new Error('Invalid session salt – possible session hijacking attempt'); } // Verify that the session salt hasn't been tampered with @@ -858,7 +858,7 @@ class EnhancedSecureWebRTCManager { privateKeyType: typeof this.ecdhKeyPair?.privateKey, privateKeyAlgorithm: this.ecdhKeyPair?.privateKey?.algorithm?.name }); - throw new Error('Локальный ECDH приватный ключ не является CryptoKey'); + throw new Error('Local ECDH private key is not a CryptoKey'); } if (!(peerPublicKey instanceof CryptoKey)) { @@ -866,7 +866,7 @@ class EnhancedSecureWebRTCManager { publicKeyType: typeof peerPublicKey, publicKeyAlgorithm: peerPublicKey?.algorithm?.name }); - throw new Error('ECDH публичный ключ собеседника не является CryptoKey'); + throw new Error('Peer ECDH public key is not a CryptoKey'); } // Store peer's public key for PFS key rotation @@ -898,7 +898,7 @@ class EnhancedSecureWebRTCManager { macKeyAlgorithm: this.macKey?.algorithm?.name, metadataKeyAlgorithm: this.metadataKey?.algorithm?.name }); - throw new Error('Недействительные типы ключей после вывода'); + throw new Error('Invalid key types after export'); } window.EnhancedSecureCryptoUtils.secureLog.log('info', 'Encryption keys set in handleSecureAnswer', { @@ -938,8 +938,7 @@ class EnhancedSecureWebRTCManager { } catch (error) { console.error('Enhanced secure answer handling failed:', error); this.onStatusChange('failed'); - - // Уведомляем основной код о критических ошибках + if (this.onAnswerError) { if (error.message.includes('слишком старые') || error.message.includes('too old')) { this.onAnswerError('replay_attack', error.message); @@ -957,7 +956,7 @@ class EnhancedSecureWebRTCManager { initiateVerification() { if (this.isInitiator) { // Initiator waits for verification confirmation - this.onMessage('🔐 Подтвердите код безопасности с собеседником для завершения подключения', 'system'); + this.onMessage('🔐 Confirm the security code with your peer to complete the connection', 'system'); } else { // Responder confirms verification automatically if codes match this.confirmVerification(); @@ -977,11 +976,11 @@ class EnhancedSecureWebRTCManager { this.dataChannel.send(JSON.stringify(verificationPayload)); this.isVerified = true; this.onStatusChange('connected'); - this.onMessage('✅ Верификация прошла успешно. Канал защищен!', 'system'); + this.onMessage('✅ Verification successful. The channel is now secure!', 'system'); this.processMessageQueue(); } catch (error) { console.error('Verification failed:', error); - this.onMessage('❌ Ошибка верификации', 'system'); + this.onMessage('❌ Verification failed', 'system'); } } @@ -997,10 +996,10 @@ class EnhancedSecureWebRTCManager { this.dataChannel.send(JSON.stringify(responsePayload)); this.isVerified = true; this.onStatusChange('connected'); - this.onMessage('✅ Верификация прошла успешно. Канал защищен!', 'system'); + this.onMessage('✅ Verification successful. The channel is now secure!', 'system'); this.processMessageQueue(); } else { - this.onMessage('❌ Код верификации не совпадает! Возможна атака!', 'system'); + this.onMessage('❌ Verification code mismatch! Possible MITM attack detected. Connection aborted for safety!', 'system'); this.disconnect(); } } @@ -1009,10 +1008,10 @@ class EnhancedSecureWebRTCManager { if (data.verified) { this.isVerified = true; this.onStatusChange('connected'); - this.onMessage('✅ Верификация прошла успешно. Канал защищен!', 'system'); + this.onMessage('✅ Verification successful. The channel is now secure.!', 'system'); this.processMessageQueue(); } else { - this.onMessage('❌ Верификация не прошла!', 'system'); + this.onMessage('❌ Verification failed!', 'system'); this.disconnect(); } } @@ -1137,7 +1136,7 @@ class EnhancedSecureWebRTCManager { async sendSecureMessage(message) { if (!this.isConnected() || !this.isVerified) { this.messageQueue.push(message); - throw new Error('Соединение не готово. Сообщение добавлено в очередь.'); + throw new Error('Connection not ready. Message queued for sending.'); } // Validate encryption keys @@ -1149,7 +1148,7 @@ class EnhancedSecureWebRTCManager { isConnected: this.isConnected(), isVerified: this.isVerified }); - throw new Error('Ключи шифрования не инициализированы. Проверьте соединение.'); + throw new Error('Encryption keys not initialized. Please check the connection.'); } try { @@ -1273,17 +1272,14 @@ class EnhancedSecureWebRTCManager { } disconnect() { - // Устанавливаем флаг намеренного отключения this.intentionalDisconnect = true; window.EnhancedSecureCryptoUtils.secureLog.log('info', 'Starting intentional disconnect'); - - // Отправляем уведомление несколько раз для надежности + this.sendDisconnectNotification(); - - // Ждем немного для доставки уведомления, затем очищаем + setTimeout(() => { - this.sendDisconnectNotification(); // Еще одна попытка + this.sendDisconnectNotification(); }, 100); setTimeout(() => { @@ -1294,7 +1290,7 @@ class EnhancedSecureWebRTCManager { handleUnexpectedDisconnect() { this.sendDisconnectNotification(); this.isVerified = false; - this.onMessage('🔌 Соединение потеряно. Попытка переподключения...', 'system'); + this.onMessage('🔌 Connection lost. Attempting to reconnect...', 'system'); setTimeout(() => { if (!this.intentionalDisconnect) { @@ -1311,8 +1307,7 @@ class EnhancedSecureWebRTCManager { timestamp: Date.now(), reason: this.intentionalDisconnect ? 'user_disconnect' : 'connection_lost' }; - - // Пытаемся отправить уведомление несколько раз + for (let i = 0; i < 3; i++) { try { this.dataChannel.send(JSON.stringify(notification)); @@ -1322,7 +1317,7 @@ class EnhancedSecureWebRTCManager { }); break; } catch (sendError) { - if (i === 2) { // Последняя попытка + if (i === 2) { window.EnhancedSecureCryptoUtils.secureLog.log('error', 'Failed to send disconnect notification', { error: sendError.message }); @@ -1338,27 +1333,24 @@ class EnhancedSecureWebRTCManager { } attemptReconnection() { - this.onMessage('❌ Не удается переподключиться. Требуется новое соединение.', 'system'); + this.onMessage('❌ Unable to reconnect. A new connection is required.', 'system'); this.cleanupConnection(); } handlePeerDisconnectNotification(data) { const reason = data.reason || 'unknown'; - const reasonText = reason === 'user_disconnect' ? 'намеренно отключился' : 'потерял соединение'; + const reasonText = reason === 'user_disconnect' ? 'manually disconnected.' : 'connection lost.'; - this.onMessage(`👋 Собеседник ${reasonText}`, 'system'); + this.onMessage(`👋 Peer ${reasonText}`, 'system'); this.onStatusChange('peer_disconnected'); - - // Устанавливаем флаг что это не наше намеренное отключение + this.intentionalDisconnect = false; this.isVerified = false; this.stopHeartbeat(); - // Очищаем UI данные - this.onKeyExchange(''); // Очищаем отпечаток - this.onVerificationRequired(''); // Очищаем код верификации - - // Очищаем соединение через небольшую задержку + this.onKeyExchange(''); + this.onVerificationRequired(''); + setTimeout(() => { this.cleanupConnection(); }, 2000); @@ -1373,8 +1365,7 @@ class EnhancedSecureWebRTCManager { this.isVerified = false; this.processedMessageIds.clear(); this.messageCounter = 0; - - // Полная очистка всех криптографических данных + this.encryptionKey = null; this.macKey = null; this.metadataKey = null; @@ -1384,21 +1375,21 @@ class EnhancedSecureWebRTCManager { this.peerPublicKey = null; this.verificationCode = null; - // PFS: Очистка всех версий ключей + // PFS: Clearing all key versions this.keyVersions.clear(); this.oldKeys.clear(); this.currentKeyVersion = 0; this.lastKeyRotation = Date.now(); - // Очистка пар ключей + // Clearing key pairs this.ecdhKeyPair = null; this.ecdsaKeyPair = null; - // Сброс счетчиков сообщений + // Resetting message counters this.sequenceNumber = 0; this.expectedSequenceNumber = 0; - // Сброс флагов безопасности + // Security flags reset completed this.securityFeatures = { hasEncryption: false, hasECDH: false, @@ -1412,7 +1403,7 @@ class EnhancedSecureWebRTCManager { hasPFS: false }; - // Закрытие соединений + // Closing connections if (this.dataChannel) { this.dataChannel.close(); this.dataChannel = null; @@ -1422,23 +1413,22 @@ class EnhancedSecureWebRTCManager { this.peerConnection = null; } - // Очистка очереди сообщений + // Clearing message queue this.messageQueue = []; - // ВАЖНО: Очистка логов безопасности + // IMPORTANT: Clearing security logs window.EnhancedSecureCryptoUtils.secureLog.clearLogs(); - // Уведомляем UI о полной очистке + // Notifying the UI about complete cleanup this.onStatusChange('disconnected'); this.onKeyExchange(''); this.onVerificationRequired(''); window.EnhancedSecureCryptoUtils.secureLog.log('info', 'Connection cleaned up completely'); - // Сброс флага намеренного отключения + // Resetting the intentional disconnect flag this.intentionalDisconnect = false; - - // Принудительная сборка мусора + if (window.gc) { window.gc(); }