Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Encrypt backed up messages #780

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ dependencies {
compile 'com.firebase:firebase-jobdispatcher:0.8.5'
compile 'com.android.support:support-annotations:25.3.1'
compile 'com.android.support:preference-v7:25.3.1'
compile 'org.sufficientlysecure:openpgp-api:12.0'

testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.6.1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ public void onCreate(Bundle bundle) {
if (bundle == null) {
showFragment(new MainSettings(), null);
}

if (preferences.shouldShowAboutDialog()) {
showDialog(ABOUT);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.zegoggles.smssync.activity.fragments;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
Expand Down Expand Up @@ -47,8 +48,13 @@
import static com.zegoggles.smssync.preferences.Preferences.Keys.IMAP_SETTINGS;
import static com.zegoggles.smssync.preferences.Preferences.Keys.MAX_ITEMS_PER_RESTORE;
import static com.zegoggles.smssync.preferences.Preferences.Keys.MAX_ITEMS_PER_SYNC;
import static com.zegoggles.smssync.preferences.Preferences.Keys.ENCRYPTION_PROVIDER;
import static com.zegoggles.smssync.preferences.Preferences.Keys.ENCRYPTION_KEYS;
import static com.zegoggles.smssync.utils.ListPreferenceHelper.initListPreference;

import org.openintents.openpgp.util.OpenPgpAppPreference;
import org.openintents.openpgp.util.OpenPgpKeyPreference;

public class AdvancedSettings extends SMSBackupPreferenceFragment {

public static class Main extends AdvancedSettings {
Expand All @@ -59,6 +65,67 @@ public void onResume() {
}
}

public static class Encryption extends AdvancedSettings {
private OpenPgpAppPreference pgp_prov;
private OpenPgpKeyPreference pgp_keys;

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
pgp_prov = (OpenPgpAppPreference) findPreference(ENCRYPTION_PROVIDER.key);
pgp_keys = (OpenPgpKeyPreference) findPreference(ENCRYPTION_KEYS.key);
}

@Override
public void onResume() {
super.onResume();
updateEncryption(null);
findPreference(ENCRYPTION_PROVIDER.key)
.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
updateEncryption(newValue.toString());
return true;
}
});
}

@Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (pgp_keys.handleOnActivityResult(requestCode, resultCode, data)) {
// handled by OpenPgpKeyPreference
return;
}
}

private void updateEncryption(String new_prov) {
boolean enableOtherOptions;

if (new_prov == null) { //we aren't given a new value, load the old one
new_prov = pgp_prov.getValue();
}

if(!new_prov.isEmpty()) {
String prov_simplename = pgp_prov.getEntryByValue(new_prov);
if (prov_simplename == null) {
pgp_prov.setSummary(getString(R.string.ui_encryption_missingprov));
enableOtherOptions = false;
} else {
pgp_prov.setSummary(getString(R.string.ui_encryption_prov) + prov_simplename);
pgp_keys.setOpenPgpProvider(new_prov);
enableOtherOptions = true;
}
} else {
pgp_prov.setSummary(getString(R.string.ui_encryption_noprov));
enableOtherOptions = false;
}

//find other options and set enabled to enableOtherOptions
pgp_keys.setEnabled(enableOtherOptions);
return;
}
}

