From 6c07121d7a73784e6a22ae16e3afd74e8b2b4a64 Mon Sep 17 00:00:00 2001 From: jubb Date: Thu, 11 Aug 2022 15:39:37 +1000 Subject: [PATCH] fix: crash for join open group dialog and v4 file upload in FS and open group --- .../v2/dialogs/JoinOpenGroupDialog.kt | 11 ++++++-- .../messaging/file_server/FileServerApi.kt | 17 ++++++----- .../messaging/open_groups/OpenGroupApi.kt | 28 +++++++++++++++---- .../libsession/snode/OnionRequestAPI.kt | 2 +- .../snode/utilities/OKHTTPUtilities.kt | 7 +++-- 5 files changed, 43 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/JoinOpenGroupDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/JoinOpenGroupDialog.kt index 39007db699..44c782577e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/JoinOpenGroupDialog.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/JoinOpenGroupDialog.kt @@ -5,6 +5,7 @@ import android.text.Spannable import android.text.SpannableStringBuilder import android.text.style.StyleSpan import android.view.LayoutInflater +import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import network.loki.messenger.R @@ -37,9 +38,13 @@ class JoinOpenGroupDialog(private val name: String, private val url: String) : B val openGroup = OpenGroupUrlParser.parseUrl(url) val activity = requireContext() as AppCompatActivity ThreadUtils.queue { - OpenGroupManager.add(openGroup.server, openGroup.room, openGroup.serverPublicKey, activity) - MessagingModuleConfiguration.shared.storage.onOpenGroupAdded(url) - ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(activity) + try { + OpenGroupManager.add(openGroup.server, openGroup.room, openGroup.serverPublicKey, activity) + MessagingModuleConfiguration.shared.storage.onOpenGroupAdded(url) + ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(activity) + } catch (e: Exception) { + Toast.makeText(activity, R.string.activity_join_public_chat_error, Toast.LENGTH_SHORT).show() + } } dismiss() } diff --git a/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerApi.kt b/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerApi.kt index e50bf62c61..b2ca605d2b 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerApi.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerApi.kt @@ -7,7 +7,6 @@ import okhttp3.HttpUrl import okhttp3.MediaType import okhttp3.RequestBody import org.session.libsession.snode.OnionRequestAPI -import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.HTTP import org.session.libsignal.utilities.JsonUtil import org.session.libsignal.utilities.Log @@ -38,6 +37,7 @@ object FileServerApi { val queryParameters: Map = mapOf(), val parameters: Any? = null, val headers: Map = mapOf(), + val body: ByteArray? = null, /** * Always `true` under normal circumstances. You might want to disable * this when running over Lokinet. @@ -45,7 +45,8 @@ object FileServerApi { val useOnionRouting: Boolean = true ) - private fun createBody(parameters: Any?): RequestBody? { + private fun createBody(body: ByteArray?, parameters: Any?): RequestBody? { + if (body != null) return RequestBody.create(MediaType.get("application/octet-stream"), body) if (parameters == null) return null val parametersAsJSON = JsonUtil.toJson(parameters) return RequestBody.create(MediaType.get("application/json"), parametersAsJSON) @@ -68,9 +69,9 @@ object FileServerApi { .headers(Headers.of(request.headers)) when (request.verb) { HTTP.Verb.GET -> requestBuilder.get() - HTTP.Verb.PUT -> requestBuilder.put(createBody(request.parameters)!!) - HTTP.Verb.POST -> requestBuilder.post(createBody(request.parameters)!!) - HTTP.Verb.DELETE -> requestBuilder.delete(createBody(request.parameters)) + HTTP.Verb.PUT -> requestBuilder.put(createBody(request.body, request.parameters)!!) + HTTP.Verb.POST -> requestBuilder.post(createBody(request.body, request.parameters)!!) + HTTP.Verb.DELETE -> requestBuilder.delete(createBody(request.body, request.parameters)) } return if (request.useOnionRouting) { OnionRequestAPI.sendOnionRequest(requestBuilder.build(), server, serverPublicKey).map { @@ -84,12 +85,10 @@ object FileServerApi { } fun upload(file: ByteArray): Promise { - val base64EncodedFile = Base64.encodeBytes(file) - val parameters = mapOf( "file" to base64EncodedFile ) val request = Request( verb = HTTP.Verb.POST, endpoint = "file", - parameters = parameters, + body = file, headers = mapOf( "Content-Disposition" to "attachment", "Content-Type" to "application/octet-stream" @@ -97,7 +96,7 @@ object FileServerApi { ) return send(request).map { response -> val json = JsonUtil.fromJson(response, Map::class.java) - json["result"] as? Long ?: throw Error.ParsingFailed + (json["id"] as? String)?.toLong() ?: throw Error.ParsingFailed } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt index 87da109836..3d5d590838 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupApi.kt @@ -212,6 +212,7 @@ object OpenGroupApi { val parameters: Any? = null, val headers: Map = mapOf(), val isAuthRequired: Boolean = true, + val body: ByteArray? = null, /** * Always `true` under normal circumstances. You might want to disable * this when running over Lokinet. @@ -219,7 +220,8 @@ object OpenGroupApi { val useOnionRouting: Boolean = true ) - private fun createBody(parameters: Any?): RequestBody? { + private fun createBody(body: ByteArray?, parameters: Any?): RequestBody? { + if (body != null) return RequestBody.create(MediaType.get("application/octet-stream"), body) if (parameters == null) return null val parametersAsJSON = JsonUtil.toJson(parameters) return RequestBody.create(MediaType.get("application/json"), parametersAsJSON) @@ -276,6 +278,17 @@ object OpenGroupApi { ) { bodyHash = parameterHash } + } else if (request.body != null) { + val byteHash = ByteArray(GenericHash.BYTES_MAX) + if (sodium.cryptoGenericHash( + byteHash, + byteHash.size, + request.body, + request.body.size.toLong() + ) + ) { + bodyHash = byteHash + } } val messageBytes = Hex.fromStringCondensed(publicKey) .plus(nonce) @@ -320,9 +333,9 @@ object OpenGroupApi { .headers(Headers.of(headers)) when (request.verb) { GET -> requestBuilder.get() - PUT -> requestBuilder.put(createBody(request.parameters)!!) - POST -> requestBuilder.post(createBody(request.parameters)!!) - DELETE -> requestBuilder.delete(createBody(request.parameters)) + PUT -> requestBuilder.put(createBody(request.body, request.parameters)!!) + POST -> requestBuilder.post(createBody(request.body, request.parameters)!!) + DELETE -> requestBuilder.delete(createBody(request.body, request.parameters)) } if (!request.room.isNullOrEmpty()) { requestBuilder.header("Room", request.room) @@ -354,13 +367,16 @@ object OpenGroupApi { // region Upload/Download fun upload(file: ByteArray, room: String, server: String): Promise { - val parameters = mapOf("file" to file) val request = Request( verb = POST, room = room, server = server, endpoint = Endpoint.RoomFile(room), - parameters = parameters + body = file, + headers = mapOf( + "Content-Disposition" to "attachment", + "Content-Type" to "application/octet-stream" + ) ) return getResponseBodyJson(request).map { json -> (json["id"] as? Number)?.toLong() ?: throw Error.ParsingFailed diff --git a/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt b/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt index b1d45b7bd0..f93a7b243e 100644 --- a/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt +++ b/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt @@ -483,7 +483,7 @@ object OnionRequestAPI { val prefixData = "l${requestData.size}:".toByteArray(Charsets.US_ASCII) val suffixData = "e".toByteArray(Charsets.US_ASCII) if (request.body() != null) { - val bodyData = body.toString().toByteArray() + val bodyData = if (body is ByteArray) body else body.toString().toByteArray() val bodyLengthData = "${bodyData.size}:".toByteArray(Charsets.US_ASCII) prefixData + requestData + bodyLengthData + bodyData + suffixData } else { diff --git a/libsession/src/main/java/org/session/libsession/snode/utilities/OKHTTPUtilities.kt b/libsession/src/main/java/org/session/libsession/snode/utilities/OKHTTPUtilities.kt index e46c493efe..4c08c4791e 100644 --- a/libsession/src/main/java/org/session/libsession/snode/utilities/OKHTTPUtilities.kt +++ b/libsession/src/main/java/org/session/libsession/snode/utilities/OKHTTPUtilities.kt @@ -3,10 +3,9 @@ package org.session.libsession.utilities import okhttp3.MultipartBody import okhttp3.Request import okio.Buffer -import java.io.IOException -import java.util.* - import org.session.libsignal.utilities.Base64 +import java.io.IOException +import java.util.Locale internal fun Request.getHeadersForOnionRequest(): Map { val result = mutableMapOf() @@ -40,6 +39,8 @@ internal fun Request.getBodyForOnionRequest(): Any? { if (body is MultipartBody) { val base64EncodedBody: String = Base64.encodeBytes(bodyAsData) return mapOf( "fileUpload" to base64EncodedBody ) + } else if (body.contentType()?.toString() == "application/octet-stream") { + return bodyAsData } else { val charset = body.contentType()?.charset() ?: Charsets.UTF_8 return bodyAsData?.toString(charset)