show p1s3 attchments with download button

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/generator/MessageGenerator.java | 13 
src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java  | 20 
src/main/java/eu/siacs/conversations/http/P1S3UrlStreamHandler.java  | 14 
src/main/java/eu/siacs/conversations/parser/MessageParser.java       | 14 
src/main/java/eu/siacs/conversations/utils/CryptoHelper.java         |  2 
src/main/java/eu/siacs/conversations/utils/MessageUtils.java         |  4 
6 files changed, 45 insertions(+), 22 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/generator/MessageGenerator.java 🔗

@@ -123,9 +123,16 @@ public class MessageGenerator extends AbstractGenerator {
 	public MessagePacket generatePgpChat(Message message) {
 		MessagePacket packet = preparePacket(message);
 		if (message.hasFileOnRemoteHost()) {
-			final String url = message.getFileParams().url.toString();
-			packet.setBody(url);
-			packet.addChild("x", Namespace.OOB).addChild("url").setContent(url);
+			Message.FileParams fileParams = message.getFileParams();
+			final URL url = fileParams.url;
+			if (P1S3UrlStreamHandler.PROTOCOL_NAME.equals(url.getProtocol())) {
+				Element x = packet.addChild("x", Namespace.P1_S3_FILE_TRANSFER);
+				x.setAttribute("name", url.getFile());
+				x.setAttribute("fileid", url.getHost());
+			} else {
+				packet.setBody(url.toString());
+				packet.addChild("x", Namespace.OOB).addChild("url").setContent(url.toString());
+			}
 		} else {
 			if (Config.supportUnencrypted()) {
 				packet.setBody(PGP_FALLBACK_MESSAGE);

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

@@ -1,18 +1,14 @@
 package eu.siacs.conversations.http;
 
 import android.os.PowerManager;
-import android.renderscript.ScriptGroup;
 import android.util.Log;
 import android.util.Pair;
 
-import org.bouncycastle.jce.exception.ExtIOException;
-
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -26,17 +22,12 @@ import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.DownloadableFile;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.Transferable;
-import eu.siacs.conversations.parser.IqParser;
 import eu.siacs.conversations.persistance.FileBackend;
 import eu.siacs.conversations.services.AbstractConnectionManager;
 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 eu.siacs.conversations.xml.Namespace;
-import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.stanzas.IqPacket;
-import rocks.xmpp.addr.Jid;
 
 public class HttpUploadConnection implements Transferable {
 
@@ -50,15 +41,13 @@ public class HttpUploadConnection implements Transferable {
 	private final XmppConnectionService mXmppConnectionService;
 	private final SlotRequester mSlotRequester;
 	private final Method method;
-
+	private final boolean mUseTor;
 	private boolean canceled = false;
 	private boolean delayed = false;
 	private DownloadableFile file;
 	private Message message;
 	private String mime;
 	private SlotRequester.Slot slot;
-	private final boolean mUseTor;
-
 	private byte[] key = null;
 
 	private long transmitted = 0;
@@ -156,7 +145,6 @@ public class HttpUploadConnection implements Transferable {
 			public void success(SlotRequester.Slot slot) {
 				if (!canceled) {
 					HttpUploadConnection.this.slot = slot;
-					Log.d(Config.LOGTAG,"not starting upload to "+slot.getPutUrl());
 					new Thread(HttpUploadConnection.this::upload).start();
 				}
 			}
@@ -225,7 +213,11 @@ public class HttpUploadConnection implements Transferable {
 				Log.d(Config.LOGTAG, "finished uploading file");
 				final URL get;
 				if (key != null) {
-					get = CryptoHelper.toAesGcmUrl(new URL(slot.getGetUrl().toString() + "#" + CryptoHelper.bytesToHex(key)));
+					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();
 				}

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

@@ -29,12 +29,13 @@
 
 package eu.siacs.conversations.http;
 
-import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.URLStreamHandler;
 
+import eu.siacs.conversations.xml.Element;
+
 public class P1S3UrlStreamHandler extends URLStreamHandler {
 
 	public static final String PROTOCOL_NAME = "p1s3";
@@ -45,6 +46,17 @@ public class P1S3UrlStreamHandler extends URLStreamHandler {
 	}
 
 	public static URL of(String fileId, String filename) throws MalformedURLException {
+		if (fileId == null || filename == null) {
+			throw new MalformedURLException("Paramaters must not be null");
+		}
 		return new URL(PROTOCOL_NAME+"://" + fileId + "/" + filename);
 	}
+
+	public static URL of(Element x) {
+		try {
+			return of(x.getAttribute("fileid"),x.getAttribute("name"));
+		} catch (MalformedURLException e) {
+			return null;
+		}
+	}
 }

src/main/java/eu/siacs/conversations/parser/MessageParser.java 🔗

@@ -3,6 +3,7 @@ package eu.siacs.conversations.parser;
 import android.util.Log;
 import android.util.Pair;
 
+import java.net.URL;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -27,6 +28,7 @@ import eu.siacs.conversations.entities.MucOptions;
 import eu.siacs.conversations.entities.ReadByMarker;
 import eu.siacs.conversations.entities.ReceiptRequest;
 import eu.siacs.conversations.http.HttpConnectionManager;
+import eu.siacs.conversations.http.P1S3UrlStreamHandler;
 import eu.siacs.conversations.services.MessageArchiveService;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.utils.CryptoHelper;
@@ -277,6 +279,8 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
 		final String pgpEncrypted = packet.findChildContent("x", "jabber:x:encrypted");
 		final Element replaceElement = packet.findChild("replace", "urn:xmpp:message-correct:0");
 		final Element oob = packet.findChild("x", Namespace.OOB);
+		final Element xP1S3 = packet.findChild("x", Namespace.P1_S3_FILE_TRANSFER);
+		final URL xP1S3url = xP1S3 == null ? null : P1S3UrlStreamHandler.of(xP1S3);
 		final String oobUrl = oob != null ? oob.findChildContent("url") : null;
 		final String replacementId = replaceElement == null ? null : replaceElement.getAttribute("id");
 		final Element axolotlEncrypted = packet.findChild(XmppAxolotlMessage.CONTAINERTAG, AxolotlService.PEP_PREFIX);
@@ -324,7 +328,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
 			return;
 		}
 
-		if ((body != null || pgpEncrypted != null || (axolotlEncrypted != null && axolotlEncrypted.hasChild("payload")) || oobUrl != null) && !isMucStatusMessage) {
+		if ((body != null || pgpEncrypted != null || (axolotlEncrypted != null && axolotlEncrypted.hasChild("payload")) || oobUrl != null || xP1S3 != null) && !isMucStatusMessage) {
 			final boolean conversationIsProbablyMuc = isTypeGroupChat || mucUserElement != null || account.getXmppConnection().getMucServersWithholdAccount().contains(counterpart.getDomain());
 			final Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), conversationIsProbablyMuc, false, query, false);
 			final boolean conversationMultiMode = conversation.getMode() == Conversation.MODE_MULTI;
@@ -362,7 +366,13 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
 				}
 			}
 			final Message message;
-			if (pgpEncrypted != null && Config.supportOpenPgp()) {
+			if (xP1S3url != null) {
+				message = new Message(conversation, xP1S3url.toString(), Message.ENCRYPTION_NONE, status);
+				message.setOob(true);
+				if (CryptoHelper.isPgpEncryptedUrl(xP1S3url.toString())) {
+					message.setEncryption(Message.ENCRYPTION_DECRYPTED);
+				}
+			} else if (pgpEncrypted != null && Config.supportOpenPgp()) {
 				message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
 			} else if (axolotlEncrypted != null && Config.supportOmemo()) {
 				Jid origin;

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

@@ -276,6 +276,6 @@ public final class CryptoHelper {
 			return false;
 		}
 		final String u = url.toLowerCase();
-		return !u.contains(" ") && (u.startsWith("https://") || u.startsWith("http://")) && u.endsWith(".pgp");
+		return !u.contains(" ") && (u.startsWith("https://") || u.startsWith("http://") || u.startsWith("p1s3://")) && u.endsWith(".pgp");
 	}
 }

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

@@ -35,6 +35,7 @@ import java.util.regex.Pattern;
 
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.http.AesGcmURLStreamHandler;
+import eu.siacs.conversations.http.P1S3UrlStreamHandler;
 
 public class MessageUtils {
 
@@ -79,7 +80,8 @@ public class MessageUtils {
 			final boolean encrypted = ref != null && AesGcmURLStreamHandler.IV_KEY.matcher(ref).matches();
 			final boolean followedByDataUri = lines.length == 2 && lines[1].startsWith("data:");
 			final boolean validAesGcm = AesGcmURLStreamHandler.PROTOCOL_NAME.equalsIgnoreCase(protocol) && encrypted && (lines.length == 1 || followedByDataUri);
-			final boolean validOob = ("http".equalsIgnoreCase(protocol) || "https".equalsIgnoreCase(protocol)) && (oob || encrypted) && lines.length == 1;
+			final boolean validProtocol = "http".equalsIgnoreCase(protocol) || "https".equalsIgnoreCase(protocol) || P1S3UrlStreamHandler.PROTOCOL_NAME.equalsIgnoreCase(protocol);
+			final boolean validOob = validProtocol && (oob || encrypted) && lines.length == 1;
 			return validAesGcm || validOob;
 		} catch (MalformedURLException e) {
 			return false;