Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/iNPUTmice/Conversations.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Gultsch <daniel@gultsch.de>2021-03-18 18:18:40 +0300
committerDaniel Gultsch <daniel@gultsch.de>2021-03-18 18:18:40 +0300
commita09c32c4dd02c04ee9b2f7f349050f8e00feb5b6 (patch)
tree14e52938a51dc279226307387befae06e904568d
parentb09a1432a347e9700ace8aa8fe729f53bfcfac80 (diff)
WIP migrate HTTP Upload code to OkHttpokhttp
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java2
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java2
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java390
-rw-r--r--src/main/java/eu/siacs/conversations/http/SlotRequester.java65
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/FileBackend.java4
-rw-r--r--src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java37
-rw-r--r--src/main/java/eu/siacs/conversations/utils/CryptoHelper.java9
7 files changed, 244 insertions, 265 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java
index 29d286a71..2fcfdc39c 100644
--- a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java
@@ -210,7 +210,7 @@ public class PgpDecryptionService {
}
}
URL url = message.getFileParams().url;
- mXmppConnectionService.getFileBackend().updateFileParams(message, url);
+ mXmppConnectionService.getFileBackend().updateFileParams(message, url.toString());
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
mXmppConnectionService.updateMessage(message);
if (!inputFile.delete()) {
diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
index e55de385a..32f9c58bd 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
@@ -524,7 +524,7 @@ public class HttpDownloadConnection implements Transferable {
} else {
url = mUrl;
}
- mXmppConnectionService.getFileBackend().updateFileParams(message, url);
+ mXmppConnectionService.getFileBackend().updateFileParams(message, url.toString());
mXmppConnectionService.updateMessage(message);
}
diff --git a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
index a6161701f..deaa80844 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
@@ -6,7 +6,6 @@ import android.util.Log;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
@@ -26,225 +25,182 @@ import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.Checksum;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.WakeLockHelper;
+import okhttp3.HttpUrl;
+import okhttp3.MultipartBody;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
import static eu.siacs.conversations.http.HttpConnectionManager.EXECUTOR;
public class HttpUploadConnection implements Transferable {
- static final List<String> WHITE_LISTED_HEADERS = Arrays.asList(
- "Authorization",
- "Cookie",
- "Expires"
- );
-
- private final HttpConnectionManager mHttpConnectionManager;
- private final XmppConnectionService mXmppConnectionService;
- private final SlotRequester mSlotRequester;
- private final Method method;
- private final boolean mUseTor;
- private boolean cancelled = false;
- private boolean delayed = false;
- private DownloadableFile file;
- private final Message message;
- private String mime;
- private SlotRequester.Slot slot;
- private byte[] key = null;
-
- private long transmitted = 0;
-
- public HttpUploadConnection(Message message, Method method, HttpConnectionManager httpConnectionManager) {
- this.message = message;
- this.method = method;
- this.mHttpConnectionManager = httpConnectionManager;
- this.mXmppConnectionService = httpConnectionManager.getXmppConnectionService();
- this.mSlotRequester = new SlotRequester(this.mXmppConnectionService);
- this.mUseTor = mXmppConnectionService.useTorToConnect();
- }
-
- @Override
- public boolean start() {
- return false;
- }
-
- @Override
- public int getStatus() {
- return STATUS_UPLOADING;
- }
-
- @Override
- public long getFileSize() {
- return file == null ? 0 : file.getExpectedSize();
- }
-
- @Override
- public int getProgress() {
- if (file == null) {
- return 0;
- }
- return (int) ((((double) transmitted) / file.getExpectedSize()) * 100);
- }
-
- @Override
- public void cancel() {
- this.cancelled = true;
- }
-
- private void fail(String errorMessage) {
- finish();
- mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED, cancelled ? Message.ERROR_MESSAGE_CANCELLED : errorMessage);
- }
-
- private void finish() {
- mHttpConnectionManager.finishUploadConnection(this);
- message.setTransferable(null);
- }
-
- public void init(boolean delay) {
- final Account account = message.getConversation().getAccount();
- this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
- if (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
- this.mime = "application/pgp-encrypted";
- } else {
- this.mime = this.file.getMimeType();
- }
- final long originalFileSize = file.getSize();
- this.delayed = delay;
- if (Config.ENCRYPT_ON_HTTP_UPLOADED
- || message.getEncryption() == Message.ENCRYPTION_AXOLOTL
- || message.getEncryption() == Message.ENCRYPTION_OTR) {
- this.key = new byte[44];
- mXmppConnectionService.getRNG().nextBytes(this.key);
- this.file.setKeyAndIv(this.key);
- }
-
- final String md5;
-
- if (method == Method.P1_S3) {
- try {
- md5 = Checksum.md5(AbstractConnectionManager.upgrade(file, new FileInputStream(file)));
- } catch (Exception e) {
- Log.d(Config.LOGTAG, account.getJid().asBareJid()+": unable to calculate md5()", e);
- fail(e.getMessage());
- return;
- }
- } else {
- md5 = null;
- }
-
- this.file.setExpectedSize(originalFileSize + (file.getKey() != null ? 16 : 0));
- message.resetFileParams();
- this.mSlotRequester.request(method, account, file, mime, md5, new SlotRequester.OnSlotRequested() {
- @Override
- public void success(SlotRequester.Slot slot) {
- if (!cancelled) {
- HttpUploadConnection.this.slot = slot;
- EXECUTOR.execute(HttpUploadConnection.this::upload);
- }
- }
-
- @Override
- public void failure(String message) {
- fail(message);
- }
- });
- message.setTransferable(this);
- mXmppConnectionService.markMessage(message, Message.STATUS_UNSEND);
- }
-
- private void upload() {
- OutputStream os = null;
- InputStream fileInputStream = null;
- HttpURLConnection connection = null;
- final PowerManager.WakeLock wakeLock = mHttpConnectionManager.createWakeLock(Thread.currentThread());
- try {
- fileInputStream = new FileInputStream(file);
- final String slotHostname = slot.getPutUrl().getHost();
- final boolean onionSlot = slotHostname != null && slotHostname.endsWith(".onion");
- final int expectedFileSize = (int) file.getExpectedSize();
- final int readTimeout = (expectedFileSize / 2048) + Config.SOCKET_TIMEOUT; //assuming a minimum transfer speed of 16kbit/s
- wakeLock.acquire(readTimeout);
- Log.d(Config.LOGTAG, "uploading to " + slot.getPutUrl().toString()+ " w/ read timeout of "+readTimeout+"s");
-
- if (mUseTor || message.getConversation().getAccount().isOnion() || onionSlot) {
- connection = (HttpURLConnection) slot.getPutUrl().openConnection(HttpConnectionManager.getProxy());
- } else {
- connection = (HttpURLConnection) slot.getPutUrl().openConnection();
- }
- if (connection instanceof HttpsURLConnection) {
- mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, true);
- }
- connection.setUseCaches(false);
- connection.setRequestMethod("PUT");
- connection.setFixedLengthStreamingMode(expectedFileSize);
- connection.setRequestProperty("User-Agent",mXmppConnectionService.getIqGenerator().getUserAgent());
- if(slot.getHeaders() != null) {
- for(HashMap.Entry<String,String> entry : slot.getHeaders().entrySet()) {
- connection.setRequestProperty(entry.getKey(),entry.getValue());
- }
- }
- connection.setDoOutput(true);
- connection.setDoInput(true);
- connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000);
- connection.setReadTimeout(readTimeout * 1000);
- connection.connect();
- final InputStream innerInputStream = AbstractConnectionManager.upgrade(file, fileInputStream);
- os = connection.getOutputStream();
- transmitted = 0;
- int count;
- byte[] buffer = new byte[4096];
- while (((count = innerInputStream.read(buffer)) != -1) && !cancelled) {
- transmitted += count;
- os.write(buffer, 0, count);
- mHttpConnectionManager.updateConversationUi(false);
- }
- os.flush();
- os.close();
- int code = connection.getResponseCode();
- InputStream is = connection.getErrorStream();
- if (is != null) {
- try (Scanner scanner = new Scanner(is)) {
- scanner.useDelimiter("\\Z");
- Log.d(Config.LOGTAG, "body: " + scanner.next());
- }
- }
- if (code == 200 || code == 201) {
- Log.d(Config.LOGTAG, "finished uploading file");
- final URL get;
- if (key != null) {
- if (method == Method.P1_S3) {
- get = new URL(slot.getGetUrl().toString()+"#"+CryptoHelper.bytesToHex(key));
- } else {
- get = CryptoHelper.toAesGcmUrl(new URL(slot.getGetUrl().toString() + "#" + CryptoHelper.bytesToHex(key)));
- }
- } else {
- get = slot.getGetUrl();
- }
- mXmppConnectionService.getFileBackend().updateFileParams(message, get);
- mXmppConnectionService.getFileBackend().updateMediaScanner(file);
- finish();
- if (!message.isPrivateMessage()) {
- message.setCounterpart(message.getConversation().getJid().asBareJid());
- }
- mXmppConnectionService.resendMessage(message, delayed);
- } else {
- Log.d(Config.LOGTAG,"http upload failed because response code was "+code);
- fail("http upload failed because response code was "+code);
- }
- } catch (Exception e) {
- e.printStackTrace();
- Log.d(Config.LOGTAG,"http upload failed "+e.getMessage());
- fail(e.getMessage());
- } finally {
- FileBackend.close(fileInputStream);
- FileBackend.close(os);
- if (connection != null) {
- connection.disconnect();
- }
- WakeLockHelper.release(wakeLock);
- }
- }
-
- public Message getMessage() {
- return message;
- }
+ static final List<String> WHITE_LISTED_HEADERS = Arrays.asList(
+ "Authorization",
+ "Cookie",
+ "Expires"
+ );
+
+ private final HttpConnectionManager mHttpConnectionManager;
+ private final XmppConnectionService mXmppConnectionService;
+ private final SlotRequester mSlotRequester;
+ private final Method method;
+ private final boolean mUseTor;
+ private boolean cancelled = false;
+ private boolean delayed = false;
+ private DownloadableFile file;
+ private final Message message;
+ private String mime;
+ private SlotRequester.Slot slot;
+ private byte[] key = null;
+
+ private long transmitted = 0;
+
+ public HttpUploadConnection(Message message, Method method, HttpConnectionManager httpConnectionManager) {
+ this.message = message;
+ this.method = method;
+ this.mHttpConnectionManager = httpConnectionManager;
+ this.mXmppConnectionService = httpConnectionManager.getXmppConnectionService();
+ this.mSlotRequester = new SlotRequester(this.mXmppConnectionService);
+ this.mUseTor = mXmppConnectionService.useTorToConnect();
+ }
+
+ @Override
+ public boolean start() {
+ return false;
+ }
+
+ @Override
+ public int getStatus() {
+ return STATUS_UPLOADING;
+ }
+
+ @Override
+ public long getFileSize() {
+ return file == null ? 0 : file.getExpectedSize();
+ }
+
+ @Override
+ public int getProgress() {
+ if (file == null) {
+ return 0;
+ }
+ return (int) ((((double) transmitted) / file.getExpectedSize()) * 100);
+ }
+
+ @Override
+ public void cancel() {
+ this.cancelled = true;
+ }
+
+ private void fail(String errorMessage) {
+ finish();
+ mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED, cancelled ? Message.ERROR_MESSAGE_CANCELLED : errorMessage);
+ }
+
+ private void finish() {
+ mHttpConnectionManager.finishUploadConnection(this);
+ message.setTransferable(null);
+ }
+
+ public void init(boolean delay) {
+ final Account account = message.getConversation().getAccount();
+ this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
+ if (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
+ this.mime = "application/pgp-encrypted";
+ } else {
+ this.mime = this.file.getMimeType();
+ }
+ final long originalFileSize = file.getSize();
+ this.delayed = delay;
+ if (Config.ENCRYPT_ON_HTTP_UPLOADED
+ || message.getEncryption() == Message.ENCRYPTION_AXOLOTL
+ || message.getEncryption() == Message.ENCRYPTION_OTR) {
+ this.key = new byte[44];
+ mXmppConnectionService.getRNG().nextBytes(this.key);
+ this.file.setKeyAndIv(this.key);
+ }
+
+ final String md5;
+
+ if (method == Method.P1_S3) {
+ try {
+ md5 = Checksum.md5(AbstractConnectionManager.upgrade(file, new FileInputStream(file)));
+ } catch (Exception e) {
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to calculate md5()", e);
+ fail(e.getMessage());
+ return;
+ }
+ } else {
+ md5 = null;
+ }
+
+ this.file.setExpectedSize(originalFileSize + (file.getKey() != null ? 16 : 0));
+ message.resetFileParams();
+ this.mSlotRequester.request(method, account, file, mime, md5, new SlotRequester.OnSlotRequested() {
+ @Override
+ public void success(SlotRequester.Slot slot) {
+ if (!cancelled) {
+ HttpUploadConnection.this.slot = slot;
+ EXECUTOR.execute(HttpUploadConnection.this::upload);
+ }
+ }
+
+ @Override
+ public void failure(String message) {
+ fail(message);
+ }
+ });
+ message.setTransferable(this);
+ mXmppConnectionService.markMessage(message, Message.STATUS_UNSEND);
+ }
+
+ private void upload() {
+ final String slotHostname = slot.getPutUrl().host();
+ final boolean onionSlot = slotHostname.endsWith(".onion");
+ try {
+ final OkHttpClient client;
+ if (mUseTor || message.getConversation().getAccount().isOnion() || onionSlot) {
+ client = new OkHttpClient.Builder().proxy(HttpConnectionManager.getProxy()).build();
+ } else {
+ client = new OkHttpClient();
+ }
+ final RequestBody requestBody = AbstractConnectionManager.requestBody(file);
+ final Request request = new Request.Builder()
+ .url(slot.getPutUrl())
+ .put(requestBody)
+ .headers(slot.getHeaders())
+ .build();
+ Log.d(Config.LOGTAG, "uploading file to " + slot.getPutUrl());
+ final Response response = client.newCall(request).execute();
+ final int code = response.code();
+ if (code == 200 || code == 201) {
+ Log.d(Config.LOGTAG, "finished uploading file");
+ final String get;
+ if (key != null) {
+ get = CryptoHelper.toAesGcmUrl(slot.getGetUrl().newBuilder().fragment(CryptoHelper.bytesToHex(key)).build());
+ } else {
+ get = slot.getGetUrl().toString();
+ }
+ mXmppConnectionService.getFileBackend().updateFileParams(message, get);
+ mXmppConnectionService.getFileBackend().updateMediaScanner(file);
+ finish();
+ if (!message.isPrivateMessage()) {
+ message.setCounterpart(message.getConversation().getJid().asBareJid());
+ }
+ mXmppConnectionService.resendMessage(message, delayed);
+ } else {
+ Log.d(Config.LOGTAG, "http upload failed because response code was " + code);
+ fail("http upload failed because response code was " + code);
+ }
+ } catch (final Exception e) {
+ Log.d(Config.LOGTAG, "http upload failed", e);
+ fail(e.getMessage());
+ }
+ }
+
+ public Message getMessage() {
+ return message;
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/http/SlotRequester.java b/src/main/java/eu/siacs/conversations/http/SlotRequester.java
index b52bab39a..249b52d43 100644
--- a/src/main/java/eu/siacs/conversations/http/SlotRequester.java
+++ b/src/main/java/eu/siacs/conversations/http/SlotRequester.java
@@ -31,9 +31,7 @@ package eu.siacs.conversations.http;
import android.util.Log;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.HashMap;
+import com.google.common.collect.ImmutableMap;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
@@ -44,6 +42,8 @@ import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+import okhttp3.Headers;
+import okhttp3.HttpUrl;
public class SlotRequester {
@@ -75,14 +75,13 @@ public class SlotRequester {
final String putUrl = slotElement.findChildContent("put");
final String getUrl = slotElement.findChildContent("get");
if (getUrl != null && putUrl != null) {
- Slot slot = new Slot(new URL(putUrl));
- slot.getUrl = new URL(getUrl);
- slot.headers = new HashMap<>();
- slot.headers.put("Content-Type", mime == null ? "application/octet-stream" : mime);
+ Slot slot = new Slot(HttpUrl.get(putUrl));
+ slot.getUrl = HttpUrl.get(getUrl);
+ slot.headers = Headers.of("Content-Type", mime == null ? "application/octet-stream" : mime);
callback.success(slot);
return;
}
- } catch (MalformedURLException e) {
+ } catch (IllegalArgumentException e) {
//fall through
}
}
@@ -105,23 +104,24 @@ public class SlotRequester {
final String putUrl = put == null ? null : put.getAttribute("url");
final String getUrl = get == null ? null : get.getAttribute("url");
if (getUrl != null && putUrl != null) {
- Slot slot = new Slot(new URL(putUrl));
- slot.getUrl = new URL(getUrl);
- slot.headers = new HashMap<>();
+ Slot slot = new Slot(HttpUrl.get(putUrl));
+ slot.getUrl = HttpUrl.get(getUrl);
+ final ImmutableMap.Builder<String,String> headers = new ImmutableMap.Builder<>();
for (Element child : put.getChildren()) {
if ("header".equals(child.getName())) {
final String name = child.getAttribute("name");
final String value = child.getContent();
if (HttpUploadConnection.WHITE_LISTED_HEADERS.contains(name) && value != null && !value.trim().contains("\n")) {
- slot.headers.put(name, value.trim());
+ headers.put(name, value.trim());
}
}
}
- slot.headers.put("Content-Type", mime == null ? "application/octet-stream" : mime);
+ headers.put("Content-Type", mime == null ? "application/octet-stream" : mime);
+ slot.headers = Headers.of(headers.build());
callback.success(slot);
return;
}
- } catch (MalformedURLException e) {
+ } catch (IllegalArgumentException e) {
//fall through
}
}
@@ -133,28 +133,7 @@ public class SlotRequester {
}
private void requestP1S3(final Account account, Jid host, String filename, String md5, OnSlotRequested callback) {
- IqPacket request = service.getIqGenerator().requestP1S3Slot(host, md5);
- service.sendIqPacket(account, request, (a, packet) -> {
- if (packet.getType() == IqPacket.TYPE.RESULT) {
- String putUrl = packet.query(Namespace.P1_S3_FILE_TRANSFER).getAttribute("upload");
- String id = packet.query().getAttribute("fileid");
- try {
- if (putUrl != null && id != null) {
- Slot slot = new Slot(new URL(putUrl));
- slot.getUrl = P1S3UrlStreamHandler.of(id, filename);
- slot.headers = new HashMap<>();
- slot.headers.put("Content-MD5", md5);
- slot.headers.put("Content-Type", " "); //required to force it to empty. otherwise library will set something
- callback.success(slot);
- return;
- }
- } catch (MalformedURLException e) {
- //fall through;
- }
- }
- callback.failure("unable to request slot");
- });
- Log.d(Config.LOGTAG, "requesting slot with p1. md5=" + md5);
+ callback.failure("unable to request slot");
}
@@ -167,23 +146,23 @@ public class SlotRequester {
}
public static class Slot {
- private final URL putUrl;
- private URL getUrl;
- private HashMap<String, String> headers;
+ private final HttpUrl putUrl;
+ private HttpUrl getUrl;
+ private Headers headers;
- private Slot(URL putUrl) {
+ private Slot(HttpUrl putUrl) {
this.putUrl = putUrl;
}
- public URL getPutUrl() {
+ public HttpUrl getPutUrl() {
return putUrl;
}
- public URL getGetUrl() {
+ public HttpUrl getGetUrl() {
return getUrl;
}
- public HashMap<String, String> getHeaders() {
+ public Headers getHeaders() {
return headers;
}
}
diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
index 690caaafd..1e5944a16 100644
--- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
@@ -1305,7 +1305,7 @@ public class FileBackend {
updateFileParams(message, null);
}
- public void updateFileParams(Message message, URL url) {
+ public void updateFileParams(Message message, String url) {
DownloadableFile file = getFile(message);
final String mime = file.getMimeType();
final boolean privateMessage = message.isPrivateMessage();
@@ -1315,7 +1315,7 @@ public class FileBackend {
final boolean pdf = "application/pdf".equals(mime);
final StringBuilder body = new StringBuilder();
if (url != null) {
- body.append(url.toString());
+ body.append(url);
}
body.append('|').append(file.getSize());
if (image || video || (pdf && Compatibility.runsTwentyOne())) {
diff --git a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java
index dcf8848bf..2db77412c 100644
--- a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java
+++ b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java
@@ -13,8 +13,10 @@ import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
@@ -23,12 +25,18 @@ import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.concurrent.atomic.AtomicLong;
+import javax.annotation.Nullable;
import javax.crypto.NoSuchPaddingException;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.utils.Compatibility;
+import okhttp3.MediaType;
+import okhttp3.RequestBody;
+import okio.BufferedSink;
+import okio.Okio;
+import okio.Source;
import static eu.siacs.conversations.entities.Transferable.VALID_CRYPTO_EXTENSIONS;
@@ -42,7 +50,7 @@ public class AbstractConnectionManager {
this.mXmppConnectionService = service;
}
- public static InputStream upgrade(DownloadableFile file, InputStream is) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, NoSuchProviderException {
+ public static InputStream upgrade(DownloadableFile file, InputStream is) {
if (file.getKey() != null && file.getIv() != null) {
AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine());
cipher.init(true, new AEADParameters(new KeyParameter(file.getKey()), 128, file.getIv()));
@@ -52,6 +60,33 @@ public class AbstractConnectionManager {
}
}
+
+ //For progress tracking see:
+ //https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/Progress.java
+
+ public static RequestBody requestBody(final DownloadableFile file) {
+ return new RequestBody() {
+
+ @Override
+ public long contentLength() {
+ return file.getSize() + (file.getKey() != null ? 16 : 0);
+ }
+
+ @Nullable
+ @Override
+ public MediaType contentType() {
+ return MediaType.parse(file.getMimeType());
+ }
+
+ @Override
+ public void writeTo(final BufferedSink sink) throws IOException {
+ try (Source source = Okio.source(upgrade(file, new FileInputStream(file)))) {
+ sink.writeAll(source);
+ }
+ }
+ };
+ }
+
public static OutputStream createOutputStream(DownloadableFile file, boolean append, boolean decrypt) {
FileOutputStream os;
try {
diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
index 3174c4198..711d1ef76 100644
--- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
@@ -33,6 +33,7 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.http.AesGcmURLStreamHandler;
import eu.siacs.conversations.xmpp.Jid;
+import okhttp3.HttpUrl;
public final class CryptoHelper {
@@ -289,6 +290,14 @@ public final class CryptoHelper {
}
}
+ public static String toAesGcmUrl(HttpUrl url) {
+ if (url.isHttps()) {
+ return AesGcmURLStreamHandler.PROTOCOL_NAME + url.toString().substring(5);
+ } else {
+ return url.toString();
+ }
+ }
+
public static URL toHttpsUrl(URL url) {
if (!url.getProtocol().equalsIgnoreCase(AesGcmURLStreamHandler.PROTOCOL_NAME)) {
return url;