mirror of https://github.com/M66B/FairEmail.git
CanonicalizingStream
This commit is contained in:
parent
beeba4c999
commit
cd821fc7c3
|
@ -3835,7 +3835,8 @@ public class FragmentCompose extends FragmentBase {
|
||||||
};
|
};
|
||||||
bpContent.setContent(imessage.getContent(), imessage.getContentType());
|
bpContent.setContent(imessage.getContent(), imessage.getContentType());
|
||||||
|
|
||||||
try (OutputStream out = new FileOutputStream(input)) {
|
try (OutputStream out = new MessageHelper.CanonicalizingStream(
|
||||||
|
new BufferedOutputStream(new FileOutputStream(input)))) {
|
||||||
bpContent.writeTo(out);
|
bpContent.writeTo(out);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -4248,8 +4249,9 @@ public class FragmentCompose extends FragmentBase {
|
||||||
|
|
||||||
// Build content
|
// Build content
|
||||||
File sinput = new File(tmp, draft.id + ".smime_sign");
|
File sinput = new File(tmp, draft.id + ".smime_sign");
|
||||||
try (FileOutputStream fos = new FileOutputStream(sinput)) {
|
try (OutputStream os = new MessageHelper.CanonicalizingStream(
|
||||||
bpContent.writeTo(fos);
|
new BufferedOutputStream(new FileOutputStream(sinput)))) {
|
||||||
|
bpContent.writeTo(os);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EntityMessage.SMIME_SIGNONLY.equals(type)) {
|
if (EntityMessage.SMIME_SIGNONLY.equals(type)) {
|
||||||
|
|
|
@ -77,6 +77,7 @@ import org.simplejavamail.outlookmessageparser.model.OutlookFileAttachment;
|
||||||
import org.simplejavamail.outlookmessageparser.model.OutlookMessage;
|
import org.simplejavamail.outlookmessageparser.model.OutlookMessage;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
@ -84,6 +85,7 @@ import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
|
import java.io.FilterOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
@ -4098,23 +4100,9 @@ public class MessageHelper {
|
||||||
if (TextUtils.isEmpty(boundary))
|
if (TextUtils.isEmpty(boundary))
|
||||||
throw new ParseException("Signed boundary missing");
|
throw new ParseException("Signed boundary missing");
|
||||||
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
apart.part.writeTo(bos);
|
|
||||||
String raw = new String(bos.toByteArray(), StandardCharsets.ISO_8859_1);
|
|
||||||
String[] parts = raw.split("\\r?\\n" + Pattern.quote("--" + boundary) + "\\r?\\n");
|
|
||||||
if (parts.length < 2)
|
|
||||||
throw new ParseException("Signed part missing");
|
|
||||||
|
|
||||||
// PGP: https://datatracker.ietf.org/doc/html/rfc3156#section-5
|
|
||||||
// S/MIME: https://datatracker.ietf.org/doc/html/rfc8551#section-3.1.1
|
|
||||||
String c = parts[1]
|
|
||||||
.replaceAll("\\r?\\n", "\r\n"); // normalize new lines
|
|
||||||
if (EntityAttachment.PGP_CONTENT.equals(apart.encrypt))
|
|
||||||
c = c.replaceAll(" +$", ""); // trim trailing spaces
|
|
||||||
|
|
||||||
File file = local.getFile(context);
|
File file = local.getFile(context);
|
||||||
try (OutputStream os = new FileOutputStream(file)) {
|
try (OutputStream os = new BufferedOutputStream(new CanonicalizingStream(new FileOutputStream(file), boundary))) {
|
||||||
os.write(c.getBytes(StandardCharsets.ISO_8859_1));
|
apart.part.writeTo(os);
|
||||||
}
|
}
|
||||||
|
|
||||||
DB db = DB.getInstance(context);
|
DB db = DB.getInstance(context);
|
||||||
|
@ -5771,4 +5759,104 @@ public class MessageHelper {
|
||||||
return "message/feedback-report".equalsIgnoreCase(type);
|
return "message/feedback-report".equalsIgnoreCase(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class CanonicalizingStream extends FilterOutputStream {
|
||||||
|
private OutputStream os;
|
||||||
|
private String boundary;
|
||||||
|
|
||||||
|
private int boundaries = 0;
|
||||||
|
private boolean carriage = false;
|
||||||
|
private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
private static final byte[] CRLF = "\r\n".getBytes(StandardCharsets.ISO_8859_1);
|
||||||
|
|
||||||
|
// PGP: https://datatracker.ietf.org/doc/html/rfc3156#section-5
|
||||||
|
// S/MIME: https://datatracker.ietf.org/doc/html/rfc8551#section-3.1.1
|
||||||
|
|
||||||
|
public CanonicalizingStream(OutputStream out) {
|
||||||
|
super(out);
|
||||||
|
this.os = out;
|
||||||
|
this.boundary = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CanonicalizingStream(OutputStream out, String boundary) {
|
||||||
|
super(out);
|
||||||
|
this.os = out;
|
||||||
|
this.boundary = "--" + boundary;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
this.write(new byte[]{(byte) b}, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b) throws IOException {
|
||||||
|
this.write(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
|
for (int i = off; i < off + len; i++) {
|
||||||
|
byte k = b[i];
|
||||||
|
if (k == '\r')
|
||||||
|
carriage = true;
|
||||||
|
else {
|
||||||
|
if (k == '\n') {
|
||||||
|
if (writeBuffer())
|
||||||
|
buffer.write(CRLF);
|
||||||
|
} else {
|
||||||
|
if (carriage) {
|
||||||
|
if (writeBuffer())
|
||||||
|
buffer.write(CRLF);
|
||||||
|
}
|
||||||
|
buffer.write(k);
|
||||||
|
}
|
||||||
|
carriage = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
flushBuffer();
|
||||||
|
super.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
flushBuffer();
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean writeBuffer() throws IOException {
|
||||||
|
try {
|
||||||
|
String line = new String(buffer.toByteArray(), StandardCharsets.ISO_8859_1);
|
||||||
|
|
||||||
|
if (boundary != null) {
|
||||||
|
if (boundary.equals(line.trim())) {
|
||||||
|
boundaries++;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (boundaries != 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
line = line.replaceAll(" +$", "");
|
||||||
|
|
||||||
|
os.write(line.getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
buffer.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void flushBuffer() throws IOException {
|
||||||
|
if (boundary != null && boundaries != 2)
|
||||||
|
throw new IOException("Content boundaries=" + boundaries);
|
||||||
|
if (buffer.size() > 0)
|
||||||
|
writeBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue