mirror of https://github.com/M66B/FairEmail.git
Encrypt/decrypt attachments
This commit is contained in:
parent
78005ab869
commit
97562a9b38
|
@ -920,32 +920,62 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
|
||||||
new SimpleTask<PendingIntent>() {
|
new SimpleTask<PendingIntent>() {
|
||||||
@Override
|
@Override
|
||||||
protected PendingIntent onLoad(Context context, Bundle args) throws Throwable {
|
protected PendingIntent onLoad(Context context, Bundle args) throws Throwable {
|
||||||
|
// Get arguments
|
||||||
long id = args.getLong("id");
|
long id = args.getLong("id");
|
||||||
Intent data = args.getParcelable("data");
|
Intent data = args.getParcelable("data");
|
||||||
|
|
||||||
DB db = DB.getInstance(context);
|
if (!pgpService.isBound())
|
||||||
for (EntityAttachment attachment : db.attachment().getAttachments(id))
|
throw new IllegalArgumentException(getString(R.string.title_no_openpgp));
|
||||||
if (attachment.available && "encrypted.asc".equals(attachment.name)) {
|
|
||||||
if (!pgpService.isBound())
|
|
||||||
throw new IllegalArgumentException(getString(R.string.title_no_openpgp));
|
|
||||||
|
|
||||||
OpenPgpApi api = new OpenPgpApi(context, pgpService.getService());
|
DB db = DB.getInstance(context);
|
||||||
|
|
||||||
|
// Find encrypted data
|
||||||
|
List<EntityAttachment> attachments = db.attachment().getAttachments(id);
|
||||||
|
for (EntityAttachment attachment : attachments)
|
||||||
|
if (attachment.available && "encrypted.asc".equals(attachment.name)) {
|
||||||
|
// Serialize encrypted data
|
||||||
FileInputStream encrypted = new FileInputStream(EntityAttachment.getFile(context, attachment.id));
|
FileInputStream encrypted = new FileInputStream(EntityAttachment.getFile(context, attachment.id));
|
||||||
ByteArrayOutputStream decrypted = new ByteArrayOutputStream();
|
ByteArrayOutputStream decrypted = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
// Decrypt message
|
||||||
|
OpenPgpApi api = new OpenPgpApi(context, pgpService.getService());
|
||||||
Intent result = api.executeApi(data, encrypted, decrypted);
|
Intent result = api.executeApi(data, encrypted, decrypted);
|
||||||
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
|
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
|
||||||
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
||||||
ByteArrayInputStream is = new ByteArrayInputStream(decrypted.toByteArray());
|
// Decode message
|
||||||
|
|
||||||
Properties props = MessageHelper.getSessionProperties(Helper.AUTH_TYPE_PASSWORD, false);
|
Properties props = MessageHelper.getSessionProperties(Helper.AUTH_TYPE_PASSWORD, false);
|
||||||
Session isession = Session.getInstance(props, null);
|
Session isession = Session.getInstance(props, null);
|
||||||
|
ByteArrayInputStream is = new ByteArrayInputStream(decrypted.toByteArray());
|
||||||
MimeMessage imessage = new MimeMessage(isession, is);
|
MimeMessage imessage = new MimeMessage(isession, is);
|
||||||
MessageHelper helper = new MessageHelper(imessage);
|
MessageHelper helper = new MessageHelper(imessage);
|
||||||
|
|
||||||
EntityMessage m = db.message().getMessage(id);
|
try {
|
||||||
m.write(context, helper.getHtml());
|
db.beginTransaction();
|
||||||
db.message().setMessageStored(id, new Date().getTime());
|
|
||||||
|
// Write decrypted body
|
||||||
|
EntityMessage m = db.message().getMessage(id);
|
||||||
|
m.write(context, helper.getHtml());
|
||||||
|
|
||||||
|
// Remove previously decrypted attachments
|
||||||
|
for (EntityAttachment a : attachments)
|
||||||
|
if (!"encrypted.asc".equals(a.name))
|
||||||
|
db.attachment().deleteAttachment(a.id);
|
||||||
|
|
||||||
|
// Add decrypted attachments
|
||||||
|
int sequence = db.attachment().getAttachmentSequence(id);
|
||||||
|
for (EntityAttachment a : helper.getAttachments()) {
|
||||||
|
a.message = id;
|
||||||
|
a.sequence = ++sequence;
|
||||||
|
a.id = db.attachment().insertAttachment(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.message().setMessageStored(id, new Date().getTime());
|
||||||
|
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
} finally {
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
|
||||||
|
|
|
@ -66,7 +66,6 @@ import android.widget.Toast;
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import org.jsoup.Jsoup;
|
|
||||||
import org.openintents.openpgp.OpenPgpError;
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
||||||
|
@ -79,7 +78,6 @@ import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -89,15 +87,11 @@ import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.mail.Address;
|
import javax.mail.Address;
|
||||||
import javax.mail.BodyPart;
|
|
||||||
import javax.mail.MessageRemovedException;
|
import javax.mail.MessageRemovedException;
|
||||||
import javax.mail.Multipart;
|
|
||||||
import javax.mail.Session;
|
import javax.mail.Session;
|
||||||
import javax.mail.internet.AddressException;
|
import javax.mail.internet.AddressException;
|
||||||
import javax.mail.internet.InternetAddress;
|
import javax.mail.internet.InternetAddress;
|
||||||
import javax.mail.internet.MimeBodyPart;
|
|
||||||
import javax.mail.internet.MimeMessage;
|
import javax.mail.internet.MimeMessage;
|
||||||
import javax.mail.internet.MimeMultipart;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -526,64 +520,62 @@ public class FragmentCompose extends FragmentEx {
|
||||||
new SimpleTask<PendingIntent>() {
|
new SimpleTask<PendingIntent>() {
|
||||||
@Override
|
@Override
|
||||||
protected PendingIntent onLoad(Context context, Bundle args) throws Throwable {
|
protected PendingIntent onLoad(Context context, Bundle args) throws Throwable {
|
||||||
|
// Get arguments
|
||||||
long id = args.getLong("id");
|
long id = args.getLong("id");
|
||||||
Intent data = args.getParcelable("data");
|
Intent data = args.getParcelable("data");
|
||||||
|
|
||||||
String body = EntityMessage.read(getContext(), id);
|
if (!pgpService.isBound())
|
||||||
|
throw new IllegalArgumentException(getString(R.string.title_no_openpgp));
|
||||||
|
|
||||||
BodyPart plain = new MimeBodyPart();
|
DB db = DB.getInstance(context);
|
||||||
plain.setContent(Jsoup.parse(body).text(), "text/plain; charset=" + Charset.defaultCharset().name());
|
|
||||||
|
|
||||||
BodyPart html = new MimeBodyPart();
|
// Get attachments
|
||||||
html.setContent(body, "text/html; charset=" + Charset.defaultCharset().name());
|
EntityMessage message = db.message().getMessage(id);
|
||||||
|
List<EntityAttachment> attachments = db.attachment().getAttachments(id);
|
||||||
Multipart alternative = new MimeMultipart("alternative");
|
for (EntityAttachment attachment : new ArrayList<>(attachments))
|
||||||
alternative.addBodyPart(plain);
|
if ("encrypted.asc".equals(attachment.name) || "signature.asc".equals(attachment.name))
|
||||||
alternative.addBodyPart(html);
|
attachments.remove(attachment);
|
||||||
|
|
||||||
|
// Build message
|
||||||
Properties props = MessageHelper.getSessionProperties(Helper.AUTH_TYPE_PASSWORD, false);
|
Properties props = MessageHelper.getSessionProperties(Helper.AUTH_TYPE_PASSWORD, false);
|
||||||
Session isession = Session.getInstance(props, null);
|
Session isession = Session.getInstance(props, null);
|
||||||
MimeMessage imessage = new MimeMessage(isession);
|
MimeMessage imessage = new MimeMessage(isession);
|
||||||
imessage.setContent(alternative);
|
MessageHelper.build(context, message, attachments, imessage);
|
||||||
|
|
||||||
|
// Serialize message
|
||||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
imessage.writeTo(os);
|
imessage.writeTo(os);
|
||||||
ByteArrayInputStream decrypted = new ByteArrayInputStream(os.toByteArray());
|
ByteArrayInputStream decrypted = new ByteArrayInputStream(os.toByteArray());
|
||||||
ByteArrayOutputStream encrypted = new ByteArrayOutputStream();
|
ByteArrayOutputStream encrypted = new ByteArrayOutputStream();
|
||||||
|
|
||||||
if (!pgpService.isBound())
|
// Encrypt message
|
||||||
throw new IllegalArgumentException(getString(R.string.title_no_openpgp));
|
OpenPgpApi api = new OpenPgpApi(context, pgpService.getService());
|
||||||
|
|
||||||
OpenPgpApi api = new OpenPgpApi(getContext(), pgpService.getService());
|
|
||||||
Intent result = api.executeApi(data, decrypted, encrypted);
|
Intent result = api.executeApi(data, decrypted, encrypted);
|
||||||
|
|
||||||
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
|
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
|
||||||
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
case OpenPgpApi.RESULT_CODE_SUCCESS:
|
||||||
EntityAttachment attachment1 = new EntityAttachment();
|
// Get public signature
|
||||||
EntityAttachment attachment2 = new EntityAttachment();
|
|
||||||
|
|
||||||
Intent keyRequest = new Intent();
|
Intent keyRequest = new Intent();
|
||||||
keyRequest.setAction(OpenPgpApi.ACTION_DETACHED_SIGN);
|
keyRequest.setAction(OpenPgpApi.ACTION_DETACHED_SIGN);
|
||||||
keyRequest.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, data.getLongExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, -1));
|
keyRequest.putExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, data.getLongExtra(OpenPgpApi.EXTRA_SIGN_KEY_ID, -1));
|
||||||
Intent keyData = api.executeApi(keyRequest, decrypted, null);
|
Intent key = api.executeApi(keyRequest, decrypted, null);
|
||||||
int r = keyData.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
int r = key.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
if (r != OpenPgpApi.RESULT_CODE_SUCCESS) {
|
if (r != OpenPgpApi.RESULT_CODE_SUCCESS) {
|
||||||
OpenPgpError error = keyData.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
|
OpenPgpError error = key.getParcelableExtra(OpenPgpApi.RESULT_ERROR);
|
||||||
throw new IllegalArgumentException(error.getMessage());
|
throw new IllegalArgumentException(error.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] signature = keyData.getByteArrayExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE);
|
// Attach encrypted data
|
||||||
|
|
||||||
DB db = DB.getInstance(context);
|
|
||||||
try {
|
try {
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
|
|
||||||
|
// Delete previously encrypted data
|
||||||
for (EntityAttachment attachment : db.attachment().getAttachments(id))
|
for (EntityAttachment attachment : db.attachment().getAttachments(id))
|
||||||
if ("encrypted.asc".equals(attachment.name) || "signature.asc".equals(attachment.name))
|
if ("encrypted.asc".equals(attachment.name) || "signature.asc".equals(attachment.name))
|
||||||
db.attachment().deleteAttachment(attachment.id);
|
db.attachment().deleteAttachment(attachment.id);
|
||||||
|
|
||||||
int seq = db.attachment().getAttachmentSequence(id);
|
int seq = db.attachment().getAttachmentSequence(id);
|
||||||
|
|
||||||
|
EntityAttachment attachment1 = new EntityAttachment();
|
||||||
attachment1.message = id;
|
attachment1.message = id;
|
||||||
attachment1.sequence = seq + 1;
|
attachment1.sequence = seq + 1;
|
||||||
attachment1.name = "encrypted.asc";
|
attachment1.name = "encrypted.asc";
|
||||||
|
@ -594,11 +586,11 @@ public class FragmentCompose extends FragmentEx {
|
||||||
|
|
||||||
OutputStream os1 = null;
|
OutputStream os1 = null;
|
||||||
try {
|
try {
|
||||||
|
byte[] bytes1 = encrypted.toByteArray();
|
||||||
os1 = new BufferedOutputStream(new FileOutputStream(file1));
|
os1 = new BufferedOutputStream(new FileOutputStream(file1));
|
||||||
byte[] bytes = encrypted.toByteArray();
|
os1.write(bytes1);
|
||||||
os1.write(bytes);
|
|
||||||
|
|
||||||
attachment1.size = bytes.length;
|
attachment1.size = bytes1.length;
|
||||||
attachment1.progress = null;
|
attachment1.progress = null;
|
||||||
attachment1.available = true;
|
attachment1.available = true;
|
||||||
db.attachment().updateAttachment(attachment1);
|
db.attachment().updateAttachment(attachment1);
|
||||||
|
@ -607,6 +599,7 @@ public class FragmentCompose extends FragmentEx {
|
||||||
os1.close();
|
os1.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EntityAttachment attachment2 = new EntityAttachment();
|
||||||
attachment2.message = id;
|
attachment2.message = id;
|
||||||
attachment2.sequence = seq + 2;
|
attachment2.sequence = seq + 2;
|
||||||
attachment2.name = "signature.asc";
|
attachment2.name = "signature.asc";
|
||||||
|
@ -617,10 +610,11 @@ public class FragmentCompose extends FragmentEx {
|
||||||
|
|
||||||
OutputStream os2 = null;
|
OutputStream os2 = null;
|
||||||
try {
|
try {
|
||||||
|
byte[] bytes2 = key.getByteArrayExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE);
|
||||||
os2 = new BufferedOutputStream(new FileOutputStream(file2));
|
os2 = new BufferedOutputStream(new FileOutputStream(file2));
|
||||||
os2.write(signature);
|
os2.write(bytes2);
|
||||||
|
|
||||||
attachment2.size = signature.length;
|
attachment2.size = bytes2.length;
|
||||||
attachment2.progress = null;
|
attachment2.progress = null;
|
||||||
attachment2.available = true;
|
attachment2.available = true;
|
||||||
db.attachment().updateAttachment(attachment2);
|
db.attachment().updateAttachment(attachment2);
|
||||||
|
|
|
@ -254,6 +254,12 @@ public class MessageHelper {
|
||||||
return imessage;
|
return imessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
build(context, message, attachments, imessage);
|
||||||
|
|
||||||
|
return imessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void build(Context context, EntityMessage message, List<EntityAttachment> attachments, MimeMessage imessage) throws IOException, MessagingException {
|
||||||
String body = message.read(context);
|
String body = message.read(context);
|
||||||
|
|
||||||
BodyPart plain = new MimeBodyPart();
|
BodyPart plain = new MimeBodyPart();
|
||||||
|
@ -302,8 +308,6 @@ public class MessageHelper {
|
||||||
|
|
||||||
imessage.setContent(multipart);
|
imessage.setContent(multipart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return imessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageHelper(MimeMessage message) {
|
MessageHelper(MimeMessage message) {
|
||||||
|
|
Loading…
Reference in New Issue