Don't allow user to supply content of type message/*

Instead we rewrite the MIME type to application/octet-stream. This is
so we don't create broken messages in case the user-supplied content is
not a valid message.
In the future we could add some validation code and allow the user to
attach well-formed messages using the proper MIME type.
This commit is contained in:
cketti 2017-11-15 22:48:46 +01:00
parent 1da373ad06
commit 6b28c5b41b
6 changed files with 40 additions and 14 deletions

View file

@ -1129,6 +1129,10 @@ public class MimeUtility {
return isSameMimeType(mimeType, "message/rfc822");
}
public static boolean isMessageType(String mimeType) {
return mimeType != null && mimeType.toLowerCase(Locale.ROOT).startsWith("message/");
}
public static boolean isSameMimeType(String mimeType, String otherMimeType) {
return mimeType != null && mimeType.equalsIgnoreCase(otherMimeType);
}

View file

@ -146,7 +146,7 @@ public class AttachmentPresenter {
int loaderId = getNextFreeLoaderId();
Attachment attachment = Attachment.createAttachment(
attachmentViewInfo.internalUri, loaderId, attachmentViewInfo.mimeType);
attachmentViewInfo.internalUri, loaderId, attachmentViewInfo.mimeType, true);
attachment = attachment.deriveWithMetadataLoaded(
attachmentViewInfo.mimeType, attachmentViewInfo.displayName, attachmentViewInfo.size);
@ -154,12 +154,16 @@ public class AttachmentPresenter {
}
public void addAttachment(Uri uri, String contentType) {
addAttachment(uri, contentType, false);
}
private void addAttachment(Uri uri, String contentType, boolean allowMessageType) {
if (attachments.containsKey(uri)) {
return;
}
int loaderId = getNextFreeLoaderId();
Attachment attachment = Attachment.createAttachment(uri, loaderId, contentType);
Attachment attachment = Attachment.createAttachment(uri, loaderId, contentType, allowMessageType);
addAttachmentAndStartLoader(attachment);
}
@ -188,7 +192,9 @@ public class AttachmentPresenter {
}
}
public void processMessageToForwardAsAttachment(MessageViewInfo messageViewInfo) throws IOException, MessagingException {
public void processMessageToForwardAsAttachment(MessageViewInfo messageViewInfo) throws IOException,
MessagingException {
if (messageViewInfo.isMessageIncomplete) {
attachmentMvpView.showMissingAttachmentsPartialMessageForwardWarning();
} else {
@ -196,7 +202,7 @@ public class AttachmentPresenter {
MessageReference messageReference = localMessage.makeMessageReference();
Uri rawMessageUri = RawMessageProvider.getRawMessageUri(messageReference);
addAttachment(rawMessageUri, "message/rfc822");
addAttachment(rawMessageUri, "message/rfc822", true);
}
}

View file

@ -83,6 +83,10 @@ public class AttachmentInfoLoader extends AsyncTaskLoader<Attachment> {
usableContentType = MimeUtility.getMimeTypeByExtension(name);
}
if (!sourceAttachment.allowMessageType && MimeUtility.isMessageType(usableContentType)) {
usableContentType = MimeUtility.DEFAULT_ATTACHMENT_MIME_TYPE;
}
if (size <= 0) {
String uriString = uri.toString();
if (uriString.startsWith("file://")) {

View file

@ -34,6 +34,11 @@ public class Attachment implements Parcelable {
*/
public final String contentType;
/**
* {@code true} if we allow MIME types of {@code message/*}, e.g. {@code message/rfc822}.
*/
public final boolean allowMessageType;
/**
* The (file)name of the attachment.
*
@ -62,12 +67,13 @@ public class Attachment implements Parcelable {
CANCELLED
}
private Attachment(Uri uri, LoadingState state, int loaderId, String contentType, String name, Long size,
String filename) {
private Attachment(Uri uri, LoadingState state, int loaderId, String contentType, boolean allowMessageType,
String name, Long size, String filename) {
this.uri = uri;
this.state = state;
this.loaderId = loaderId;
this.contentType = contentType;
this.allowMessageType = allowMessageType;
this.name = name;
this.size = size;
this.filename = filename;
@ -78,6 +84,7 @@ public class Attachment implements Parcelable {
state = (LoadingState) in.readSerializable();
loaderId = in.readInt();
contentType = in.readString();
allowMessageType = in.readInt() != 0;
name = in.readString();
if (in.readInt() != 0) {
size = in.readLong();
@ -87,29 +94,33 @@ public class Attachment implements Parcelable {
filename = in.readString();
}
public static Attachment createAttachment(Uri uri, int loaderId, String contentType) {
return new Attachment(uri, Attachment.LoadingState.URI_ONLY, loaderId, contentType, null, null, null);
public static Attachment createAttachment(Uri uri, int loaderId, String contentType, boolean allowMessageType) {
return new Attachment(uri, Attachment.LoadingState.URI_ONLY, loaderId, contentType, allowMessageType, null,
null, null);
}
public Attachment deriveWithMetadataLoaded(String usableContentType, String name, long size) {
if (state != Attachment.LoadingState.URI_ONLY) {
throw new IllegalStateException("deriveWithMetadataLoaded can only be called on a URI_ONLY attachment!");
}
return new Attachment(uri, Attachment.LoadingState.METADATA, loaderId, usableContentType, name, size, null);
return new Attachment(uri, Attachment.LoadingState.METADATA, loaderId, usableContentType, allowMessageType,
name, size, null);
}
public Attachment deriveWithLoadCancelled() {
if (state != Attachment.LoadingState.METADATA) {
throw new IllegalStateException("deriveWitLoadCancelled can only be called on a METADATA attachment!");
}
return new Attachment(uri, Attachment.LoadingState.CANCELLED, loaderId, contentType, name, size, null);
return new Attachment(uri, Attachment.LoadingState.CANCELLED, loaderId, contentType, allowMessageType, name,
size, null);
}
public Attachment deriveWithLoadComplete(String absolutePath) {
if (state != Attachment.LoadingState.METADATA) {
throw new IllegalStateException("deriveWithLoadComplete can only be called on a METADATA attachment!");
}
return new Attachment(uri, Attachment.LoadingState.COMPLETE, loaderId, contentType, name, size, absolutePath);
return new Attachment(uri, Attachment.LoadingState.COMPLETE, loaderId, contentType, allowMessageType, name,
size, absolutePath);
}
// === Parcelable ===
@ -125,6 +136,7 @@ public class Attachment implements Parcelable {
dest.writeSerializable(state);
dest.writeInt(loaderId);
dest.writeString(contentType);
dest.writeInt(allowMessageType ? 1 : 0);
dest.writeString(name);
if (size != null) {
dest.writeInt(1);

View file

@ -274,7 +274,7 @@ public class MessageBuilderTest {
fileOutputStream.write(bytes);
fileOutputStream.close();
return Attachment.createAttachment(null, 0, mimeType)
return Attachment.createAttachment(null, 0, mimeType, true)
.deriveWithMetadataLoaded(mimeType, filename, bytes.length)
.deriveWithLoadComplete(tempFile.getAbsolutePath());
}

View file

@ -464,7 +464,7 @@ public class PgpMessageBuilderTest {
.setEnablePgpInline(true)
.build();
pgpMessageBuilder.setCryptoStatus(cryptoStatus);
pgpMessageBuilder.setAttachments(Collections.singletonList(Attachment.createAttachment(null, 0, null)));
pgpMessageBuilder.setAttachments(Collections.singletonList(Attachment.createAttachment(null, 0, null, true)));
Callback mockCallback = mock(Callback.class);
pgpMessageBuilder.buildAsync(mockCallback);
@ -481,7 +481,7 @@ public class PgpMessageBuilderTest {
.setEnablePgpInline(true)
.build();
pgpMessageBuilder.setCryptoStatus(cryptoStatus);
pgpMessageBuilder.setAttachments(Collections.singletonList(Attachment.createAttachment(null, 0, null)));
pgpMessageBuilder.setAttachments(Collections.singletonList(Attachment.createAttachment(null, 0, null, true)));
Callback mockCallback = mock(Callback.class);
pgpMessageBuilder.buildAsync(mockCallback);