mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 17:29:32 +01:00
Update to the new attachment upload form libsignal method.
This commit is contained in:
@@ -17,6 +17,7 @@ import org.signal.libsignal.net.MultiRecipientSendAuthorization;
|
||||
import org.signal.libsignal.net.MultiRecipientSendFailure;
|
||||
import org.signal.libsignal.net.RequestResult;
|
||||
import org.signal.libsignal.net.RequestUnauthorizedException;
|
||||
import org.signal.libsignal.net.UploadTooLargeException;
|
||||
import org.signal.libsignal.net.RetryLaterException;
|
||||
import org.signal.libsignal.protocol.IdentityKey;
|
||||
import org.signal.libsignal.protocol.IdentityKeyPair;
|
||||
@@ -832,11 +833,22 @@ public class SignalServiceMessageSender {
|
||||
return uploadAttachmentV4(attachment, attachmentKey, attachmentData);
|
||||
}
|
||||
|
||||
public ResumableUploadSpec getResumableUploadSpec() throws IOException {
|
||||
public ResumableUploadSpec getResumableUploadSpec(long uploadSizeBytes) throws IOException {
|
||||
Log.d(TAG, "Using pipe to retrieve attachment upload attributes...");
|
||||
AttachmentUploadForm v4UploadAttributes = NetworkResultUtil.toBasicLegacy(attachmentApi.getAttachmentV4UploadForm());
|
||||
RequestResult<AttachmentUploadForm, UploadTooLargeException> result = attachmentApi.getAttachmentV4UploadForm(uploadSizeBytes);
|
||||
|
||||
return socket.getResumableUploadSpec(v4UploadAttributes);
|
||||
if (result instanceof RequestResult.Success) {
|
||||
AttachmentUploadForm v4UploadAttributes = ((RequestResult.Success<AttachmentUploadForm>) result).getResult();
|
||||
return socket.getResumableUploadSpec(v4UploadAttributes);
|
||||
} else if (result instanceof RequestResult.NonSuccess) {
|
||||
throw ((RequestResult.NonSuccess<UploadTooLargeException>) result).getError();
|
||||
} else if (result instanceof RequestResult.RetryableNetworkError) {
|
||||
throw new PushNetworkException(((RequestResult.RetryableNetworkError) result).getNetworkError());
|
||||
} else if (result instanceof RequestResult.ApplicationError) {
|
||||
throw new RuntimeException(((RequestResult.ApplicationError) result).getCause());
|
||||
} else {
|
||||
throw new IOException("Unexpected RequestResult type: " + result.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
private SignalServiceAttachmentPointer uploadAttachmentV4(SignalServiceAttachmentStream attachment, byte[] attachmentKey, PushAttachmentData attachmentData) throws IOException {
|
||||
|
||||
@@ -5,20 +5,25 @@
|
||||
|
||||
package org.whispersystems.signalservice.api.attachment
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.libsignal.net.AuthMessagesService
|
||||
import org.signal.libsignal.net.AuthenticatedChatConnection
|
||||
import org.signal.libsignal.net.RequestResult
|
||||
import org.signal.libsignal.net.UploadTooLargeException
|
||||
import org.signal.libsignal.net.getOrError
|
||||
import org.whispersystems.signalservice.api.NetworkResult
|
||||
import org.whispersystems.signalservice.api.crypto.AttachmentCipherStreamUtil
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream
|
||||
import org.whispersystems.signalservice.api.websocket.SignalWebSocket
|
||||
import org.whispersystems.signalservice.internal.crypto.PaddingInputStream
|
||||
import org.whispersystems.signalservice.internal.get
|
||||
import org.whispersystems.signalservice.internal.push.AttachmentUploadForm
|
||||
import org.whispersystems.signalservice.internal.push.PushAttachmentData
|
||||
import org.whispersystems.signalservice.internal.push.PushServiceSocket
|
||||
import org.whispersystems.signalservice.internal.push.http.AttachmentCipherOutputStreamFactory
|
||||
import org.whispersystems.signalservice.internal.push.http.ResumableUploadSpec
|
||||
import org.whispersystems.signalservice.internal.websocket.WebSocketRequestMessage
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
@@ -36,56 +41,25 @@ class AttachmentApi(
|
||||
|
||||
/**
|
||||
* Gets a v4 attachment upload form, which provides the necessary information to upload an attachment.
|
||||
*
|
||||
* GET /v4/attachments/form/upload
|
||||
* - 200: Success
|
||||
* - 413: Too many attempts
|
||||
* - 429: Too many attempts
|
||||
*/
|
||||
fun getAttachmentV4UploadForm(): NetworkResult<AttachmentUploadForm> {
|
||||
val request = WebSocketRequestMessage.get("/v4/attachments/form/upload")
|
||||
return NetworkResult.fromWebSocketRequest(authWebSocket, request, AttachmentUploadForm::class)
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads an attachment using the v4 upload scheme.
|
||||
*/
|
||||
fun uploadAttachmentV4(attachmentStream: SignalServiceAttachmentStream): NetworkResult<AttachmentUploadResult> {
|
||||
if (attachmentStream.resumableUploadSpec.isEmpty) {
|
||||
throw IllegalStateException("Attachment must have a resumable upload spec!")
|
||||
}
|
||||
|
||||
return NetworkResult.fromFetch {
|
||||
val resumableUploadSpec = attachmentStream.resumableUploadSpec.get()
|
||||
|
||||
val paddedLength = PaddingInputStream.getPaddedSize(attachmentStream.length)
|
||||
val dataStream: InputStream = PaddingInputStream(attachmentStream.inputStream, attachmentStream.length)
|
||||
val ciphertextLength = AttachmentCipherStreamUtil.getCiphertextLength(paddedLength)
|
||||
|
||||
val attachmentData = PushAttachmentData(
|
||||
contentType = attachmentStream.contentType,
|
||||
data = dataStream,
|
||||
dataSize = ciphertextLength,
|
||||
incremental = attachmentStream.isFaststart,
|
||||
outputStreamFactory = AttachmentCipherOutputStreamFactory(resumableUploadSpec.attachmentKey, resumableUploadSpec.attachmentIv),
|
||||
listener = attachmentStream.listener,
|
||||
cancelationSignal = attachmentStream.cancelationSignal,
|
||||
resumableUploadSpec = attachmentStream.resumableUploadSpec.get()
|
||||
)
|
||||
|
||||
val digestInfo = pushServiceSocket.uploadAttachment(attachmentData)
|
||||
|
||||
AttachmentUploadResult(
|
||||
remoteId = SignalServiceAttachmentRemoteId.V4(resumableUploadSpec.cdnKey),
|
||||
cdnNumber = resumableUploadSpec.cdnNumber,
|
||||
key = resumableUploadSpec.attachmentKey,
|
||||
digest = digestInfo.digest,
|
||||
incrementalDigest = digestInfo.incrementalDigest,
|
||||
incrementalDigestChunkSize = digestInfo.incrementalMacChunkSize,
|
||||
uploadTimestamp = attachmentStream.uploadTimestamp,
|
||||
dataSize = attachmentStream.length,
|
||||
blurHash = attachmentStream.blurHash.getOrNull()
|
||||
)
|
||||
fun getAttachmentV4UploadForm(uploadSizeBytes: Long): RequestResult<AttachmentUploadForm, UploadTooLargeException> {
|
||||
return try {
|
||||
runBlocking {
|
||||
authWebSocket.runWithChatConnection { chatConnection ->
|
||||
AuthMessagesService(chatConnection as AuthenticatedChatConnection).getUploadForm(uploadSizeBytes)
|
||||
}
|
||||
}.getOrError().map { form ->
|
||||
AttachmentUploadForm(
|
||||
cdn = form.cdn,
|
||||
key = form.key,
|
||||
headers = form.headers,
|
||||
signedUploadLocation = form.signedUploadUrl.toString()
|
||||
)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
RequestResult.RetryableNetworkError(e)
|
||||
} catch (e: Throwable) {
|
||||
RequestResult.ApplicationError(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user