Фикс: расшифровка групповых фото — fallback на hex group key (Desktop v1.2.1 parity)
Desktop теперь шифрует аттачменты в группах hex-версией ключа. Android пробует raw key, при неудаче — hex key. Фикс в 3 местах: processDownloadedImage, downloadAndDecryptImage, loadBitmapForViewerImage. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -141,6 +141,7 @@ class MainActivity : FragmentActivity() {
|
|||||||
// 🔥 Инициализируем ProtocolManager для обработки онлайн статусов
|
// 🔥 Инициализируем ProtocolManager для обработки онлайн статусов
|
||||||
ProtocolManager.initialize(this)
|
ProtocolManager.initialize(this)
|
||||||
CallManager.initialize(this)
|
CallManager.initialize(this)
|
||||||
|
com.rosetta.messenger.ui.chats.components.AttachmentDownloadDebugLogger.init(this)
|
||||||
|
|
||||||
// 🔔 Инициализируем Firebase для push-уведомлений
|
// 🔔 Инициализируем Firebase для push-уведомлений
|
||||||
initializeFirebase()
|
initializeFirebase()
|
||||||
|
|||||||
@@ -2851,7 +2851,14 @@ private suspend fun processDownloadedImage(
|
|||||||
var decryptDebug = MessageCrypto.AttachmentDecryptDebugResult(null, emptyList())
|
var decryptDebug = MessageCrypto.AttachmentDecryptDebugResult(null, emptyList())
|
||||||
val decrypted =
|
val decrypted =
|
||||||
if (groupPassword != null) {
|
if (groupPassword != null) {
|
||||||
val plain = CryptoManager.decryptWithPassword(encryptedContent, groupPassword!!)
|
// Try raw group key first, then hex-encoded (Desktop v1.2.1+ sends hex-encrypted attachments)
|
||||||
|
var plain = CryptoManager.decryptWithPassword(encryptedContent, groupPassword!!)
|
||||||
|
if (plain == null) {
|
||||||
|
val hexKey = groupPassword!!.toByteArray(Charsets.ISO_8859_1)
|
||||||
|
.joinToString("") { "%02x".format(it.toInt() and 0xff) }
|
||||||
|
logPhotoDebug("Group raw key failed, trying hex key: id=$idShort, hexKeyLen=${hexKey.length}")
|
||||||
|
plain = CryptoManager.decryptWithPassword(encryptedContent, hexKey)
|
||||||
|
}
|
||||||
decryptDebug = MessageCrypto.AttachmentDecryptDebugResult(plain, emptyList())
|
decryptDebug = MessageCrypto.AttachmentDecryptDebugResult(plain, emptyList())
|
||||||
plain
|
plain
|
||||||
} else {
|
} else {
|
||||||
@@ -2968,6 +2975,11 @@ internal suspend fun downloadAndDecryptImage(
|
|||||||
} else if (isGroupStoredKey(chachaKey)) {
|
} else if (isGroupStoredKey(chachaKey)) {
|
||||||
val groupPassword = decodeGroupPassword(chachaKey, privateKey) ?: return@withContext null
|
val groupPassword = decodeGroupPassword(chachaKey, privateKey) ?: return@withContext null
|
||||||
CryptoManager.decryptWithPassword(encryptedContent, groupPassword)
|
CryptoManager.decryptWithPassword(encryptedContent, groupPassword)
|
||||||
|
?: run {
|
||||||
|
val hexKey = groupPassword.toByteArray(Charsets.ISO_8859_1)
|
||||||
|
.joinToString("") { "%02x".format(it.toInt() and 0xff) }
|
||||||
|
CryptoManager.decryptWithPassword(encryptedContent, hexKey)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val keyCandidates = MessageCrypto.decryptKeyFromSenderCandidates(chachaKey, privateKey)
|
val keyCandidates = MessageCrypto.decryptKeyFromSenderCandidates(chachaKey, privateKey)
|
||||||
if (keyCandidates.isEmpty()) return@withContext null
|
if (keyCandidates.isEmpty()) return@withContext null
|
||||||
|
|||||||
@@ -8,9 +8,22 @@ object AttachmentDownloadDebugLogger {
|
|||||||
private val _logs = MutableStateFlow<List<String>>(emptyList())
|
private val _logs = MutableStateFlow<List<String>>(emptyList())
|
||||||
val logs: StateFlow<List<String>> = _logs.asStateFlow()
|
val logs: StateFlow<List<String>> = _logs.asStateFlow()
|
||||||
|
|
||||||
fun log(@Suppress("UNUSED_PARAMETER") message: String) {
|
private var appContext: android.content.Context? = null
|
||||||
// Disabled by request: no runtime accumulation of photo debug logs.
|
|
||||||
return
|
fun init(context: android.content.Context) {
|
||||||
|
appContext = context.applicationContext
|
||||||
|
}
|
||||||
|
|
||||||
|
fun log(message: String) {
|
||||||
|
val ctx = appContext ?: return
|
||||||
|
try {
|
||||||
|
val ts = java.text.SimpleDateFormat("HH:mm:ss.SSS", java.util.Locale.getDefault()).format(java.util.Date())
|
||||||
|
val line = "$ts [PhotoDL] $message"
|
||||||
|
android.util.Log.d("PhotoDL", message)
|
||||||
|
val dir = java.io.File(ctx.filesDir, "crash_reports")
|
||||||
|
if (!dir.exists()) dir.mkdirs()
|
||||||
|
java.io.File(dir, "image_logs.txt").appendText("$line\n")
|
||||||
|
} catch (_: Exception) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
||||||
|
|||||||
@@ -984,7 +984,7 @@ private fun viewerLog(context: Context, msg: String) {
|
|||||||
val ts = java.text.SimpleDateFormat("HH:mm:ss.SSS", java.util.Locale.getDefault()).format(java.util.Date())
|
val ts = java.text.SimpleDateFormat("HH:mm:ss.SSS", java.util.Locale.getDefault()).format(java.util.Date())
|
||||||
val dir = java.io.File(context.filesDir, "crash_reports")
|
val dir = java.io.File(context.filesDir, "crash_reports")
|
||||||
if (!dir.exists()) dir.mkdirs()
|
if (!dir.exists()) dir.mkdirs()
|
||||||
java.io.File(dir, "rosettadev1.txt").appendText("$ts [Viewer] $msg\n")
|
java.io.File(dir, "image_logs.txt").appendText("$ts [Viewer] $msg\n")
|
||||||
} catch (_: Exception) {}
|
} catch (_: Exception) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1062,7 +1062,14 @@ private suspend fun loadBitmapForViewerImage(
|
|||||||
val groupPassword = CryptoManager.decryptWithPassword(
|
val groupPassword = CryptoManager.decryptWithPassword(
|
||||||
image.chachaKey.removePrefix("group:"), privateKey
|
image.chachaKey.removePrefix("group:"), privateKey
|
||||||
)
|
)
|
||||||
if (groupPassword != null) CryptoManager.decryptWithPassword(encryptedContent, groupPassword) else null
|
if (groupPassword != null) {
|
||||||
|
CryptoManager.decryptWithPassword(encryptedContent, groupPassword)
|
||||||
|
?: run {
|
||||||
|
val hexKey = groupPassword.toByteArray(Charsets.ISO_8859_1)
|
||||||
|
.joinToString("") { "%02x".format(it.toInt() and 0xff) }
|
||||||
|
CryptoManager.decryptWithPassword(encryptedContent, hexKey)
|
||||||
|
}
|
||||||
|
} else null
|
||||||
} else if (image.chachaKey.isNotEmpty()) {
|
} else if (image.chachaKey.isNotEmpty()) {
|
||||||
val decryptedKeyAndNonce = MessageCrypto.decryptKeyFromSender(image.chachaKey, privateKey)
|
val decryptedKeyAndNonce = MessageCrypto.decryptKeyFromSender(image.chachaKey, privateKey)
|
||||||
MessageCrypto.decryptAttachmentBlobWithPlainKey(encryptedContent, decryptedKeyAndNonce)
|
MessageCrypto.decryptAttachmentBlobWithPlainKey(encryptedContent, decryptedKeyAndNonce)
|
||||||
|
|||||||
Reference in New Issue
Block a user