Added base64 encoded attachment support

This commit is contained in:
Kevin R 2022-06-03 00:08:20 +02:00
parent 63e94a9fb4
commit ed8793f354
No known key found for this signature in database
GPG key ID: A4AD5E0732960C98
4 changed files with 47 additions and 7 deletions

View file

@ -51,7 +51,7 @@ public class AttachmentHelper {
} }
public SignalServiceAttachmentPointer uploadAttachment(String attachment) throws IOException, AttachmentInvalidException { public SignalServiceAttachmentPointer uploadAttachment(String attachment) throws IOException, AttachmentInvalidException {
var attachmentStream = AttachmentUtils.createAttachmentStream(new File(attachment)); var attachmentStream = AttachmentUtils.createAttachmentStream(attachment);
return uploadAttachment(attachmentStream); return uploadAttachment(attachmentStream);
} }

View file

@ -6,6 +6,7 @@ import org.whispersystems.signalservice.api.util.StreamDetails;
import org.whispersystems.signalservice.internal.push.http.ResumableUploadSpec; import org.whispersystems.signalservice.internal.push.http.ResumableUploadSpec;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -19,17 +20,21 @@ public class AttachmentUtils {
} }
final var signalServiceAttachments = new ArrayList<SignalServiceAttachmentStream>(attachments.size()); final var signalServiceAttachments = new ArrayList<SignalServiceAttachmentStream>(attachments.size());
for (var attachment : attachments) { for (var attachment : attachments) {
signalServiceAttachments.add(createAttachmentStream(new File(attachment))); signalServiceAttachments.add(createAttachmentStream(attachment));
} }
return signalServiceAttachments; return signalServiceAttachments;
} }
public static SignalServiceAttachmentStream createAttachmentStream(File attachmentFile) throws AttachmentInvalidException { public static SignalServiceAttachmentStream createAttachmentStream(String attachment) throws AttachmentInvalidException {
try { try {
final var streamDetails = Utils.createStreamDetailsFromFile(attachmentFile); final var streamDetails = Utils.createStreamDetails(attachment);
return createAttachmentStream(streamDetails, Optional.of(attachmentFile.getName())); final var name = streamDetails.getStream() instanceof FileInputStream
? new File(attachment).getName()
: null;
return createAttachmentStream(streamDetails, Optional.ofNullable(name));
} catch (IOException e) { } catch (IOException e) {
throw new AttachmentInvalidException(attachmentFile.toString(), e); throw new AttachmentInvalidException(attachment, e);
} }
} }

View file

@ -9,6 +9,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.StreamDetails; import org.whispersystems.signalservice.api.util.StreamDetails;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
@ -17,6 +18,7 @@ import java.net.URLConnection;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.Base64;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -44,6 +46,29 @@ public class Utils {
return mime; return mime;
} }
private static boolean isBase64DataString(String[] parts) {
return parts.length == 2
&& parts[0].startsWith("data:")
&& parts[0].contains("/")
&& parts[1].startsWith("base64,");
}
public static boolean isBase64DataString(String value) {
return isBase64DataString(value.split(";", 2));
}
public static StreamDetails createStreamDetailsFromBase64(String base64) {
final String[] parts = base64.split(";", 2);
if (!isBase64DataString(parts)) {
throw new IllegalArgumentException("The given argument is not a valid base64 string.");
}
parts[0] = parts[0].substring(5);
byte[] bytes = Base64.getDecoder().decode(parts[1].substring(7).getBytes(StandardCharsets.UTF_8));
return new StreamDetails(new ByteArrayInputStream(bytes), parts[0], bytes.length);
}
public static StreamDetails createStreamDetailsFromFile(File file) throws IOException { public static StreamDetails createStreamDetailsFromFile(File file) throws IOException {
InputStream stream = new FileInputStream(file); InputStream stream = new FileInputStream(file);
final var size = file.length(); final var size = file.length();
@ -51,6 +76,14 @@ public class Utils {
return new StreamDetails(stream, mime, size); return new StreamDetails(stream, mime, size);
} }
public static StreamDetails createStreamDetails(String value) throws IOException {
if (isBase64DataString(value)) {
return createStreamDetailsFromBase64(value);
}
return createStreamDetailsFromFile(new File(value));
}
public static Fingerprint computeSafetyNumber( public static Fingerprint computeSafetyNumber(
boolean isUuidCapable, boolean isUuidCapable,
SignalServiceAddress ownAddress, SignalServiceAddress ownAddress,

View file

@ -55,7 +55,9 @@ public class SendCommand implements JsonRpcLocalCommand {
mut.addArgument("--message-from-stdin") mut.addArgument("--message-from-stdin")
.action(Arguments.storeTrue()) .action(Arguments.storeTrue())
.help("Read the message from standard input."); .help("Read the message from standard input.");
subparser.addArgument("-a", "--attachment").nargs("*").help("Add file as attachment"); subparser.addArgument("-a", "--attachment").nargs("*").help("Add file as attachment."
+ "Base64 encoded attachments can be added and must follow the format "
+ "data:<MIME-TYPE>;base64,<BASE64 ENCODED DATA>.");
subparser.addArgument("-e", "--end-session", "--endsession") subparser.addArgument("-e", "--end-session", "--endsession")
.help("Clear session state and send end session message.") .help("Clear session state and send end session message.")
.action(Arguments.storeTrue()); .action(Arguments.storeTrue());