feat: Add logging for packet details before sending, including attachment count and details
This commit is contained in:
@@ -752,7 +752,11 @@ object MessageCrypto {
|
||||
* Использует PBKDF2 + AES-CBC с тем же ключом что и основное сообщение
|
||||
*
|
||||
* В RN: encodeWithPassword(key.toString('utf-8'), JSON.stringify(reply))
|
||||
* где key = Buffer.concat([chacha_key, nonce]) - 56 bytes as UTF-8 string
|
||||
* где key = Buffer.concat([chacha_key, nonce]) - 56 bytes
|
||||
*
|
||||
* ВАЖНО: JavaScript Buffer.toString('utf-8') на невалидных UTF-8 байтах
|
||||
* заменяет их на U+FFFD (replacement character). Это поведение нужно
|
||||
* воспроизвести в Kotlin для совместимости.
|
||||
*
|
||||
* Формат выхода: "ivBase64:ciphertextBase64" (совместим с desktop)
|
||||
*/
|
||||
@@ -762,9 +766,11 @@ object MessageCrypto {
|
||||
android.util.Log.d("MessageCrypto", " - ReplyJson length: ${replyJson.length}")
|
||||
android.util.Log.d("MessageCrypto", " - PlainKeyAndNonce length: ${plainKeyAndNonce.size}")
|
||||
|
||||
// Convert keyAndNonce to UTF-8 string (as password) - same as RN: key.toString('utf-8')
|
||||
val password = String(plainKeyAndNonce, Charsets.UTF_8)
|
||||
// Convert keyAndNonce to string - simulate JS Buffer.toString('utf-8') behavior
|
||||
// which replaces invalid UTF-8 sequences with U+FFFD
|
||||
val password = bytesToJsUtf8String(plainKeyAndNonce)
|
||||
android.util.Log.d("MessageCrypto", " - Password length: ${password.length}")
|
||||
android.util.Log.d("MessageCrypto", " - Password char codes: ${password.take(5).map { it.code }}")
|
||||
|
||||
// Compress with pako (deflate)
|
||||
val deflater = java.util.zip.Deflater()
|
||||
@@ -786,7 +792,7 @@ object MessageCrypto {
|
||||
)
|
||||
val secretKey = factory.generateSecret(spec)
|
||||
val keyBytes = secretKey.encoded
|
||||
android.util.Log.d("MessageCrypto", " - PBKDF2 key derived: ${keyBytes.size} bytes")
|
||||
android.util.Log.d("MessageCrypto", " - PBKDF2 key derived: ${keyBytes.toHex()}")
|
||||
|
||||
// Generate random IV (16 bytes)
|
||||
val iv = ByteArray(16)
|
||||
@@ -815,6 +821,25 @@ object MessageCrypto {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts bytes to string mimicking JavaScript's Buffer.toString('utf-8') behavior.
|
||||
* Invalid UTF-8 sequences are replaced with U+FFFD (replacement character).
|
||||
*/
|
||||
private fun bytesToJsUtf8String(bytes: ByteArray): String {
|
||||
// CharsetDecoder with REPLACE action mimics JS behavior
|
||||
val decoder = Charsets.UTF_8.newDecoder()
|
||||
decoder.onMalformedInput(java.nio.charset.CodingErrorAction.REPLACE)
|
||||
decoder.onUnmappableCharacter(java.nio.charset.CodingErrorAction.REPLACE)
|
||||
decoder.replaceWith("\uFFFD")
|
||||
|
||||
return try {
|
||||
decoder.decode(java.nio.ByteBuffer.wrap(bytes)).toString()
|
||||
} catch (e: Exception) {
|
||||
// Fallback to standard UTF-8 (shouldn't happen with REPLACE action)
|
||||
String(bytes, Charsets.UTF_8)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔥 Расшифровывает reply blob из attachments (как в React Native)
|
||||
* Формат входа: "ivBase64:ciphertextBase64"
|
||||
@@ -842,8 +867,10 @@ object MessageCrypto {
|
||||
val ciphertext = Base64.decode(parts[1], Base64.DEFAULT)
|
||||
android.util.Log.d("MessageCrypto", " - IV size: ${iv.size}, Ciphertext size: ${ciphertext.size}")
|
||||
|
||||
// Password from keyAndNonce
|
||||
val password = String(plainKeyAndNonce, Charsets.UTF_8)
|
||||
// Password from keyAndNonce - use same JS-like UTF-8 conversion
|
||||
val password = bytesToJsUtf8String(plainKeyAndNonce)
|
||||
android.util.Log.d("MessageCrypto", " - Password length: ${password.length}")
|
||||
android.util.Log.d("MessageCrypto", " - Password char codes: ${password.take(5).map { it.code }}")
|
||||
|
||||
// PBKDF2 key derivation
|
||||
val factory = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
|
||||
@@ -855,6 +882,7 @@ object MessageCrypto {
|
||||
)
|
||||
val secretKey = factory.generateSecret(spec)
|
||||
val keyBytes = secretKey.encoded
|
||||
android.util.Log.d("MessageCrypto", " - PBKDF2 key derived: ${keyBytes.toHex()}")
|
||||
|
||||
// AES-CBC decryption
|
||||
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
|
||||
|
||||
@@ -224,11 +224,18 @@ fun ChatDetailScreen(
|
||||
var showEmojiPicker by remember { mutableStateOf(false) }
|
||||
val emojiPanelHeight = if (imeHeight > 50.dp) imeHeight else 280.dp
|
||||
|
||||
// Динамический bottom padding для списка: инпут (~70dp) + клавиатура/эмодзи
|
||||
// 🔥 Reply/Forward state (нужен для расчёта listBottomPadding)
|
||||
val replyMessages by viewModel.replyMessages.collectAsState()
|
||||
val hasReply = replyMessages.isNotEmpty()
|
||||
|
||||
// 🔥 Дополнительная высота для reply панели (~50dp)
|
||||
val replyPanelHeight = if (hasReply) 50.dp else 0.dp
|
||||
|
||||
// Динамический bottom padding для списка: инпут (~70dp) + reply (~50dp) + клавиатура/эмодзи
|
||||
val listBottomPadding = when {
|
||||
isKeyboardVisible -> 70.dp + imeHeight
|
||||
showEmojiPicker -> 70.dp + emojiPanelHeight
|
||||
else -> 100.dp
|
||||
isKeyboardVisible -> 70.dp + replyPanelHeight + imeHeight
|
||||
showEmojiPicker -> 70.dp + replyPanelHeight + emojiPanelHeight
|
||||
else -> 100.dp + replyPanelHeight
|
||||
}
|
||||
|
||||
// Telegram-style scroll tracking
|
||||
@@ -289,10 +296,8 @@ fun ChatDetailScreen(
|
||||
val isTyping by viewModel.opponentTyping.collectAsState()
|
||||
val isOnline by viewModel.opponentOnline.collectAsState()
|
||||
|
||||
// 🔥 Reply/Forward state
|
||||
val replyMessages by viewModel.replyMessages.collectAsState()
|
||||
// 🔥 Reply/Forward state (replyMessages и hasReply определены выше для listBottomPadding)
|
||||
val isForwardMode by viewModel.isForwardMode.collectAsState()
|
||||
val hasReply = replyMessages.isNotEmpty()
|
||||
|
||||
// 🔥 Добавляем информацию о датах к сообщениям
|
||||
// В reversed layout (новые внизу) - показываем дату ПОСЛЕ сообщения (визуально сверху)
|
||||
|
||||
@@ -801,6 +801,13 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
attachments = messageAttachments
|
||||
}
|
||||
|
||||
// 🔥 Log packet details before sending
|
||||
ProtocolManager.addLog("📤📤📤 SENDING PACKET 📤📤📤")
|
||||
ProtocolManager.addLog(" - Attachments count: ${packet.attachments.size}")
|
||||
packet.attachments.forEach { att ->
|
||||
ProtocolManager.addLog(" - Attachment: type=${att.type}, id=${att.id}, blob=${att.blob.take(50)}...")
|
||||
}
|
||||
|
||||
// Отправляем пакет
|
||||
ProtocolManager.send(packet)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user