aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java
diff options
context:
space:
mode:
authorChristian Schneppe <christian.schneppe@pix-art.de>2019-12-24 13:52:27 +0100
committerChristian Schneppe <christian.schneppe@pix-art.de>2019-12-24 14:05:40 +0100
commit15d27e2cbb616480e6ce6cf5d25de9e5ab81c9c2 (patch)
tree9eaaa064726cb7ac91c12b8caf8381e6aa147593 /src/main/java
parent80c0e7d575616455626e883df08ce443f9ac9740 (diff)
Implement download resumption for OMEMO encrypted files
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/de/pixart/messenger/http/HttpDownloadConnection.java65
-rw-r--r--src/main/java/de/pixart/messenger/services/AbstractConnectionManager.java13
2 files changed, 56 insertions, 22 deletions
diff --git a/src/main/java/de/pixart/messenger/http/HttpDownloadConnection.java b/src/main/java/de/pixart/messenger/http/HttpDownloadConnection.java
index 6d92529db..ae53f580e 100644
--- a/src/main/java/de/pixart/messenger/http/HttpDownloadConnection.java
+++ b/src/main/java/de/pixart/messenger/http/HttpDownloadConnection.java
@@ -1,10 +1,14 @@
package de.pixart.messenger.http;
import android.os.PowerManager;
-import androidx.annotation.Nullable;
import android.util.Log;
+import androidx.annotation.Nullable;
+
+import com.google.common.io.ByteStreams;
+
import java.io.BufferedInputStream;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -93,12 +97,17 @@ public class HttpDownloadConnection implements Transferable {
} else {
ext = extension.main;
}
- if (message.getStatus() == Message.STATUS_RECEIVED){
+ if (message.getStatus() == Message.STATUS_RECEIVED) {
message.setRelativeFilePath(fileDateFormat.format(new Date(message.getTimeSent())) + "_" + message.getUuid().substring(0, 4) + (ext != null ? ("." + ext) : ""));
} else {
message.setRelativeFilePath("Sent/" + fileDateFormat.format(new Date(message.getTimeSent())) + "_" + message.getUuid().substring(0, 4) + (ext != null ? ("." + ext) : ""));
}
- this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
+ if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
+ this.file = new DownloadableFile(mXmppConnectionService.getCacheDir().getAbsolutePath() + "/" + message.getUuid());
+ Log.d(Config.LOGTAG, "create temporary OMEMO encrypted file: " + this.file.getAbsolutePath() + "(" + message.getMimeType() + ")");
+ } else {
+ this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
+ }
final String reference = mUrl.getRef();
if (reference != null && AesGcmURLStreamHandler.IV_KEY.matcher(reference).matches()) {
this.file.setKeyAndIv(CryptoHelper.hexToBytes(reference));
@@ -141,7 +150,41 @@ public class HttpDownloadConnection implements Transferable {
mHttpConnectionManager.updateConversationUi(true);
}
- private void finish() {
+ private void decryptOmemoFile() throws Exception {
+ final DownloadableFile outputFile = mXmppConnectionService.getFileBackend().getFile(message, true);
+
+ if (outputFile.getParentFile().mkdirs()) {
+ Log.d(Config.LOGTAG, "created parent directories for " + outputFile.getAbsolutePath());
+ }
+
+ try {
+ outputFile.createNewFile();
+ final InputStream is = new FileInputStream(this.file);
+
+ outputFile.setKey(this.file.getKey());
+ outputFile.setIv(this.file.getIv());
+ final OutputStream os = AbstractConnectionManager.createOutputStream(outputFile, false, true);
+
+ ByteStreams.copy(is, os);
+
+ FileBackend.close(is);
+ FileBackend.close(os);
+
+ if (!file.delete()) {
+ Log.w(Config.LOGTAG, "unable to delete temporary OMEMO encrypted file " + file.getAbsolutePath());
+ }
+
+ message.setRelativeFilePath(outputFile.getPath());
+ } catch (IOException e) {
+ message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
+ mXmppConnectionService.updateMessage(message);
+ }
+ }
+
+ private void finish() throws Exception {
+ if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
+ decryptOmemoFile();
+ }
message.setTransferable(null);
mHttpConnectionManager.finishConnection(this);
boolean notify = acceptedAutomatically && !message.isRead();
@@ -263,6 +306,10 @@ public class HttpDownloadConnection implements Transferable {
retrieveFailed(e);
return;
}
+ //TODO at this stage we probably also want to persist the file size in the body of the
+ // message via a similar mechansim as updateFileParams() - essentially body needs to read
+ // "url|filesize"
+ // afterwards a file that failed to download mid way will not display 'check file size' anymore
file.setExpectedSize(size);
message.resetFileParams();
if (mHttpConnectionManager.hasStoragePermission()
@@ -349,8 +396,8 @@ public class HttpDownloadConnection implements Transferable {
try {
changeStatus(STATUS_DOWNLOADING);
download();
- updateImageBounds();
finish();
+ updateImageBounds();
} catch (SSLHandshakeException e) {
changeStatus(STATUS_OFFER);
} catch (Exception e) {
@@ -383,11 +430,11 @@ public class HttpDownloadConnection implements Transferable {
connection.setRequestProperty("User-Agent", mXmppConnectionService.getIqGenerator().getUserAgent());
connection.setRequestProperty("Accept-Encoding", "identity");
final long expected = file.getExpectedSize();
- final boolean tryResume = file.exists() && file.getKey() == null && file.getSize() > 0 && file.getSize() < expected;
+ final boolean tryResume = file.exists() && file.getSize() > 0 && file.getSize() < expected;
long resumeSize = 0;
if (tryResume) {
resumeSize = file.getSize();
- Log.d(Config.LOGTAG, "http download trying resume after" + resumeSize + " of " + expected);
+ Log.d(Config.LOGTAG, "http download trying resume after " + resumeSize + " of " + expected);
connection.setRequestProperty("Range", "bytes=" + resumeSize + "-");
}
connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000);
@@ -401,7 +448,7 @@ public class HttpDownloadConnection implements Transferable {
Log.d(Config.LOGTAG, "server resumed");
transmitted = file.getSize();
updateProgress(Math.round(((double) transmitted / expected) * 100));
- os = AbstractConnectionManager.createAppendedOutputStream(file);
+ os = AbstractConnectionManager.createOutputStream(file, true, false);
if (os == null) {
throw new FileWriterException();
}
@@ -421,7 +468,7 @@ public class HttpDownloadConnection implements Transferable {
if (!file.exists() && !file.createNewFile()) {
throw new FileWriterException();
}
- os = AbstractConnectionManager.createOutputStream(file, true);
+ os = AbstractConnectionManager.createOutputStream(file, false, false);
}
int count;
byte[] buffer = new byte[4096];
diff --git a/src/main/java/de/pixart/messenger/services/AbstractConnectionManager.java b/src/main/java/de/pixart/messenger/services/AbstractConnectionManager.java
index 19a7341f8..cba382b61 100644
--- a/src/main/java/de/pixart/messenger/services/AbstractConnectionManager.java
+++ b/src/main/java/de/pixart/messenger/services/AbstractConnectionManager.java
@@ -51,19 +51,6 @@ public class AbstractConnectionManager {
}
}
-
- public static OutputStream createAppendedOutputStream(DownloadableFile file) {
- return createOutputStream(file, false, true);
- }
-
- public static OutputStream createOutputStream(DownloadableFile file) {
- return createOutputStream(file, false);
- }
-
- public static OutputStream createOutputStream(DownloadableFile file, boolean gcm) {
- return createOutputStream(file, gcm, false);
- }
-
public static OutputStream createOutputStream(DownloadableFile file, boolean append, boolean decrypt) {
FileOutputStream os;
try {