discover file extension in original filename from pgp

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java | 24 
src/main/java/eu/siacs/conversations/entities/Message.java            | 37 
src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java |  2 
src/main/java/eu/siacs/conversations/persistance/FileBackend.java     | 22 
src/main/java/eu/siacs/conversations/utils/MimeUtils.java             | 33 
5 files changed, 75 insertions(+), 43 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java 🔗

@@ -2,7 +2,9 @@ package eu.siacs.conversations.crypto;
 
 import android.app.PendingIntent;
 import android.content.Intent;
+import android.util.Log;
 
+import org.openintents.openpgp.OpenPgpMetadata;
 import org.openintents.openpgp.util.OpenPgpApi;
 
 import java.io.ByteArrayInputStream;
@@ -17,11 +19,13 @@ import java.util.ArrayDeque;
 import java.util.HashSet;
 import java.util.List;
 
+import eu.siacs.conversations.Config;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.DownloadableFile;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.http.HttpConnectionManager;
 import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.utils.MimeUtils;
 
 public class PgpDecryptionService {
 
@@ -176,13 +180,31 @@ public class PgpDecryptionService {
 				try {
 					final DownloadableFile inputFile = mXmppConnectionService.getFileBackend().getFile(message, false);
 					final DownloadableFile outputFile = mXmppConnectionService.getFileBackend().getFile(message, true);
-					outputFile.getParentFile().mkdirs();
+					if (outputFile.getParentFile().mkdirs()) {
+						Log.d(Config.LOGTAG,"created parent directories for "+outputFile.getAbsolutePath());
+					}
 					outputFile.createNewFile();
 					InputStream is = new FileInputStream(inputFile);
 					OutputStream os = new FileOutputStream(outputFile);
 					Intent result = getOpenPgpApi().executeApi(params, is, os);
 					switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
 						case OpenPgpApi.RESULT_CODE_SUCCESS:
+							OpenPgpMetadata openPgpMetadata = result.getParcelableExtra(OpenPgpApi.RESULT_METADATA);
+							String originalFilename = openPgpMetadata.getFilename();
+							String originalExtension = originalFilename == null ? null : MimeUtils.extractRelevantExtension(originalFilename);
+							if (originalExtension != null && MimeUtils.extractRelevantExtension(outputFile.getName()) == null) {
+								Log.d(Config.LOGTAG,"detected original filename during pgp decryption");
+								String mime = MimeUtils.guessMimeTypeFromExtension(originalExtension);
+								String path = outputFile.getName()+"."+originalExtension;
+								DownloadableFile fixedFile = mXmppConnectionService.getFileBackend().getFileForPath(path,mime);
+								if (fixedFile.getParentFile().mkdirs()) {
+									Log.d(Config.LOGTAG,"created parent directories for "+fixedFile.getAbsolutePath());
+								}
+								if (outputFile.renameTo(fixedFile)) {
+									Log.d(Config.LOGTAG, "renamed " + outputFile.getAbsolutePath() + " to " + fixedFile.getAbsolutePath());
+									message.setRelativeFilePath(path);
+								}
+							}
 							URL url = message.getFileParams().url;
 							mXmppConnectionService.getFileBackend().updateFileParams(message, url);
 							message.setEncryption(Message.ENCRYPTION_DECRYPTED);

src/main/java/eu/siacs/conversations/entities/Message.java 🔗

@@ -680,46 +680,19 @@ public class Message extends AbstractEntity {
 		this.oob = isOob;
 	}
 
-	private static String extractRelevantExtension(URL url) {
-		String path = url.getPath();
-		return extractRelevantExtension(path);
-	}
-
-	private static String extractRelevantExtension(String path) {
-		if (path == null || path.isEmpty()) {
-			return null;
-		}
-
-		String filename = path.substring(path.lastIndexOf('/') + 1).toLowerCase();
-		int dotPosition = filename.lastIndexOf(".");
-
-		if (dotPosition != -1) {
-			String extension = filename.substring(dotPosition + 1);
-			// we want the real file extension, not the crypto one
-			if (Transferable.VALID_CRYPTO_EXTENSIONS.contains(extension)) {
-				return extractRelevantExtension(filename.substring(0,dotPosition));
-			} else {
-				return extension;
-			}
-		}
-		return null;
-	}
-
 	public String getMimeType() {
+		String extension;
 		if (relativeFilePath != null) {
-			int start = relativeFilePath.lastIndexOf('.') + 1;
-			if (start < relativeFilePath.length()) {
-				return MimeUtils.guessMimeTypeFromExtension(relativeFilePath.substring(start));
-			} else {
-				return null;
-			}
+			extension = MimeUtils.extractRelevantExtension(relativeFilePath);
 		} else {
 			try {
-				return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(body.trim())));
+				final URL url = new URL(body.split("\n")[0]);
+				extension = MimeUtils.extractRelevantExtension(url);
 			} catch (MalformedURLException e) {
 				return null;
 			}
 		}
+		return MimeUtils.guessMimeTypeFromExtension(extension);
 	}
 
 	public synchronized boolean treatAsDownloadable() {

src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java 🔗

@@ -89,7 +89,7 @@ public class HttpDownloadConnection implements Transferable {
 			} else {
 				extension = lastPart;
 			}
-			message.setRelativeFilePath(message.getUuid() + "." + extension);
+			message.setRelativeFilePath(message.getUuid() + (extension != null ? ("." + extension) : ""));
 			this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
 			final String reference = mUrl.getRef();
 			if (reference != null && AesGcmURLStreamHandler.IV_KEY.matcher(reference).matches()) {

src/main/java/eu/siacs/conversations/persistance/FileBackend.java 🔗

@@ -110,19 +110,11 @@ public class FileBackend {
 		return getFile(message, true);
 	}
 
-	public DownloadableFile getFile(Message message, boolean decrypted) {
-		final boolean encrypted = !decrypted
-				&& (message.getEncryption() == Message.ENCRYPTION_PGP
-				|| message.getEncryption() == Message.ENCRYPTION_DECRYPTED);
+	public DownloadableFile getFileForPath(String path, String mime) {
 		final DownloadableFile file;
-		String path = message.getRelativeFilePath();
-		if (path == null) {
-			path = message.getUuid();
-		}
 		if (path.startsWith("/")) {
 			file = new DownloadableFile(path);
 		} else {
-			String mime = message.getMimeType();
 			if (mime != null && mime.startsWith("image/")) {
 				file = new DownloadableFile(getConversationsDirectory("Images") + path);
 			} else if (mime != null && mime.startsWith("video/")) {
@@ -131,6 +123,18 @@ public class FileBackend {
 				file = new DownloadableFile(getConversationsDirectory("Files") + path);
 			}
 		}
+		return file;
+	}
+
+	public DownloadableFile getFile(Message message, boolean decrypted) {
+		final boolean encrypted = !decrypted
+				&& (message.getEncryption() == Message.ENCRYPTION_PGP
+				|| message.getEncryption() == Message.ENCRYPTION_DECRYPTED);
+		String path = message.getRelativeFilePath();
+		if (path == null) {
+			path = message.getUuid();
+		}
+		final DownloadableFile file = getFileForPath(path, message.getMimeType());
 		if (encrypted) {
 			return new DownloadableFile(getConversationsDirectory("Files") + file.getName() + ".pgp");
 		} else {

src/main/java/eu/siacs/conversations/utils/MimeUtils.java 🔗

@@ -21,9 +21,13 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URL;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
+
+import eu.siacs.conversations.entities.Transferable;
+
 /**
  * Utilities for dealing with MIME types.
  * Used to implement java.net.URLConnection and android.webkit.MimeTypeMap.
@@ -510,4 +514,33 @@ public final class MimeUtils {
         }
         return mimeType;
     }
+
+    public static String extractRelevantExtension(URL url) {
+        String path = url.getPath();
+        return extractRelevantExtension(path, true);
+    }
+
+    public static String extractRelevantExtension(final String path) {
+        return extractRelevantExtension(path, false);
+    }
+
+    public static String extractRelevantExtension(final String path, final boolean ignoreCryptoExtension) {
+        if (path == null || path.isEmpty()) {
+            return null;
+        }
+
+        String filename = path.substring(path.lastIndexOf('/') + 1).toLowerCase();
+        int dotPosition = filename.lastIndexOf(".");
+
+        if (dotPosition != -1) {
+            String extension = filename.substring(dotPosition + 1);
+            // we want the real file extension, not the crypto one
+            if (ignoreCryptoExtension && Transferable.VALID_CRYPTO_EXTENSIONS.contains(extension)) {
+                return extractRelevantExtension(filename.substring(0,dotPosition));
+            } else {
+                return extension;
+            }
+        }
+        return null;
+    }
 }