mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-30 13:35:18 +00:00
Take care of remaining loose ends
This commit is contained in:
parent
e2ad23482d
commit
a14fc0503f
@ -4,6 +4,8 @@ import android.graphics.Bitmap;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.session.libsession.messaging.jobs.Data;
|
import org.session.libsession.messaging.jobs.Data;
|
||||||
|
import org.session.libsession.utilities.DownloadUtilities;
|
||||||
|
import org.session.libsignal.service.api.crypto.AttachmentCipherInputStream;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.session.libsession.messaging.threads.GroupRecord;
|
import org.session.libsession.messaging.threads.GroupRecord;
|
||||||
@ -22,6 +24,7 @@ import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
|
|||||||
import org.session.libsignal.service.api.push.exceptions.NonSuccessfulResponseCodeException;
|
import org.session.libsignal.service.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
@ -91,9 +94,20 @@ public class AvatarDownloadJob extends BaseJob implements InjectableType {
|
|||||||
attachment = File.createTempFile("avatar", "tmp", context.getCacheDir());
|
attachment = File.createTempFile("avatar", "tmp", context.getCacheDir());
|
||||||
attachment.deleteOnExit();
|
attachment.deleteOnExit();
|
||||||
|
|
||||||
SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false, Optional.absent(), url);
|
SignalServiceAttachmentPointer pointer = new SignalServiceAttachmentPointer(avatarId, contentType, key, Optional.of(0), Optional.absent(), 0, 0, digest, fileName, false, Optional.absent(), url);
|
||||||
InputStream inputStream = receiver.retrieveAttachment(pointer, attachment, MAX_AVATAR_SIZE);
|
|
||||||
Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key, 0, digest), 500, 500);
|
if (pointer.getUrl().isEmpty()) throw new InvalidMessageException("Missing attachment URL.");
|
||||||
|
DownloadUtilities.downloadFile(attachment, pointer.getUrl(), MAX_AVATAR_SIZE, null);
|
||||||
|
|
||||||
|
// Assume we're retrieving an attachment for an open group server if the digest is not set
|
||||||
|
InputStream inputStream;
|
||||||
|
if (!pointer.getDigest().isPresent()) {
|
||||||
|
inputStream = new FileInputStream(attachment);
|
||||||
|
} else {
|
||||||
|
inputStream = AttachmentCipherInputStream.createForAttachment(attachment, pointer.getSize().or(0), pointer.getKey(), pointer.getDigest().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap avatar = BitmapUtil.createScaledBitmap(context, new AttachmentModel(attachment, key, 0, digest), 500, 500);
|
||||||
|
|
||||||
database.updateProfilePicture(groupId, avatar);
|
database.updateProfilePicture(groupId, avatar);
|
||||||
inputStream.close();
|
inputStream.close();
|
||||||
|
@ -10,9 +10,11 @@ import org.session.libsession.messaging.avatars.AvatarHelper;
|
|||||||
import org.session.libsession.messaging.jobs.Data;
|
import org.session.libsession.messaging.jobs.Data;
|
||||||
import org.session.libsession.messaging.threads.Address;
|
import org.session.libsession.messaging.threads.Address;
|
||||||
import org.session.libsession.messaging.threads.recipients.Recipient;
|
import org.session.libsession.messaging.threads.recipients.Recipient;
|
||||||
|
import org.session.libsession.utilities.DownloadUtilities;
|
||||||
import org.session.libsession.utilities.TextSecurePreferences;
|
import org.session.libsession.utilities.TextSecurePreferences;
|
||||||
import org.session.libsession.utilities.Util;
|
import org.session.libsession.utilities.Util;
|
||||||
import org.session.libsignal.service.api.SignalServiceMessageReceiver;
|
import org.session.libsignal.service.api.SignalServiceMessageReceiver;
|
||||||
|
import org.session.libsignal.service.api.crypto.ProfileCipherInputStream;
|
||||||
import org.session.libsignal.service.api.push.exceptions.PushNetworkException;
|
import org.session.libsignal.service.api.push.exceptions.PushNetworkException;
|
||||||
import org.session.libsignal.utilities.logging.Log;
|
import org.session.libsignal.utilities.logging.Log;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
@ -22,6 +24,7 @@ import org.thoughtcrime.securesms.jobmanager.Job;
|
|||||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -102,7 +105,8 @@ public class RetrieveProfileAvatarJob extends BaseJob implements InjectableType
|
|||||||
File downloadDestination = File.createTempFile("avatar", ".jpg", context.getCacheDir());
|
File downloadDestination = File.createTempFile("avatar", ".jpg", context.getCacheDir());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
InputStream avatarStream = receiver.retrieveProfileAvatar(profileAvatar, downloadDestination, profileKey, MAX_PROFILE_SIZE_BYTES);
|
DownloadUtilities.downloadFile(downloadDestination, profileAvatar, MAX_PROFILE_SIZE_BYTES, null);
|
||||||
|
InputStream avatarStream = new ProfileCipherInputStream(new FileInputStream(downloadDestination), profileKey);
|
||||||
File decryptDestination = File.createTempFile("avatar", ".jpg", context.getCacheDir());
|
File decryptDestination = File.createTempFile("avatar", ".jpg", context.getCacheDir());
|
||||||
|
|
||||||
Util.copy(avatarStream, new FileOutputStream(decryptDestination));
|
Util.copy(avatarStream, new FileOutputStream(decryptDestination));
|
||||||
|
@ -6,7 +6,9 @@ import nl.komponents.kovenant.deferred
|
|||||||
import nl.komponents.kovenant.functional.map
|
import nl.komponents.kovenant.functional.map
|
||||||
import nl.komponents.kovenant.then
|
import nl.komponents.kovenant.then
|
||||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||||
|
import org.session.libsession.messaging.file_server.FileServerAPI
|
||||||
import org.session.libsession.messaging.utilities.DotNetAPI
|
import org.session.libsession.messaging.utilities.DotNetAPI
|
||||||
|
import org.session.libsession.utilities.DownloadUtilities
|
||||||
import org.session.libsignal.service.loki.utilities.retryIfNeeded
|
import org.session.libsignal.service.loki.utilities.retryIfNeeded
|
||||||
import org.session.libsignal.utilities.*
|
import org.session.libsignal.utilities.*
|
||||||
import org.session.libsignal.utilities.Base64
|
import org.session.libsignal.utilities.Base64
|
||||||
@ -315,7 +317,7 @@ object OpenGroupAPI: DotNetAPI() {
|
|||||||
Log.d("Loki", "Downloading open group profile picture from \"$url\".")
|
Log.d("Loki", "Downloading open group profile picture from \"$url\".")
|
||||||
val outputStream = ByteArrayOutputStream()
|
val outputStream = ByteArrayOutputStream()
|
||||||
try {
|
try {
|
||||||
throw IOException();
|
DownloadUtilities.downloadFile(outputStream, url, FileServerAPI.maxFileSize, null)
|
||||||
Log.d("Loki", "Open group profile picture was successfully loaded from \"$url\"")
|
Log.d("Loki", "Open group profile picture was successfully loaded from \"$url\"")
|
||||||
return outputStream.toByteArray()
|
return outputStream.toByteArray()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
package org.session.libsession.utilities
|
||||||
|
|
||||||
|
import okhttp3.HttpUrl
|
||||||
|
import okhttp3.Request
|
||||||
|
import org.session.libsession.messaging.file_server.FileServerAPI
|
||||||
|
import org.session.libsession.snode.OnionRequestAPI
|
||||||
|
import org.session.libsignal.utilities.logging.Log
|
||||||
|
import org.session.libsignal.service.api.messages.SignalServiceAttachment
|
||||||
|
import org.session.libsignal.service.api.push.exceptions.NonSuccessfulResponseCodeException
|
||||||
|
import org.session.libsignal.service.api.push.exceptions.PushNetworkException
|
||||||
|
import org.session.libsignal.utilities.Base64
|
||||||
|
import java.io.*
|
||||||
|
|
||||||
|
object DownloadUtilities {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks the calling thread.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun downloadFile(destination: File, url: String, maxSize: Int, listener: SignalServiceAttachment.ProgressListener?) {
|
||||||
|
val outputStream = FileOutputStream(destination) // Throws
|
||||||
|
var remainingAttempts = 4
|
||||||
|
var exception: Exception? = null
|
||||||
|
while (remainingAttempts > 0) {
|
||||||
|
remainingAttempts -= 1
|
||||||
|
try {
|
||||||
|
downloadFile(outputStream, url, maxSize, listener)
|
||||||
|
exception = null
|
||||||
|
break
|
||||||
|
} catch (e: Exception) {
|
||||||
|
exception = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exception != null) { throw exception }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks the calling thread.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun downloadFile(outputStream: OutputStream, url: String, maxSize: Int, listener: SignalServiceAttachment.ProgressListener?) {
|
||||||
|
// We need to throw a PushNetworkException or NonSuccessfulResponseCodeException
|
||||||
|
// because the underlying Signal logic requires these to work correctly
|
||||||
|
val oldPrefixedHost = "https://" + HttpUrl.get(url).host()
|
||||||
|
var newPrefixedHost = oldPrefixedHost
|
||||||
|
if (oldPrefixedHost.contains(FileServerAPI.fileStorageBucketURL)) {
|
||||||
|
newPrefixedHost = FileServerAPI.shared.server
|
||||||
|
}
|
||||||
|
// Edge case that needs to work: https://file-static.lokinet.org/i1pNmpInq3w9gF3TP8TFCa1rSo38J6UM
|
||||||
|
// → https://file.getsession.org/loki/v1/f/XLxogNXVEIWHk14NVCDeppzTujPHxu35
|
||||||
|
val fileID = url.substringAfter(oldPrefixedHost).substringAfter("/f/")
|
||||||
|
val sanitizedURL = "$newPrefixedHost/loki/v1/f/$fileID"
|
||||||
|
val request = Request.Builder().url(sanitizedURL).get()
|
||||||
|
try {
|
||||||
|
val serverPublicKey = if (newPrefixedHost.contains(FileServerAPI.shared.server)) FileServerAPI.fileServerPublicKey
|
||||||
|
else FileServerAPI.shared.getPublicKeyForOpenGroupServer(newPrefixedHost).get()
|
||||||
|
val json = OnionRequestAPI.sendOnionRequest(request.build(), newPrefixedHost, serverPublicKey, isJSONRequired = false).get()
|
||||||
|
val result = json["result"] as? String
|
||||||
|
if (result == null) {
|
||||||
|
Log.d("Loki", "Couldn't parse attachment from: $json.")
|
||||||
|
throw PushNetworkException("Missing response body.")
|
||||||
|
}
|
||||||
|
val body = Base64.decode(result)
|
||||||
|
if (body.size > maxSize) {
|
||||||
|
Log.d("Loki", "Attachment size limit exceeded.")
|
||||||
|
throw PushNetworkException("Max response size exceeded.")
|
||||||
|
}
|
||||||
|
body.inputStream().use { input ->
|
||||||
|
val buffer = ByteArray(32768)
|
||||||
|
var count = 0
|
||||||
|
var bytes = input.read(buffer)
|
||||||
|
while (bytes >= 0) {
|
||||||
|
outputStream.write(buffer, 0, bytes)
|
||||||
|
count += bytes
|
||||||
|
if (count > maxSize) {
|
||||||
|
Log.d("Loki", "Attachment size limit exceeded.")
|
||||||
|
throw PushNetworkException("Max response size exceeded.")
|
||||||
|
}
|
||||||
|
listener?.onAttachmentProgress(body.size.toLong(), count.toLong())
|
||||||
|
bytes = input.read(buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.d("Loki", "Couldn't download attachment due to error: $e.")
|
||||||
|
throw if (e is NonSuccessfulResponseCodeException) e else PushNetworkException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user