public static class Backup extends AdvancedSettings {
private static final int REQUEST_CALL_LOG_PERMISSIONS = 0;
private CheckBoxPreference callLogPreference;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
import static com.zegoggles.smssync.App.LOCAL_LOGV;
import static com.zegoggles.smssync.App.TAG;

import org.openintents.openpgp.util.OpenPgpServiceConnection;

public class MessageConverter {
private final Context context;
private final ThreadHelper threadHelper = new ThreadHelper();
Expand All @@ -61,7 +63,8 @@ public MessageConverter(Context context,
Preferences preferences,
String userEmail,
PersonLookup personLookup,
ContactAccessor contactAccessor) {
ContactAccessor contactAccessor,
OpenPgpServiceConnection serviceConnection) {
this.context = context;
markAsReadType = preferences.getMarkAsReadType();
this.personLookup = personLookup;
Expand All @@ -84,9 +87,11 @@ public MessageConverter(Context context,
this.personLookup,
preferences.getMailSubjectPrefix(),
allowedIds,

new MmsSupport(this.context.getContentResolver(), this.personLookup),
preferences.getCallLogType(),
preferences.getDataTypePreferences());
preferences.getDataTypePreferences(),
serviceConnection);
}

private boolean markAsSeen(DataType dataType, Map<String, String> msgMap) {
Expand Down
43 changes: 41 additions & 2 deletions app/src/main/java/com/zegoggles/smssync/mail/MessageGenerator.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.zegoggles.smssync.mail;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.CallLog;
import android.provider.Telephony;
Expand All @@ -20,7 +21,12 @@
import com.zegoggles.smssync.preferences.AddressStyle;
import com.zegoggles.smssync.preferences.CallLogTypes;
import com.zegoggles.smssync.preferences.DataTypePreferences;
import com.zegoggles.smssync.preferences.Preferences;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
Expand All @@ -30,6 +36,9 @@
import static com.zegoggles.smssync.App.TAG;
import static com.zegoggles.smssync.Consts.MMS_PART;

import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpServiceConnection;

class MessageGenerator {
private static final String ERROR_PARSING_DATE = "error parsing date";
private final Context context;
Expand All @@ -43,6 +52,8 @@ class MessageGenerator {
private final MmsSupport mmsSupport;
private final CallLogTypes callLogTypes;
private final DataTypePreferences dataTypePreferences;
private final OpenPgpServiceConnection mServiceConnection;
private final Preferences preferences;

MessageGenerator(Context context,
Address userAddress,
Expand All @@ -53,7 +64,8 @@ class MessageGenerator {
@Nullable ContactGroupIds contactsToBackup,
MmsSupport mmsSupport,
CallLogTypes callLogTypes,
DataTypePreferences dataTypePreferences) {
DataTypePreferences dataTypePreferences,
OpenPgpServiceConnection serviceConnection) {
this.headerGenerator = headerGenerator;
this.userAddress = userAddress;
this.addressStyle = addressStyle;
Expand All @@ -63,8 +75,11 @@ class MessageGenerator {
this.contactGroupIds = contactsToBackup;
this.callFormatter = new CallFormatter(this.context.getResources());
this.mmsSupport = mmsSupport;
// this looks like it should be changed to comply with new style
this.preferences = new Preferences(this.context);
this.dataTypePreferences = dataTypePreferences;
this.callLogTypes = callLogTypes;
this.mServiceConnection = serviceConnection;
}

public @Nullable Message messageForDataType(Map<String, String> msgMap, DataType dataType) throws MessagingException {
Expand All @@ -85,7 +100,31 @@ class MessageGenerator {

final Message msg = new MimeMessage();
msg.setSubject(getSubject(DataType.SMS, record));
setBody(msg, new TextBody(msgMap.get(Telephony.TextBasedSmsColumns.BODY)));

String msgTxt = msgMap.get(Telephony.TextBasedSmsColumns.BODY);

if (mServiceConnection != null) {
Intent data = new Intent();
ByteArrayOutputStream os;
InputStream is;
data.setAction(OpenPgpApi.ACTION_ENCRYPT);
data.putExtra(OpenPgpApi.EXTRA_KEY_IDS, preferences.getEncryptionKeyID());
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
try {
is = new ByteArrayInputStream(msgTxt.getBytes("UTF-8"));
os = new ByteArrayOutputStream();
OpenPgpApi api = new OpenPgpApi(this.context, mServiceConnection.getService());
Intent result = api.executeApi(data, is, os);
switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
case OpenPgpApi.RESULT_CODE_SUCCESS: {
msgTxt = os.toString("UTF-8");
break;
}
}
} catch (UnsupportedEncodingException e) {}
}

setBody(msg, new TextBody(msgTxt));

final int messageType = toInt(msgMap.get(Telephony.TextBasedSmsColumns.TYPE));
if (Telephony.TextBasedSmsColumns.MESSAGE_TYPE_INBOX == messageType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.support.annotation.StyleRes;
import android.util.Log;
import com.zegoggles.smssync.App;
Expand All @@ -38,6 +39,8 @@
import static com.zegoggles.smssync.preferences.Preferences.Keys.CONFIRM_ACTION;
import static com.zegoggles.smssync.preferences.Preferences.Keys.DARK_THEME;
import static com.zegoggles.smssync.preferences.Preferences.Keys.ENABLE_AUTO_BACKUP;
import static com.zegoggles.smssync.preferences.Preferences.Keys.ENCRYPTION_PROVIDER;
import static com.zegoggles.smssync.preferences.Preferences.Keys.ENCRYPTION_KEYS;
import static com.zegoggles.smssync.preferences.Preferences.Keys.FIRST_USE;
import static com.zegoggles.smssync.preferences.Preferences.Keys.INCOMING_TIMEOUT_SECONDS;
import static com.zegoggles.smssync.preferences.Preferences.Keys.LAST_VERSION_CODE;
Expand Down Expand Up @@ -86,6 +89,8 @@ public enum Keys {
WIFI_ONLY("wifi_only"),
REFERENCE_UID("reference_uid"),
MAIL_SUBJECT_PREFIX("mail_subject_prefix"),
ENCRYPTION_PROVIDER("openpgp_provider_list"),
ENCRYPTION_KEYS("pgp_keys"),
RESTORE_STARRED_ONLY("restore_starred_only"),
MARK_AS_READ_TYPES("mark_as_read_types"),
MARK_AS_READ_ON_RESTORE("mark_as_read_on_restore"),
Expand Down Expand Up @@ -226,6 +231,26 @@ public boolean isFirstBackup() {
return true;
}

public String getEncryptionProvider() {
return preferences.getString(ENCRYPTION_PROVIDER.key, "");
}

public long[] getEncryptionKeyID() {
long[] retval = new long[1];
retval[0] = preferences.getLong(ENCRYPTION_KEYS.key, 0);
return retval;
}

public boolean isEncryptionAvailable() {
if (TextUtils.isEmpty(getEncryptionProvider()))
return false;

if (getEncryptionKeyID()[0] == 0)
return false;

return true;
}

public boolean isFirstUse() {
if (isFirstBackup() && !preferences.contains(FIRST_USE.key)) {
preferences.edit().putBoolean(FIRST_USE.key, false).commit();
Expand Down
23 changes: 21 additions & 2 deletions app/src/main/java/com/zegoggles/smssync/service/BackupTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
import static com.zegoggles.smssync.service.state.SmsSyncState.FINISHED_BACKUP;
import static com.zegoggles.smssync.service.state.SmsSyncState.LOGIN;

import org.openintents.openpgp.util.OpenPgpServiceConnection;

class BackupTask extends AsyncTask<BackupConfig, BackupState, BackupState> {
private final SmsBackupService service;
private final BackupItemsFetcher fetcher;
Expand All @@ -55,6 +57,7 @@ class BackupTask extends AsyncTask<BackupConfig, BackupState, BackupState> {
private final Preferences preferences;
private final ContactAccessor contactAccessor;
private final TokenRefresher tokenRefresher;
private final OpenPgpServiceConnection mServiceConnection;

BackupTask(@NonNull SmsBackupService service) {
final Context context = service.getApplicationContext();
Expand All @@ -68,8 +71,16 @@ class BackupTask extends AsyncTask<BackupConfig, BackupState, BackupState> {

PersonLookup personLookup = new PersonLookup(service.getContentResolver());

// bind to pgp service
if (preferences.isEncryptionAvailable()) {
this.mServiceConnection = new OpenPgpServiceConnection(context, preferences.getEncryptionProvider());
this.mServiceConnection.bindToService();
} else {
this.mServiceConnection = null;
}

this.contactAccessor = new ContactAccessor();
this.converter = new MessageConverter(context, service.getPreferences(), authPreferences.getUserEmail(), personLookup, contactAccessor);
this.converter = new MessageConverter(context, service.getPreferences(), authPreferences.getUserEmail(), personLookup, contactAccessor, this.mServiceConnection);

if (preferences.isCallLogCalendarSyncEnabled()) {
calendarSyncer = new CalendarSyncer(
Expand All @@ -92,7 +103,8 @@ class BackupTask extends AsyncTask<BackupConfig, BackupState, BackupState> {
AuthPreferences authPreferences,
Preferences preferences,
ContactAccessor accessor,
TokenRefresher refresher) {
TokenRefresher refresher,
OpenPgpServiceConnection serviceConnection) {
this.service = service;
this.fetcher = fetcher;
this.converter = messageConverter;
Expand All @@ -101,6 +113,7 @@ class BackupTask extends AsyncTask<BackupConfig, BackupState, BackupState> {
this.preferences = preferences;
this.contactAccessor = accessor;
this.tokenRefresher = refresher;
this.mServiceConnection = serviceConnection;
}

@Override
Expand Down Expand Up @@ -236,6 +249,9 @@ protected void onProgressUpdate(BackupState... progress) {

@Override
protected void onPostExecute(BackupState result) {
if (this.mServiceConnection != null) {
this.mServiceConnection.unbindFromService();
}
if (result != null) {
post(result);
}
Expand All @@ -244,6 +260,9 @@ protected void onPostExecute(BackupState result) {

@Override
protected void onCancelled() {
if (this.mServiceConnection != null) {
this.mServiceConnection.unbindFromService();
}
post(transition(CANCELED_BACKUP, null));
App.unregister(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ protected void handleIntent(final Intent intent) {
getPreferences(),
getAuthPreferences().getUserEmail(),
new PersonLookup(getContentResolver()),
new ContactAccessor()
new ContactAccessor(),
null
);

RestoreConfig config = new RestoreConfig(
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,15 @@
<string name="ui_dialog_account_manager_token_error">Could not get token from system. Do you want to try the browser authentication method?</string>
<string name="select_google_account">Select a Google account</string>

<!-- encryption strings -->
<string name="ui_encryption_title">Encryption</string>
<string name="ui_encryption_desc">Encrypt backed up messages.</string>
<string name="ui_encryption_selectprov">Select OpenPGP Provider</string>
<string name="ui_encryption_noprov">No provider selected.</string>
<string name="ui_encryption_prov">PGP provider:\u0020</string>
<string name="ui_encryption_missingprov">Your chosen PGP provider does not appear to be installed.</string>
<string name="ui_encryption_selkeys">Select Keys</string>

<!-- donation related -->
<string name="donate">Donate</string>
<string name="donate_summary">Using secure Google Play Store in-app payment.</string>
Expand Down
Loading