From 1ef6f883e34a08dc916ad7dfabd7f892964aff54 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Mon, 27 Jul 2015 14:10:26 +0530 Subject: introduced keyserver sync adapter --- OpenKeychain/src/main/AndroidManifest.xml | 14 ++ .../org/sufficientlysecure/keychain/Constants.java | 5 + .../keychain/keyimport/HkpKeyserver.java | 6 +- .../keychain/operations/ImportOperation.java | 37 +++- .../keychain/provider/KeychainContract.java | 17 ++ .../keychain/provider/KeychainDatabase.java | 18 +- .../keychain/provider/KeychainProvider.java | 37 ++++ .../keychain/provider/ProviderHelper.java | 71 +++++++ .../service/KeyserverSyncAdapterService.java | 234 +++++++++++++++++++++ .../keychain/service/PassphraseCacheService.java | 4 +- .../keychain/ui/DeleteKeyDialogActivity.java | 1 - .../keychain/ui/KeyListFragment.java | 24 ++- OpenKeychain/src/main/res/values/strings.xml | 6 + .../main/res/xml/keyserver_sync_adapter_desc.xml | 8 + 14 files changed, 456 insertions(+), 26 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java create mode 100644 OpenKeychain/src/main/res/xml/keyserver_sync_adapter_desc.xml (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index dae34ff3a..d3047decc 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -800,6 +800,20 @@ android:resource="@xml/custom_pgp_contacts_structure" /> + + + + + + + + { } if (!result.success()) { badKeys += 1; - } else if (result.updated()) { - updatedKeys += 1; - importedMasterKeyIds.add(key.getMasterKeyId()); } else { - newKeys += 1; - if (key.isSecret()) { - secret += 1; + if (result.updated()) { + updatedKeys += 1; + importedMasterKeyIds.add(key.getMasterKeyId()); + } else { + newKeys += 1; + if (key.isSecret()) { + secret += 1; + } + importedMasterKeyIds.add(key.getMasterKeyId()); + } + if (entry.mBytes == null) { + // synonymous to isDownloadFromKeyserver. + // If no byte data was supplied, import from keyserver took place + // this prevents file imports being noted as keyserver imports + mProviderHelper.renewKeyLastUpdatedTime(key.getMasterKeyId(), + GregorianCalendar.getInstance().getTimeInMillis(), + TimeUnit.MILLISECONDS); } - importedMasterKeyIds.add(key.getMasterKeyId()); } log.add(result, 2); @@ -386,7 +397,7 @@ public class ImportOperation extends BaseOperation { @NonNull @Override - public OperationResult execute(ImportKeyringParcel importInput, CryptoInputParcel cryptoInput) { + public ImportKeyResult execute(ImportKeyringParcel importInput, CryptoInputParcel cryptoInput) { ArrayList keyList = importInput.mKeyList; String keyServer = importInput.mKeyserver; @@ -497,7 +508,7 @@ public class ImportOperation extends BaseOperation { Progressable mProgressable; private int mTotalKeys; private int mImportedKeys = 0; - ArrayList mImportedMasterKeyIds = new ArrayList(); + ArrayList mImportedMasterKeyIds = new ArrayList<>(); private int mBadKeys = 0; private int mNewKeys = 0; private int mUpdatedKeys = 0; @@ -515,7 +526,9 @@ public class ImportOperation extends BaseOperation { public KeyImportAccumulator(int totalKeys, Progressable externalProgressable) { mTotalKeys = totalKeys; mProgressable = externalProgressable; - mProgressable.setProgress(0, totalKeys); + if (mProgressable != null) { + mProgressable.setProgress(0, totalKeys); + } } public int getTotalKeys() { @@ -529,7 +542,9 @@ public class ImportOperation extends BaseOperation { public synchronized void accumulateKeyImport(ImportKeyResult result) { mImportedKeys++; - mProgressable.setProgress(mImportedKeys, mTotalKeys); + if (mProgressable != null) { + mProgressable.setProgress(mImportedKeys, mTotalKeys); + } mImportLog.addAll(result.getLog().toList());//accumulates log mBadKeys += result.mBadKeys; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index 0d9a4ac16..73a687efe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -51,6 +51,11 @@ public class KeychainContract { String EXPIRY = "expiry"; } + interface UpdatedKeysColumns { + String MASTER_KEY_ID = "master_key_id"; // not a database id + String LAST_UPDATED = "last_updated"; // time since epoch in seconds + } + interface UserPacketsColumns { String MASTER_KEY_ID = "master_key_id"; // foreign key to key_rings._ID String TYPE = "type"; // not a database id @@ -97,6 +102,8 @@ public class KeychainContract { public static final String BASE_KEY_RINGS = "key_rings"; + public static final String BASE_UPDATED_KEYS = "updated_keys"; + public static final String PATH_UNIFIED = "unified"; public static final String PATH_FIND = "find"; @@ -234,6 +241,16 @@ public class KeychainContract { } + public static class UpdatedKeys implements UpdatedKeysColumns, BaseColumns { + public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() + .appendPath(BASE_UPDATED_KEYS).build(); + + public static final String CONTENT_TYPE + = "vnd.android.cursor.dir/vnd.org.sufficientlysecure.keychain.provider.updated_keys"; + public static final String CONTENT_ITEM_TYPE + = "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.provider.updated_keys"; + } + public static class UserPackets implements UserPacketsColumns, BaseColumns { public static final String VERIFIED = "verified"; public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index 4d16d44c5..d7fb738fc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -34,6 +34,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.CertsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns; +import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeysColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPacketsColumns; import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity; import org.sufficientlysecure.keychain.util.Log; @@ -53,7 +54,7 @@ import java.io.IOException; */ public class KeychainDatabase extends SQLiteOpenHelper { private static final String DATABASE_NAME = "openkeychain.db"; - private static final int DATABASE_VERSION = 11; + private static final int DATABASE_VERSION = 12; static Boolean apgHack = false; private Context mContext; @@ -61,6 +62,7 @@ public class KeychainDatabase extends SQLiteOpenHelper { String KEY_RINGS_PUBLIC = "keyrings_public"; String KEY_RINGS_SECRET = "keyrings_secret"; String KEYS = "keys"; + String UPDATED_KEYS = "updated_keys"; String USER_PACKETS = "user_packets"; String CERTS = "certs"; String API_APPS = "api_apps"; @@ -144,6 +146,14 @@ public class KeychainDatabase extends SQLiteOpenHelper { + Tables.USER_PACKETS + "(" + UserPacketsColumns.MASTER_KEY_ID + ", " + UserPacketsColumns.RANK + ") ON DELETE CASCADE" + ")"; + private static final String CREATE_UPDATE_KEYS = + "CREATE TABLE IF NOT EXISTS " + Tables.UPDATED_KEYS + " (" + + UpdatedKeysColumns.MASTER_KEY_ID + " INTEGER PRIMARY KEY, " + + UpdatedKeysColumns.LAST_UPDATED + " INTEGER, " + + "FOREIGN KEY(" + UpdatedKeysColumns.MASTER_KEY_ID + ") REFERENCES " + + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE" + + ")"; + private static final String CREATE_API_APPS = "CREATE TABLE IF NOT EXISTS " + Tables.API_APPS + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " @@ -206,6 +216,7 @@ public class KeychainDatabase extends SQLiteOpenHelper { db.execSQL(CREATE_KEYS); db.execSQL(CREATE_USER_PACKETS); db.execSQL(CREATE_CERTS); + db.execSQL(CREATE_UPDATE_KEYS); db.execSQL(CREATE_API_APPS); db.execSQL(CREATE_API_APPS_ACCOUNTS); db.execSQL(CREATE_API_APPS_ALLOWED_KEYS); @@ -278,8 +289,11 @@ public class KeychainDatabase extends SQLiteOpenHelper { // fix problems in database, see #1402 for details // https://github.com/open-keychain/open-keychain/issues/1402 db.execSQL("DELETE FROM api_accounts WHERE key_id BETWEEN 0 AND 3"); + case 12: + db.execSQL(CREATE_UPDATE_KEYS); if (oldVersion == 10) { - // no consolidate if we are updating from 10, we're just here for the api_accounts fix + // no consolidate if we are updating from 10, we're just here for + // the api_accounts fix and the new update keys table return; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 3ed9b1da9..178199805 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; +import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPacketsColumns; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; @@ -72,6 +73,9 @@ public class KeychainProvider extends ContentProvider { private static final int KEY_RINGS_FIND_BY_EMAIL = 400; private static final int KEY_RINGS_FIND_BY_SUBKEY = 401; + private static final int UPDATED_KEYS = 500; + private static final int UPDATED_KEYS_SPECIFIC = 501; + protected UriMatcher mUriMatcher; /** @@ -179,6 +183,12 @@ public class KeychainProvider extends ContentProvider { matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/" + KeychainContract.PATH_ALLOWED_KEYS, API_ALLOWED_KEYS); + /** + * to access table containing last updated dates of keys + */ + matcher.addURI(authority, KeychainContract.BASE_UPDATED_KEYS, UPDATED_KEYS); + matcher.addURI(authority, KeychainContract.BASE_UPDATED_KEYS + "/*", UPDATED_KEYS_SPECIFIC); + return matcher; } @@ -218,6 +228,11 @@ public class KeychainProvider extends ContentProvider { case KEY_RING_SECRET: return KeyRings.CONTENT_ITEM_TYPE; + case UPDATED_KEYS: + return UpdatedKeys.CONTENT_TYPE; + case UPDATED_KEYS_SPECIFIC: + return UpdatedKeys.CONTENT_ITEM_TYPE; + case API_APPS: return ApiApps.CONTENT_TYPE; @@ -606,6 +621,22 @@ public class KeychainProvider extends ContentProvider { break; } + case UPDATED_KEYS: + case UPDATED_KEYS_SPECIFIC: { + HashMap projectionMap = new HashMap<>(); + qb.setTables(Tables.UPDATED_KEYS); + projectionMap.put(UpdatedKeys.MASTER_KEY_ID, Tables.UPDATED_KEYS + "." + + UpdatedKeys.MASTER_KEY_ID); + projectionMap.put(UpdatedKeys.LAST_UPDATED, Tables.UPDATED_KEYS + "." + + UpdatedKeys.LAST_UPDATED); + qb.setProjectionMap(projectionMap); + if (match == UPDATED_KEYS_SPECIFIC) { + qb.appendWhere(UpdatedKeys.MASTER_KEY_ID + " = "); + qb.appendWhereEscapeString(uri.getPathSegments().get(1)); + } + break; + } + case API_APPS: { qb.setTables(Tables.API_APPS); @@ -726,6 +757,12 @@ public class KeychainProvider extends ContentProvider { keyId = values.getAsLong(Certs.MASTER_KEY_ID); break; } + case UPDATED_KEYS: { + long updatedKeyId = db.replace(Tables.UPDATED_KEYS, null, values); + rowUri = UpdatedKeys.CONTENT_URI.buildUpon().appendPath("" + updatedKeyId) + .build(); + break; + } case API_APPS: { db.insertOrThrow(Tables.API_APPS, null, values); break; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 0c37bfc2a..e8eea6831 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -59,6 +59,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; +import org.sufficientlysecure.keychain.provider.KeychainContract.UpdatedKeys; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.remote.AppSettings; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -82,6 +83,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.concurrent.TimeUnit; /** * This class contains high level methods for database access. Despite its @@ -685,6 +687,41 @@ public class ProviderHelper { mIndent -= 1; } + // before deleting key, retrieve it's last updated time + final int INDEX_MASTER_KEY_ID = 0; + final int INDEX_LAST_UPDATED = 1; + Cursor lastUpdatedCursor = mContentResolver.query( + UpdatedKeys.CONTENT_URI, + new String[]{ + UpdatedKeys.MASTER_KEY_ID, + UpdatedKeys.LAST_UPDATED + }, + UpdatedKeys.MASTER_KEY_ID + " = ?", + new String[]{"" + masterKeyId}, + null + ); + ContentValues lastUpdatedEntry = null; + if (lastUpdatedCursor.moveToNext()) { + lastUpdatedEntry = new ContentValues(2); + lastUpdatedEntry.put(UpdatedKeys.MASTER_KEY_ID, + lastUpdatedCursor.getLong(INDEX_MASTER_KEY_ID)); + lastUpdatedEntry.put(UpdatedKeys.LAST_UPDATED, + lastUpdatedCursor.getLong(INDEX_LAST_UPDATED)); + Log.e("PHILIP", "cv: " + lastUpdatedEntry + " actual: " + masterKeyId); + } + lastUpdatedCursor.close(); + + if (lastUpdatedEntry != null) { + // there was an entry to re-insert + // this operation must happen after the new key is inserted + operations.add( + ContentProviderOperation + .newInsert(UpdatedKeys.CONTENT_URI) + .withValues(lastUpdatedEntry) + .build() + ); + } + try { // delete old version of this keyRing, which also deletes all keys and userIds on cascade int deleted = mContentResolver.delete( @@ -1239,6 +1276,28 @@ public class ProviderHelper { } // 2. wipe database (IT'S DANGEROUS) + + // first, backup our list of updated key times + ArrayList updatedKeysValues = new ArrayList<>(); + final int INDEX_MASTER_KEY_ID = 0; + final int INDEX_LAST_UPDATED = 1; + Cursor lastUpdatedCursor = mContentResolver.query( + UpdatedKeys.CONTENT_URI, + new String[]{ + UpdatedKeys.MASTER_KEY_ID, + UpdatedKeys.LAST_UPDATED + }, + null, null, null); + while (lastUpdatedCursor.moveToNext()) { + ContentValues values = new ContentValues(); + values.put(UpdatedKeys.MASTER_KEY_ID, + lastUpdatedCursor.getLong(INDEX_MASTER_KEY_ID)); + values.put(UpdatedKeys.LAST_UPDATED, + lastUpdatedCursor.getLong(INDEX_LAST_UPDATED)); + updatedKeysValues.add(values); + } + lastUpdatedCursor.close(); + log.add(LogType.MSG_CON_DB_CLEAR, indent); mContentResolver.delete(KeyRings.buildUnifiedKeyRingsUri(), null, null); @@ -1288,6 +1347,10 @@ public class ProviderHelper { new ProgressFixedScaler(progress, 25, 99, 100, R.string.progress_con_reimport)) .serialKeyRingImport(itPublics, numPublics, null, null); log.add(result, indent); + // re-insert our backed up list of updated key times + // TODO: can this cause issues in case a public key re-import failed? + mContentResolver.bulkInsert(UpdatedKeys.CONTENT_URI, + updatedKeysValues.toArray(new ContentValues[updatedKeysValues.size()])); } else { log.add(LogType.MSG_CON_REIMPORT_PUBLIC_SKIP, indent); } @@ -1397,6 +1460,14 @@ public class ProviderHelper { return getKeyRingAsArmoredString(data); } + public Uri renewKeyLastUpdatedTime(long masterKeyId, long time, TimeUnit timeUnit) { + ContentValues values = new ContentValues(); + values.put(UpdatedKeys.MASTER_KEY_ID, masterKeyId); + values.put(UpdatedKeys.LAST_UPDATED, timeUnit.toSeconds(time)); + + return mContentResolver.insert(UpdatedKeys.CONTENT_URI, values); + } + public ArrayList getRegisteredApiApps() { Cursor cursor = mContentResolver.query(ApiApps.CONTENT_URI, null, null, null, null); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java new file mode 100644 index 000000000..4a7e2942e --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java @@ -0,0 +1,234 @@ +package org.sufficientlysecure.keychain.service; + +import android.accounts.Account; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.AbstractThreadedSyncAdapter; +import android.content.ContentProviderClient; +import android.content.Context; +import android.content.Intent; +import android.content.SyncResult; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.os.IBinder; +import android.support.v4.app.NotificationCompat; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.ImportOperation; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.ui.MainActivity; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ParcelableProxy; +import org.sufficientlysecure.keychain.util.Preferences; + +import java.util.ArrayList; +import java.util.GregorianCalendar; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +public class KeyserverSyncAdapterService extends Service { + + private static final String ACTION_IGNORE_TOR = "ignore_tor"; + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.e("PHILIP", "Sync adapter service starting"); + switch (intent.getAction()) { + case ACTION_IGNORE_TOR: { + updateKeysFromKeyserver(this, + new CryptoInputParcel(ParcelableProxy.getForNoProxy())); + break; + } + } + // TODO: correct flag? + return START_NOT_STICKY; + } + + private static AtomicBoolean sCancelled = new AtomicBoolean(false); + + private class KeyserverSyncAdapter extends AbstractThreadedSyncAdapter { + + public KeyserverSyncAdapter() { + super(KeyserverSyncAdapterService.this, true); + } + + @Override + public void onPerformSync(Account account, Bundle extras, String authority, + ContentProviderClient provider, SyncResult syncResult) { + Log.d(Constants.TAG, "Performing a keyserver sync!"); + + updateKeysFromKeyserver(KeyserverSyncAdapterService.this, new CryptoInputParcel()); + } + } + + @Override + public IBinder onBind(Intent intent) { + return new KeyserverSyncAdapter().getSyncAdapterBinder(); + } + + public static void updateKeysFromKeyserver(Context context, + CryptoInputParcel cryptoInputParcel) { + /** + * 1. Get keys which have been updated recently and therefore do not need to + * be updated now + * 2. Get list of all keys and filter out ones that don't need to be updated + * 3. Update the remaining keys. + * At any time, if the operation is to be cancelled, the sCancelled AtomicBoolean may be set + */ + + // 1. Get keys which have been updated recently and don't need to updated now + final int INDEX_UPDATED_KEYS_MASTER_KEY_ID = 0; + final int INDEX_LAST_UPDATED = 1; + + final long TIME_DAY = TimeUnit.DAYS.toSeconds(1); + final long CURRENT_TIME = GregorianCalendar.getInstance().get(GregorianCalendar.SECOND); + Log.e("PHILIP", "day: " + TIME_DAY); + Cursor updatedKeysCursor = context.getContentResolver().query( + KeychainContract.UpdatedKeys.CONTENT_URI, + new String[]{ + KeychainContract.UpdatedKeys.MASTER_KEY_ID, + KeychainContract.UpdatedKeys.LAST_UPDATED + }, + "? - " + KeychainContract.UpdatedKeys.LAST_UPDATED + " < " + TIME_DAY, + new String[]{"" + CURRENT_TIME}, + null + ); + + ArrayList ignoreMasterKeyIds = new ArrayList<>(); + while (updatedKeysCursor.moveToNext()) { + long masterKeyId = updatedKeysCursor.getLong(INDEX_UPDATED_KEYS_MASTER_KEY_ID); + Log.d(Constants.TAG, "Keyserver sync: {" + masterKeyId + "} last updated at {" + + updatedKeysCursor.getLong(INDEX_LAST_UPDATED) + "}s"); + ignoreMasterKeyIds.add(masterKeyId); + } + updatedKeysCursor.close(); + + // 2. Make a list of public keys which should be updated + final int INDEX_MASTER_KEY_ID = 0; + final int INDEX_FINGERPRINT = 1; + Cursor keyCursor = context.getContentResolver().query( + KeychainContract.KeyRings.buildUnifiedKeyRingsUri(), + new String[]{ + KeychainContract.KeyRings.MASTER_KEY_ID, + KeychainContract.KeyRings.FINGERPRINT + }, + null, + null, + null + ); + + if (keyCursor == null) { + return; + } + + ArrayList keyList = new ArrayList<>(); + while (keyCursor.moveToNext()) { + long keyId = keyCursor.getLong(INDEX_MASTER_KEY_ID); + if (ignoreMasterKeyIds.contains(keyId)) { + continue; + } + String fingerprint = KeyFormattingUtils + .convertFingerprintToHex(keyCursor.getBlob(INDEX_FINGERPRINT)); + String hexKeyId = KeyFormattingUtils + .convertKeyIdToHex(keyId); + // we aren't updating from keybase as of now + keyList.add(new ParcelableKeyRing(fingerprint, hexKeyId, null)); + } + keyCursor.close(); + + if (sCancelled.get()) { + // if we've already been cancelled + return; + } + + // 3. Actually update the keys + Log.e("PHILIP", keyList.toString()); + ImportOperation importOp = new ImportOperation(context, new ProviderHelper(context), null); + ImportKeyResult result = importOp.execute( + new ImportKeyringParcel(keyList, + Preferences.getPreferences(context).getPreferredKeyserver()), + cryptoInputParcel + ); + if (result.isPending()) { + NotificationManager manager = + (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); + manager.notify(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT, + getOrbotNoification(context)); + + Log.d(Constants.TAG, "Keyserver sync failed due to pending result " + + result.getRequiredInputParcel().mType); + } else { + Log.d(Constants.TAG, "Background keyserver sync completed: new " + result.mNewKeys + + " updated " + result.mUpdatedKeys + " bad " + result.mBadKeys); + } + } + + public static void preventAndCancelUpdates() { + // TODO: PHILIP uncomment! + // sCancelled.set(true); + } + + public static void allowUpdates() { + sCancelled.set(false); + } + + private static Notification getOrbotNoification(Context context) { + // TODO: PHILIP work in progress + NotificationCompat.Builder builder = new NotificationCompat.Builder(context); + builder.setSmallIcon(R.drawable.ic_stat_notify_24dp) + .setLargeIcon(getBitmap(R.drawable.ic_launcher, context)) + .setContentTitle(context.getString(R.string.keyserver_sync_orbot_notif_title)) + .setContentText(context.getString(R.string.keyserver_sync_orbot_notif_msg)); + + // In case the user decides to not use tor + Intent ignoreTorIntent = new Intent(context, KeyserverSyncAdapterService.class); + ignoreTorIntent.setAction(ACTION_IGNORE_TOR); + PendingIntent ignoreTorPi = PendingIntent.getService( + context, + Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT, + ignoreTorIntent, + PendingIntent.FLAG_CANCEL_CURRENT + ); + + builder.addAction(R.drawable.abc_ic_clear_mtrl_alpha, + context.getString(R.string.keyserver_sync_orbot_notif_ignore), + ignoreTorPi); + + return builder.build(); + } + + // from de.azapps.mirakel.helper.Helpers from https://github.com/MirakelX/mirakel-android + private static Bitmap getBitmap(int resId, Context context) { + int mLargeIconWidth = (int) context.getResources().getDimension( + android.R.dimen.notification_large_icon_width); + int mLargeIconHeight = (int) context.getResources().getDimension( + android.R.dimen.notification_large_icon_height); + Drawable d; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + // noinspection deprecation (can't help it at this api level) + d = context.getResources().getDrawable(resId); + } else { + d = context.getDrawable(resId); + } + if (d == null) { + return null; + } + Bitmap b = Bitmap.createBitmap(mLargeIconWidth, mLargeIconHeight, Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(b); + d.setBounds(0, 0, mLargeIconWidth, mLargeIconHeight); + d.draw(c); + return b; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index 2a258b7e3..be269c66d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -101,8 +101,6 @@ public class PassphraseCacheService extends Service { private static final long DEFAULT_TTL = 15; - private static final int NOTIFICATION_ID = 1; - private static final int MSG_PASSPHRASE_CACHE_GET_OKAY = 1; private static final int MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND = 2; @@ -477,7 +475,7 @@ public class PassphraseCacheService extends Service { private void updateService() { if (mPassphraseCache.size() > 0) { - startForeground(NOTIFICATION_ID, getNotification()); + startForeground(Constants.Notification.PASSPHRASE_CACHE, getNotification()); } else { // stop whole service if no cached passphrases remaining Log.d(Constants.TAG, "PassphraseCacheService: No passphrases remaining in memory, stopping service!"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java index b22053df1..478259133 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DeleteKeyDialogActivity.java @@ -48,7 +48,6 @@ import org.sufficientlysecure.keychain.service.RevokeKeyringParcel; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; -import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.ThemeChanger; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 8c46876be..4997d3fab 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -25,7 +25,6 @@ import java.util.HashMap; import android.animation.ObjectAnimator; import android.annotation.TargetApi; -import android.app.Activity; import android.content.Context; import android.content.Intent; import android.database.Cursor; @@ -65,15 +64,14 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.ConsolidateInputParcel; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; +import org.sufficientlysecure.keychain.service.KeyserverSyncAdapterService; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.FabContainer; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; @@ -522,7 +520,9 @@ public class KeyListFragment extends LoaderFragment } private void updateAllKeys() { - Activity activity = getActivity(); + // TODO: PHILIP just for testing, remove! + KeyserverSyncAdapterService.updateKeysFromKeyserver(getActivity(), new CryptoInputParcel()); + /*Activity activity = getActivity(); if (activity == null) { return; } @@ -563,7 +563,7 @@ public class KeyListFragment extends LoaderFragment mImportOpHelper = new CryptoOperationHelper<>(1, this, this, R.string.progress_updating); - mImportOpHelper.cryptoOperation(); + mImportOpHelper.cryptoOperation();*/ } private void consolidate() { @@ -647,6 +647,18 @@ public class KeyListFragment extends LoaderFragment } } + @Override + public void onResume() { + super.onResume(); + KeyserverSyncAdapterService.preventAndCancelUpdates(); + } + + @Override + public void onPause() { + super.onPause(); + KeyserverSyncAdapterService.allowUpdates(); + } + @Override public void fabMoveUp(int height) { ObjectAnimator anim = ObjectAnimator.ofFloat(mFab, "translationY", 0, -height); diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 72406aaab..6309faf85 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1351,6 +1351,12 @@ "Clear Passwords" "Password" + + "Orbot not running" + "Keyserver sync failed since Orbot is not running. What would you like to do?" + "Start Orbot" + "Don't use Tor" + "Take back your privacy with OpenKeychain!" "Create my key" diff --git a/OpenKeychain/src/main/res/xml/keyserver_sync_adapter_desc.xml b/OpenKeychain/src/main/res/xml/keyserver_sync_adapter_desc.xml new file mode 100644 index 000000000..76211aaf1 --- /dev/null +++ b/OpenKeychain/src/main/res/xml/keyserver_sync_adapter_desc.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file -- cgit v1.2.3 From 448657602ce5baa5b2a99e26ab2eb2fb8061778f Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Thu, 30 Jul 2015 04:39:38 +0530 Subject: improved orbot notify, added periodic sync --- .../org/sufficientlysecure/keychain/Constants.java | 7 +- .../service/KeyserverSyncAdapterService.java | 88 ++++++++++++++++++++-- .../keychain/ui/MainActivity.java | 19 +++++ OpenKeychain/src/main/res/values/strings.xml | 6 +- .../main/res/xml/keyserver_sync_adapter_desc.xml | 2 +- 5 files changed, 104 insertions(+), 18 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index c66c33453..03d39f6be 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -19,14 +19,9 @@ package org.sufficientlysecure.keychain; import android.os.Environment; -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; import org.spongycastle.jce.provider.BouncyCastleProvider; -import org.sufficientlysecure.keychain.BuildConfig; - import java.io.File; -import java.net.InetSocketAddress; import java.net.Proxy; public final class Constants { @@ -43,7 +38,7 @@ public final class Constants { public static final String ACCOUNT_TYPE = BuildConfig.ACCOUNT_TYPE; public static final String CUSTOM_CONTACT_DATA_MIME_TYPE = "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.key"; - public static final String PROVIDER_AUTHORITY = BuildConfig.APPLICATION_ID + ".provider"; + public static final String PROVIDER_AUTHORITY = BuildConfig.PROVIDER_CONTENT_AUTHORITY; public static final String TEMPSTORAGE_AUTHORITY = BuildConfig.APPLICATION_ID + ".tempstorage"; public static final String CLIPBOARD_LABEL = "Keychain"; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java index 4a7e2942e..a08797e6d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java @@ -16,6 +16,7 @@ import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; import android.support.v4.app.NotificationCompat; @@ -27,7 +28,7 @@ import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -import org.sufficientlysecure.keychain.ui.MainActivity; +import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ParcelableProxy; @@ -41,19 +42,49 @@ import java.util.concurrent.atomic.AtomicBoolean; public class KeyserverSyncAdapterService extends Service { private static final String ACTION_IGNORE_TOR = "ignore_tor"; + private static final String ACTION_DISMISS_NOTIFICATION = "cancel_sync"; + private static final String ACTION_START_ORBOT = "start_orbot"; @Override - public int onStartCommand(Intent intent, int flags, int startId) { + public int onStartCommand(Intent intent, int flags, final int startId) { Log.e("PHILIP", "Sync adapter service starting"); + NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); switch (intent.getAction()) { case ACTION_IGNORE_TOR: { updateKeysFromKeyserver(this, new CryptoInputParcel(ParcelableProxy.getForNoProxy())); + manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT); + stopSelf(startId); + break; + } + case ACTION_START_ORBOT: { + Intent startOrbot = new Intent(this, OrbotRequiredDialogActivity.class); + startOrbot.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startOrbot.setAction(OrbotRequiredDialogActivity.ACTION_START_ORBOT); + startActivity(startOrbot); + new Handler().postDelayed( + new Runnable() { + @Override + public void run() { + updateKeysFromKeyserver(KeyserverSyncAdapterService.this, + new CryptoInputParcel()); + stopSelf(startId); + } + }, + 30000 // shouldn't take longer for orbot to start + ); + + manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT); + break; + } + case ACTION_DISMISS_NOTIFICATION: { + manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT); + stopSelf(startId); break; } } // TODO: correct flag? - return START_NOT_STICKY; + return START_REDELIVER_INTENT; } private static AtomicBoolean sCancelled = new AtomicBoolean(false); @@ -92,16 +123,16 @@ public class KeyserverSyncAdapterService extends Service { final int INDEX_UPDATED_KEYS_MASTER_KEY_ID = 0; final int INDEX_LAST_UPDATED = 1; - final long TIME_DAY = TimeUnit.DAYS.toSeconds(1); + final long TIME_MAX = TimeUnit.DAYS.toSeconds(7); final long CURRENT_TIME = GregorianCalendar.getInstance().get(GregorianCalendar.SECOND); - Log.e("PHILIP", "day: " + TIME_DAY); + Log.e("PHILIP", "week: " + TIME_MAX); Cursor updatedKeysCursor = context.getContentResolver().query( KeychainContract.UpdatedKeys.CONTENT_URI, new String[]{ KeychainContract.UpdatedKeys.MASTER_KEY_ID, KeychainContract.UpdatedKeys.LAST_UPDATED }, - "? - " + KeychainContract.UpdatedKeys.LAST_UPDATED + " < " + TIME_DAY, + "? - " + KeychainContract.UpdatedKeys.LAST_UPDATED + " < " + TIME_MAX, new String[]{"" + CURRENT_TIME}, null ); @@ -110,7 +141,7 @@ public class KeyserverSyncAdapterService extends Service { while (updatedKeysCursor.moveToNext()) { long masterKeyId = updatedKeysCursor.getLong(INDEX_UPDATED_KEYS_MASTER_KEY_ID); Log.d(Constants.TAG, "Keyserver sync: {" + masterKeyId + "} last updated at {" - + updatedKeysCursor.getLong(INDEX_LAST_UPDATED) + "}s"); + + updatedKeysCursor.getLong(INDEX_LAST_UPDATED) + "}s"); ignoreMasterKeyIds.add(masterKeyId); } updatedKeysCursor.close(); @@ -197,7 +228,7 @@ public class KeyserverSyncAdapterService extends Service { ignoreTorIntent.setAction(ACTION_IGNORE_TOR); PendingIntent ignoreTorPi = PendingIntent.getService( context, - Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT, + 0, // security not issue since we're giving this pending intent to Notification Manager ignoreTorIntent, PendingIntent.FLAG_CANCEL_CURRENT ); @@ -206,9 +237,50 @@ public class KeyserverSyncAdapterService extends Service { context.getString(R.string.keyserver_sync_orbot_notif_ignore), ignoreTorPi); + // not enough space to show it + Intent dismissIntent = new Intent(context, KeyserverSyncAdapterService.class); + dismissIntent.setAction(ACTION_DISMISS_NOTIFICATION); + PendingIntent dismissPi = PendingIntent.getService( + context, + 0, // security not issue since we're giving this pending intent to Notification Manager + dismissIntent, + PendingIntent.FLAG_CANCEL_CURRENT + ); + + /*builder.addAction(R.drawable.abc_ic_clear_mtrl_alpha, + context.getString(android.R.string.cancel), + dismissPi + );*/ + + Intent startOrbotIntent = new Intent(context, KeyserverSyncAdapterService.class); + startOrbotIntent.setAction(ACTION_START_ORBOT); + PendingIntent startOrbotPi = PendingIntent.getService( + context, + 0, // security not issue since we're giving this pending intent to Notification Manager + startOrbotIntent, + PendingIntent.FLAG_CANCEL_CURRENT + ); + + builder.addAction(R.drawable.abc_ic_clear_mtrl_alpha, + context.getString(R.string.keyserver_sync_orbot_notif_start), + startOrbotPi + ); + builder.setContentIntent(startOrbotPi); + return builder.build(); } + /** + * will perform a staggered update of user's keys using delays to ensure new Tor circuits, as + * performed by parcimonie + * + * @return result of the sync + */ + private static ImportKeyResult staggeredSync() { + // TODO: WIP + return null; + } + // from de.azapps.mirakel.helper.Helpers from https://github.com/MirakelX/mirakel-android private static Bitmap getBitmap(int resId, Context context) { int mLargeIconWidth = (int) context.getResources().getDimension( diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index 6f5d98afd..0fa6566f8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -19,6 +19,9 @@ package org.sufficientlysecure.keychain.ui; +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.ContentResolver; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; @@ -37,11 +40,14 @@ import com.mikepenz.materialdrawer.DrawerBuilder; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; +import org.sufficientlysecure.keychain.service.KeyserverSyncAdapterService; import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.util.FabContainer; +import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; public class MainActivity extends BaseNfcActivity implements FabContainer, OnBackStackChangedListener { @@ -164,6 +170,19 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac } } + enablePeriodicKeyserverSync(); + + } + + private void enablePeriodicKeyserverSync() { + // TODO: Increase periodic update time after testing + Log.e("PHILIP", "enabled periodic keyserversybc"); + ContentResolver.addPeriodicSync( + new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE), + Constants.PROVIDER_AUTHORITY, + new Bundle(), + 2*60 + ); } private void setFragment(Fragment fragment, boolean addToBackStack) { diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 6309faf85..67a727645 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1352,10 +1352,10 @@ "Password" - "Orbot not running" - "Keyserver sync failed since Orbot is not running. What would you like to do?" + "Sync From Cloud requires Orbot" + "Tap to start orbot" "Start Orbot" - "Don't use Tor" + "Direct" "Take back your privacy with OpenKeychain!" diff --git a/OpenKeychain/src/main/res/xml/keyserver_sync_adapter_desc.xml b/OpenKeychain/src/main/res/xml/keyserver_sync_adapter_desc.xml index 76211aaf1..3923fae59 100644 --- a/OpenKeychain/src/main/res/xml/keyserver_sync_adapter_desc.xml +++ b/OpenKeychain/src/main/res/xml/keyserver_sync_adapter_desc.xml @@ -1,6 +1,6 @@ Date: Mon, 10 Aug 2015 06:17:29 +0530 Subject: reworked keyserversyncadapterservice flow --- .../keychain/KeychainApplication.java | 20 +- .../keychain/operations/ImportOperation.java | 10 +- .../service/KeyserverSyncAdapterService.java | 368 +++++++++++++++------ .../keychain/ui/KeyListFragment.java | 33 +- .../keychain/ui/MainActivity.java | 19 -- .../keychain/ui/OrbotRequiredDialogActivity.java | 60 +++- .../keychain/ui/base/BaseActivity.java | 2 + .../keychain/util/orbot/OrbotHelper.java | 36 +- 8 files changed, 385 insertions(+), 163 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index cd24394d7..1d6de260d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -28,6 +28,7 @@ import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.Bundle; import android.os.Environment; import android.provider.ContactsContract; import android.widget.Toast; @@ -44,6 +45,7 @@ import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.TlsHelper; import java.security.Security; +import java.util.Arrays; import java.util.HashMap; @@ -136,17 +138,31 @@ public class KeychainApplication extends Application { } /** - * Add OpenKeychain account to Android to link contacts with keys + * Add OpenKeychain account to Android to link contacts with keys and keyserver sync */ public static void setupAccountAsNeeded(Context context) { try { AccountManager manager = AccountManager.get(context); Account[] accounts = manager.getAccountsByType(Constants.ACCOUNT_TYPE); - if (accounts == null || accounts.length == 0) { + + if (accounts.length == 0) { Account account = new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE); if (manager.addAccountExplicitly(account, null, null)) { + // for contact sync ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1); ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true); + // for keyserver sync + ContentResolver.setIsSyncable(account, Constants.PROVIDER_AUTHORITY, 1); + ContentResolver.setSyncAutomatically(account, Constants.PROVIDER_AUTHORITY, + true); + // TODO: Increase periodic update time after testing + Log.e("PHILIP", "enabled periodic keyserversync"); + ContentResolver.addPeriodicSync( + new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE), + Constants.PROVIDER_AUTHORITY, + new Bundle(), + 60 + ); } else { Log.e(Constants.TAG, "Adding account failed!"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java index 9513f58ee..bde161db7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java @@ -503,7 +503,7 @@ public class ImportOperation extends BaseOperation { /** * Used to accumulate the results of individual key imports */ - private class KeyImportAccumulator { + public static class KeyImportAccumulator { private OperationResult.OperationLog mImportLog = new OperationResult.OperationLog(); Progressable mProgressable; private int mTotalKeys; @@ -531,14 +531,6 @@ public class ImportOperation extends BaseOperation { } } - public int getTotalKeys() { - return mTotalKeys; - } - - public int getImportedKeys() { - return mImportedKeys; - } - public synchronized void accumulateKeyImport(ImportKeyResult result) { mImportedKeys++; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java index a08797e6d..11d543f49 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java @@ -1,12 +1,14 @@ package org.sufficientlysecure.keychain.service; import android.accounts.Account; +import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.AbstractThreadedSyncAdapter; import android.content.ContentProviderClient; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.SyncResult; @@ -18,6 +20,10 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.PowerManager; +import android.os.SystemClock; import android.support.v4.app.NotificationCompat; import org.sufficientlysecure.keychain.Constants; @@ -25,6 +31,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.operations.ImportOperation; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; @@ -33,62 +40,100 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; import java.util.ArrayList; import java.util.GregorianCalendar; +import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; public class KeyserverSyncAdapterService extends Service { private static final String ACTION_IGNORE_TOR = "ignore_tor"; + private static final String ACTION_UPDATE_ALL = "update_all"; + private static final String ACTION_SYNC_NOW = "sync_now"; private static final String ACTION_DISMISS_NOTIFICATION = "cancel_sync"; private static final String ACTION_START_ORBOT = "start_orbot"; + private static final String ACTION_CANCEL = "cancel"; + + private AtomicBoolean mCancelled = new AtomicBoolean(false); @Override - public int onStartCommand(Intent intent, int flags, final int startId) { - Log.e("PHILIP", "Sync adapter service starting"); + public int onStartCommand(final Intent intent, int flags, final int startId) { + Log.e("PHILIP", "Sync adapter service starting" + intent.getAction()); + NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT); switch (intent.getAction()) { + case ACTION_CANCEL: { + mCancelled.set(true); + break; + } + // the reason for the separation betweyeen SYNC_NOW and UPDATE_ALL is so that starting + // the sync directly from the notification is possible while the screen is on with + // UPDATE_ALL, but a postponed sync is only started if screen is off + case ACTION_SYNC_NOW: { + // this checks for screen on/off before sync, and postpones the sync if on + ContentResolver.requestSync( + new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE), + Constants.PROVIDER_AUTHORITY, + new Bundle() + ); + break; + } + case ACTION_UPDATE_ALL: { + // does not check for screen on/off + asyncKeyUpdate(this, new CryptoInputParcel()); + break; + } case ACTION_IGNORE_TOR: { - updateKeysFromKeyserver(this, - new CryptoInputParcel(ParcelableProxy.getForNoProxy())); - manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT); - stopSelf(startId); + asyncKeyUpdate(this, new CryptoInputParcel(ParcelableProxy.getForNoProxy())); break; } case ACTION_START_ORBOT: { Intent startOrbot = new Intent(this, OrbotRequiredDialogActivity.class); startOrbot.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startOrbot.setAction(OrbotRequiredDialogActivity.ACTION_START_ORBOT); - startActivity(startOrbot); - new Handler().postDelayed( - new Runnable() { + startOrbot.putExtra(OrbotRequiredDialogActivity.EXTRA_START_ORBOT, true); + Messenger messenger = new Messenger( + new Handler() { @Override - public void run() { - updateKeysFromKeyserver(KeyserverSyncAdapterService.this, - new CryptoInputParcel()); - stopSelf(startId); + public void handleMessage(Message msg) { + switch (msg.what) { + case OrbotRequiredDialogActivity.MESSAGE_ORBOT_STARTED: { + Log.e("PHILIP", "orbot activity returned"); + asyncKeyUpdate(KeyserverSyncAdapterService.this, + new CryptoInputParcel()); + break; + } + case OrbotRequiredDialogActivity.MESSAGE_ORBOT_IGNORE: { + asyncKeyUpdate(KeyserverSyncAdapterService.this, + new CryptoInputParcel( + ParcelableProxy.getForNoProxy())); + break; + } + case OrbotRequiredDialogActivity.MESSAGE_DIALOG_CANCEL: { + // just stop service + stopSelf(); + break; + } + } } - }, - 30000 // shouldn't take longer for orbot to start + } ); - - manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT); + startOrbot.putExtra(OrbotRequiredDialogActivity.EXTRA_MESSENGER, messenger); + startActivity(startOrbot); break; } case ACTION_DISMISS_NOTIFICATION: { - manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT); + // notification is dismissed at the beginning stopSelf(startId); break; } } - // TODO: correct flag? - return START_REDELIVER_INTENT; + return START_NOT_STICKY; } - private static AtomicBoolean sCancelled = new AtomicBoolean(false); - private class KeyserverSyncAdapter extends AbstractThreadedSyncAdapter { public KeyserverSyncAdapter() { @@ -100,7 +145,19 @@ public class KeyserverSyncAdapterService extends Service { ContentProviderClient provider, SyncResult syncResult) { Log.d(Constants.TAG, "Performing a keyserver sync!"); - updateKeysFromKeyserver(KeyserverSyncAdapterService.this, new CryptoInputParcel()); + PowerManager pm = (PowerManager) KeyserverSyncAdapterService.this + .getSystemService(Context.POWER_SERVICE); + @SuppressWarnings("deprecation") // our min is API 15, deprecated only in 20 + boolean isScreenOn = pm.isScreenOn(); + + if (!isScreenOn) { + Intent serviceIntent = new Intent(KeyserverSyncAdapterService.this, + KeyserverSyncAdapterService.class); + serviceIntent.setAction(ACTION_UPDATE_ALL); + startService(serviceIntent); + } else { + postponeSync(); + } } } @@ -109,23 +166,178 @@ public class KeyserverSyncAdapterService extends Service { return new KeyserverSyncAdapter().getSyncAdapterBinder(); } - public static void updateKeysFromKeyserver(Context context, - CryptoInputParcel cryptoInputParcel) { - /** - * 1. Get keys which have been updated recently and therefore do not need to - * be updated now - * 2. Get list of all keys and filter out ones that don't need to be updated - * 3. Update the remaining keys. - * At any time, if the operation is to be cancelled, the sCancelled AtomicBoolean may be set - */ + private void handleUpdateResult(ImportKeyResult result) { + if (result.isPending()) { + Log.e(Constants.TAG, "Keyserver sync pending result: " + + result.getRequiredInputParcel().mType); + // result is pending due to Orbot not being started + // try to start it silently, if disabled show notificationaa + new OrbotHelper.SilentStartManager() { + @Override + protected void onOrbotStarted() { + // retry the update + asyncKeyUpdate(KeyserverSyncAdapterService.this, + new CryptoInputParcel()); + } + + @Override + protected void onSilentStartDisabled() { + // show notification + NotificationManager manager = + (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + manager.notify(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT, + getOrbotNoification(KeyserverSyncAdapterService.this)); + } + }.startOrbotAndListen(this, false); + } else if (isUpdateCancelled()) { + Log.d(Constants.TAG, "Keyserver sync cancelled"); + postponeSync(); + } else { + Log.d(Constants.TAG, "Keyserver sync completed: Updated: " + result.mUpdatedKeys + + " Failed: " + result.mBadKeys); + stopSelf(); + } + } + + private void postponeSync() { + AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); + Intent serviceIntent = new Intent(this, KeyserverSyncAdapterService.class); + serviceIntent.setAction(ACTION_SYNC_NOW); + PendingIntent pi = PendingIntent.getService(this, 0, serviceIntent, + PendingIntent.FLAG_UPDATE_CURRENT); + alarmManager.set( + AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + 30 * 1000, + pi + ); + } + + private void asyncKeyUpdate(final Context context, + final CryptoInputParcel cryptoInputParcel) { + Log.e("PHILIP", "async key update starting"); + new Thread(new Runnable() { + @Override + public void run() { + ImportKeyResult result = updateKeysFromKeyserver(context, cryptoInputParcel); + handleUpdateResult(result); + } + }).start(); + } + + private synchronized ImportKeyResult updateKeysFromKeyserver(final Context context, + final CryptoInputParcel cryptoInputParcel) { + mCancelled.set(false); + + ArrayList keyList = getKeysToUpdate(context); + + if (isUpdateCancelled()) { // if we've already been cancelled + return new ImportKeyResult(OperationResult.RESULT_CANCELLED, + new OperationResult.OperationLog()); + } + + if (cryptoInputParcel.getParcelableProxy() == null) { + // no explicit proxy, retrieve from preferences. Check if we should do a staggered sync + if (Preferences.getPreferences(context).getProxyPrefs().torEnabled) { + return staggeredUpdate(context, keyList, cryptoInputParcel); + } else { + return directUpdate(context, keyList, cryptoInputParcel); + } + } else { + return directUpdate(context, keyList, cryptoInputParcel); + } + } + + private ImportKeyResult directUpdate(Context context, ArrayList keyList, + CryptoInputParcel cryptoInputParcel) { + Log.d(Constants.TAG, "Starting normal update"); + ImportOperation importOp = new ImportOperation(context, new ProviderHelper(context), null); + return importOp.execute( + new ImportKeyringParcel(keyList, + Preferences.getPreferences(context).getPreferredKeyserver()), + cryptoInputParcel + ); + } + + + /** + * will perform a staggered update of user's keys using delays to ensure new Tor circuits, as + * performed by parcimonie. Relevant issue and method at: + * https://github.com/open-keychain/open-keychain/issues/1337 + * + * @return result of the sync + */ + private ImportKeyResult staggeredUpdate(Context context, ArrayList keyList, + CryptoInputParcel cryptoInputParcel) { + Log.d(Constants.TAG, "Starting staggered update"); + // assuming maxCircuitDirtiness is 10min in Tor + // final int MAX_CIRCUIT_DIRTINESS = (int) TimeUnit.MINUTES.toSeconds(10); + // TODO: PHILIP remove after testing + final int MAX_CIRCUIT_DIRTINESS = (int) TimeUnit.MINUTES.toSeconds(1); + // final int WEEK_IN_SECONDS = (int) TimeUnit.DAYS.toSeconds(7); + final int WEEK_IN_SECONDS = 0; + ImportOperation.KeyImportAccumulator accumulator + = new ImportOperation.KeyImportAccumulator(keyList.size(), null); + for (ParcelableKeyRing keyRing : keyList) { + int waitTime; + int staggeredTime = new Random().nextInt(1 + 2 * (WEEK_IN_SECONDS / keyList.size())); + if (staggeredTime >= MAX_CIRCUIT_DIRTINESS) { + waitTime = staggeredTime; + } else { + waitTime = MAX_CIRCUIT_DIRTINESS + new Random().nextInt(MAX_CIRCUIT_DIRTINESS); + } + Log.d(Constants.TAG, "Updating key with fingerprint " + keyRing.mExpectedFingerprint + + " with a wait time of " + waitTime + "s"); + try { + Thread.sleep(waitTime * 1000); + } catch (InterruptedException e) { + Log.e(Constants.TAG, "Exception during sleep between key updates", e); + // skip this one + continue; + } + ArrayList keyWrapper = new ArrayList<>(); + keyWrapper.add(keyRing); + if (isUpdateCancelled()) { + return new ImportKeyResult(ImportKeyResult.RESULT_CANCELLED, + new OperationResult.OperationLog()); + } + ImportKeyResult result = + new ImportOperation(context, new ProviderHelper(context), null, mCancelled) + .execute( + new ImportKeyringParcel( + keyWrapper, + Preferences.getPreferences(context) + .getPreferredKeyserver() + ), + cryptoInputParcel + ); + if (result.isPending()) { + return result; + } + accumulator.accumulateKeyImport(result); + } + return accumulator.getConsolidatedResult(); + } + + /** + * 1. Get keys which have been updated recently and therefore do not need to + * be updated now + * 2. Get list of all keys and filter out ones that don't need to be updated + * 3. Return keys to be updated + * + * @return list of keys that require update + */ + private ArrayList getKeysToUpdate(Context context) { // 1. Get keys which have been updated recently and don't need to updated now final int INDEX_UPDATED_KEYS_MASTER_KEY_ID = 0; final int INDEX_LAST_UPDATED = 1; - final long TIME_MAX = TimeUnit.DAYS.toSeconds(7); - final long CURRENT_TIME = GregorianCalendar.getInstance().get(GregorianCalendar.SECOND); - Log.e("PHILIP", "week: " + TIME_MAX); + // all time in seconds not milliseconds + // TODO: PHILIP correct TIME_MAX after testing + // final long TIME_MAX = TimeUnit.DAYS.toSeconds(7); + final long TIME_MAX = 1; + final long CURRENT_TIME = GregorianCalendar.getInstance().getTimeInMillis() / 1000; + Log.e("PHILIP", "week: " + TIME_MAX + " current: " + CURRENT_TIME); Cursor updatedKeysCursor = context.getContentResolver().query( KeychainContract.UpdatedKeys.CONTENT_URI, new String[]{ @@ -161,7 +373,7 @@ public class KeyserverSyncAdapterService extends Service { ); if (keyCursor == null) { - return; + return new ArrayList<>(); } ArrayList keyList = new ArrayList<>(); @@ -179,49 +391,39 @@ public class KeyserverSyncAdapterService extends Service { } keyCursor.close(); - if (sCancelled.get()) { - // if we've already been cancelled - return; - } - - // 3. Actually update the keys - Log.e("PHILIP", keyList.toString()); - ImportOperation importOp = new ImportOperation(context, new ProviderHelper(context), null); - ImportKeyResult result = importOp.execute( - new ImportKeyringParcel(keyList, - Preferences.getPreferences(context).getPreferredKeyserver()), - cryptoInputParcel - ); - if (result.isPending()) { - NotificationManager manager = - (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); - manager.notify(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT, - getOrbotNoification(context)); + return keyList; + } - Log.d(Constants.TAG, "Keyserver sync failed due to pending result " + - result.getRequiredInputParcel().mType); - } else { - Log.d(Constants.TAG, "Background keyserver sync completed: new " + result.mNewKeys - + " updated " + result.mUpdatedKeys + " bad " + result.mBadKeys); - } + private boolean isUpdateCancelled() { + return mCancelled.get(); } - public static void preventAndCancelUpdates() { - // TODO: PHILIP uncomment! - // sCancelled.set(true); + /** + * will cancel an update already in progress + * + * @param context used to send an Intent to the service requesting cancellation. + */ + public static void cancelUpdates(Context context) { + Intent intent = new Intent(context, KeyserverSyncAdapterService.class); + intent.setAction(ACTION_CANCEL); + context.startService(intent); } - public static void allowUpdates() { - sCancelled.set(false); + // TODO: PHILIP remove! + @Override + public void onDestroy() { + Log.e("PHILIP", "onDestroy"); + super.onDestroy(); } - private static Notification getOrbotNoification(Context context) { + private Notification getOrbotNoification(Context context) { // TODO: PHILIP work in progress NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setSmallIcon(R.drawable.ic_stat_notify_24dp) .setLargeIcon(getBitmap(R.drawable.ic_launcher, context)) .setContentTitle(context.getString(R.string.keyserver_sync_orbot_notif_title)) - .setContentText(context.getString(R.string.keyserver_sync_orbot_notif_msg)); + .setContentText(context.getString(R.string.keyserver_sync_orbot_notif_msg)) + .setAutoCancel(true); // In case the user decides to not use tor Intent ignoreTorIntent = new Intent(context, KeyserverSyncAdapterService.class); @@ -237,21 +439,6 @@ public class KeyserverSyncAdapterService extends Service { context.getString(R.string.keyserver_sync_orbot_notif_ignore), ignoreTorPi); - // not enough space to show it - Intent dismissIntent = new Intent(context, KeyserverSyncAdapterService.class); - dismissIntent.setAction(ACTION_DISMISS_NOTIFICATION); - PendingIntent dismissPi = PendingIntent.getService( - context, - 0, // security not issue since we're giving this pending intent to Notification Manager - dismissIntent, - PendingIntent.FLAG_CANCEL_CURRENT - ); - - /*builder.addAction(R.drawable.abc_ic_clear_mtrl_alpha, - context.getString(android.R.string.cancel), - dismissPi - );*/ - Intent startOrbotIntent = new Intent(context, KeyserverSyncAdapterService.class); startOrbotIntent.setAction(ACTION_START_ORBOT); PendingIntent startOrbotPi = PendingIntent.getService( @@ -261,7 +448,7 @@ public class KeyserverSyncAdapterService extends Service { PendingIntent.FLAG_CANCEL_CURRENT ); - builder.addAction(R.drawable.abc_ic_clear_mtrl_alpha, + builder.addAction(R.drawable.abc_ic_commit_search_api_mtrl_alpha, context.getString(R.string.keyserver_sync_orbot_notif_start), startOrbotPi ); @@ -270,19 +457,8 @@ public class KeyserverSyncAdapterService extends Service { return builder.build(); } - /** - * will perform a staggered update of user's keys using delays to ensure new Tor circuits, as - * performed by parcimonie - * - * @return result of the sync - */ - private static ImportKeyResult staggeredSync() { - // TODO: WIP - return null; - } - // from de.azapps.mirakel.helper.Helpers from https://github.com/MirakelX/mirakel-android - private static Bitmap getBitmap(int resId, Context context) { + private Bitmap getBitmap(int resId, Context context) { int mLargeIconWidth = (int) context.getResources().getDimension( android.R.dimen.notification_large_icon_width); int mLargeIconHeight = (int) context.getResources().getDimension( diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 4997d3fab..9630463fc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -18,13 +18,9 @@ package org.sufficientlysecure.keychain.ui; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; - import android.animation.ObjectAnimator; import android.annotation.TargetApi; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.database.Cursor; @@ -64,13 +60,14 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.ConsolidateInputParcel; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.KeyserverSyncAdapterService; -import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.FabContainer; import org.sufficientlysecure.keychain.util.Log; @@ -78,6 +75,10 @@ import org.sufficientlysecure.keychain.util.Preferences; import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + /** * Public key list with sticky list headers. It does _not_ extend ListFragment because it uses * StickyListHeaders library which does not extend upon ListView. @@ -520,9 +521,7 @@ public class KeyListFragment extends LoaderFragment } private void updateAllKeys() { - // TODO: PHILIP just for testing, remove! - KeyserverSyncAdapterService.updateKeysFromKeyserver(getActivity(), new CryptoInputParcel()); - /*Activity activity = getActivity(); + Activity activity = getActivity(); if (activity == null) { return; } @@ -536,7 +535,7 @@ public class KeyListFragment extends LoaderFragment ); if (cursor == null) { - Notify.create(activity, R.string.error_loading_keys, Style.ERROR); + Notify.create(activity, R.string.error_loading_keys, Notify.Style.ERROR); return; } @@ -563,7 +562,7 @@ public class KeyListFragment extends LoaderFragment mImportOpHelper = new CryptoOperationHelper<>(1, this, this, R.string.progress_updating); - mImportOpHelper.cryptoOperation();*/ + mImportOpHelper.cryptoOperation(); } private void consolidate() { @@ -647,18 +646,6 @@ public class KeyListFragment extends LoaderFragment } } - @Override - public void onResume() { - super.onResume(); - KeyserverSyncAdapterService.preventAndCancelUpdates(); - } - - @Override - public void onPause() { - super.onPause(); - KeyserverSyncAdapterService.allowUpdates(); - } - @Override public void fabMoveUp(int height) { ObjectAnimator anim = ObjectAnimator.ofFloat(mFab, "translationY", 0, -height); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index 0fa6566f8..6f5d98afd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -19,9 +19,6 @@ package org.sufficientlysecure.keychain.ui; -import android.accounts.Account; -import android.accounts.AccountManager; -import android.content.ContentResolver; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; @@ -40,14 +37,11 @@ import com.mikepenz.materialdrawer.DrawerBuilder; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; -import org.sufficientlysecure.keychain.service.KeyserverSyncAdapterService; import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.util.FabContainer; -import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; public class MainActivity extends BaseNfcActivity implements FabContainer, OnBackStackChangedListener { @@ -170,19 +164,6 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac } } - enablePeriodicKeyserverSync(); - - } - - private void enablePeriodicKeyserverSync() { - // TODO: Increase periodic update time after testing - Log.e("PHILIP", "enabled periodic keyserversybc"); - ContentResolver.addPeriodicSync( - new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE), - Constants.PROVIDER_AUTHORITY, - new Bundle(), - 2*60 - ); } private void setFragment(Fragment fragment, boolean addToBackStack) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java index d1c247a76..d12b3fc22 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java @@ -18,12 +18,20 @@ package org.sufficientlysecure.keychain.ui; +import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; import android.support.v4.app.FragmentActivity; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; @@ -34,8 +42,14 @@ import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; public class OrbotRequiredDialogActivity extends FragmentActivity implements OrbotHelper.DialogActions { + public static final int MESSAGE_ORBOT_STARTED = 1; + public static final int MESSAGE_ORBOT_IGNORE = 2; + public static final int MESSAGE_DIALOG_CANCEL = 3; + // if suppplied and true will start Orbot directly without showing dialog public static final String EXTRA_START_ORBOT = "start_orbot"; + // used for communicating results when triggered from a service + public static final String EXTRA_MESSENGER = "messenger"; // to provide any previous crypto input into which proxy preference is merged public static final String EXTRA_CRYPTO_INPUT = "extra_crypto_input"; @@ -43,6 +57,9 @@ public class OrbotRequiredDialogActivity extends FragmentActivity public static final String RESULT_CRYPTO_INPUT = "result_crypto_input"; private CryptoInputParcel mCryptoInputParcel; + private Messenger mMessenger; + + private ProgressDialog mShowOrbotProgressDialog; @Override protected void onCreate(Bundle savedInstanceState) { @@ -54,9 +71,15 @@ public class OrbotRequiredDialogActivity extends FragmentActivity mCryptoInputParcel = new CryptoInputParcel(); } + mMessenger = getIntent().getParcelableExtra(EXTRA_MESSENGER); + boolean startOrbotDirect = getIntent().getBooleanExtra(EXTRA_START_ORBOT, false); if (startOrbotDirect) { - OrbotHelper.bestPossibleOrbotStart(this, this); + mShowOrbotProgressDialog = new ProgressDialog(this); + mShowOrbotProgressDialog.setTitle(R.string.progress_starting_orbot); + mShowOrbotProgressDialog.setCancelable(false); + mShowOrbotProgressDialog.show(); + OrbotHelper.bestPossibleOrbotStart(this, this, false); } else { showDialog(); } @@ -84,13 +107,32 @@ public class OrbotRequiredDialogActivity extends FragmentActivity super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case OrbotHelper.START_TOR_RESULT: { - onOrbotStarted(); // assumption that orbot was started, no way to tell for sure + dismissOrbotProgressDialog(); + // unfortunately, this result is returned immediately and not when Orbot is started + // 10s is approximately the longest time Orbot has taken to start + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + onOrbotStarted(); // assumption that orbot was started + } + }, 10000); } } } + /** + * for when Orbot is started without showing the dialog by the EXTRA_START_ORBOT intent extra + */ + private void dismissOrbotProgressDialog() { + if (mShowOrbotProgressDialog != null) { + mShowOrbotProgressDialog.dismiss(); + } + } + @Override public void onOrbotStarted() { + dismissOrbotProgressDialog(); + sendMessage(MESSAGE_ORBOT_STARTED); Intent intent = new Intent(); // send back unmodified CryptoInputParcel for a retry intent.putExtra(RESULT_CRYPTO_INPUT, mCryptoInputParcel); @@ -100,6 +142,7 @@ public class OrbotRequiredDialogActivity extends FragmentActivity @Override public void onNeutralButton() { + sendMessage(MESSAGE_ORBOT_IGNORE); Intent intent = new Intent(); mCryptoInputParcel.addParcelableProxy(ParcelableProxy.getForNoProxy()); intent.putExtra(RESULT_CRYPTO_INPUT, mCryptoInputParcel); @@ -109,6 +152,19 @@ public class OrbotRequiredDialogActivity extends FragmentActivity @Override public void onCancel() { + sendMessage(MESSAGE_DIALOG_CANCEL); finish(); } + + private void sendMessage(int what) { + if (mMessenger != null) { + Message msg = Message.obtain(); + msg.what = what; + try { + mMessenger.send(msg); + } catch (RemoteException e) { + Log.e(Constants.TAG, "Could not deliver message", e); + } + } + } } \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java index fcf5dc11e..aa4e7d840 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/BaseActivity.java @@ -30,6 +30,7 @@ import android.view.ViewGroup; import android.widget.TextView; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.KeyserverSyncAdapterService; import org.sufficientlysecure.keychain.ui.util.ThemeChanger; /** @@ -51,6 +52,7 @@ public abstract class BaseActivity extends AppCompatActivity { @Override protected void onResume() { super.onResume(); + KeyserverSyncAdapterService.cancelUpdates(this); if (mThemeChanger.changeTheme()) { Intent intent = getIntent(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java index d5ee75f9b..6305d2033 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java @@ -361,7 +361,7 @@ public class OrbotHelper { .show(fragmentActivity.getSupportFragmentManager(), "OrbotHelperOrbotStartDialog"); } - }.startOrbotAndListen(fragmentActivity); + }.startOrbotAndListen(fragmentActivity, true); return false; } else { @@ -385,7 +385,8 @@ public class OrbotHelper { * activities wishing to respond to a change in Orbot state. */ public static void bestPossibleOrbotStart(final DialogActions dialogActions, - final Activity activity) { + final Activity activity, + boolean showProgress) { new SilentStartManager() { @Override @@ -397,23 +398,23 @@ public class OrbotHelper { protected void onSilentStartDisabled() { requestShowOrbotStart(activity); } - }.startOrbotAndListen(activity); + }.startOrbotAndListen(activity, showProgress); } /** * base class for listening to silent orbot starts. Also handles display of progress dialog. */ - private static abstract class SilentStartManager { + public static abstract class SilentStartManager { private ProgressDialog mProgressDialog; - public void startOrbotAndListen(Context context) { - mProgressDialog = new ProgressDialog(ThemeChanger.getDialogThemeWrapper(context)); - mProgressDialog.setMessage(context.getString(R.string.progress_starting_orbot)); - mProgressDialog.setCancelable(false); - mProgressDialog.show(); + public void startOrbotAndListen(final Context context, final boolean showProgress) { + Log.e("PHILIP", "starting orbot listener"); + if (showProgress) { + showProgressDialog(context); + } - BroadcastReceiver receiver = new BroadcastReceiver() { + final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (intent.getStringExtra(OrbotHelper.EXTRA_STATUS)) { @@ -423,14 +424,18 @@ public class OrbotHelper { new Handler().postDelayed(new Runnable() { @Override public void run() { - mProgressDialog.dismiss(); + if (showProgress) { + mProgressDialog.dismiss(); + } onOrbotStarted(); } }, 1000); break; case OrbotHelper.STATUS_STARTS_DISABLED: context.unregisterReceiver(this); - mProgressDialog.dismiss(); + if (showProgress) { + mProgressDialog.dismiss(); + } onSilentStartDisabled(); break; @@ -444,6 +449,13 @@ public class OrbotHelper { requestStartTor(context); } + private void showProgressDialog(Context context) { + mProgressDialog = new ProgressDialog(ThemeChanger.getDialogThemeWrapper(context)); + mProgressDialog.setMessage(context.getString(R.string.progress_starting_orbot)); + mProgressDialog.setCancelable(false); + mProgressDialog.show(); + } + protected abstract void onOrbotStarted(); protected abstract void onSilentStartDisabled(); -- cgit v1.2.3 From 6af24527da68721cb6e613e0bf8f8a5b4addbbf4 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Sun, 16 Aug 2015 14:32:35 +0530 Subject: changed sync name --- OpenKeychain/src/main/AndroidManifest.xml | 5 ++++- OpenKeychain/src/main/res/values/strings.xml | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index d3047decc..0bc2e87ec 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -723,10 +723,13 @@ android:name=".service.KeychainService" android:exported="false" /> + + android:exported="false" + android:label="@string/keyserver_sync_settings_title"/> "Password" + "Update Keys from Cloud" "Sync From Cloud requires Orbot" "Tap to start orbot" "Start Orbot" -- cgit v1.2.3 From 93d66d39f7b985b33538a9f5531e47571693b901 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Sun, 16 Aug 2015 19:47:38 +0530 Subject: changed orbot notification icons --- .../keychain/service/KeyserverSyncAdapterService.java | 14 ++++++++------ .../keychain/ui/OrbotRequiredDialogActivity.java | 5 ++++- .../src/main/res/drawable-hdpi/ic_ic_stat_tor.png | Bin 0 -> 920 bytes OpenKeychain/src/main/res/drawable-hdpi/ic_stat_tor.png | Bin 0 -> 920 bytes .../src/main/res/drawable-hdpi/ic_stat_tor_off.png | Bin 0 -> 1090 bytes .../src/main/res/drawable-mdpi/ic_ic_stat_tor.png | Bin 0 -> 540 bytes OpenKeychain/src/main/res/drawable-mdpi/ic_stat_tor.png | Bin 0 -> 540 bytes .../src/main/res/drawable-mdpi/ic_stat_tor_off.png | Bin 0 -> 727 bytes .../src/main/res/drawable-xhdpi/ic_ic_stat_tor.png | Bin 0 -> 1188 bytes OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_tor.png | Bin 0 -> 1188 bytes .../src/main/res/drawable-xhdpi/ic_stat_tor_off.png | Bin 0 -> 2037 bytes .../src/main/res/drawable-xxhdpi/ic_ic_stat_tor.png | Bin 0 -> 2589 bytes .../src/main/res/drawable-xxhdpi/ic_stat_tor.png | Bin 0 -> 2589 bytes .../src/main/res/drawable-xxhdpi/ic_stat_tor_off.png | Bin 0 -> 3776 bytes .../src/main/res/drawable-xxxhdpi/ic_ic_stat_tor.png | Bin 0 -> 4105 bytes .../src/main/res/drawable-xxxhdpi/ic_stat_tor.png | Bin 0 -> 4105 bytes .../src/main/res/drawable-xxxhdpi/ic_stat_tor_off.png | Bin 0 -> 5960 bytes 17 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 OpenKeychain/src/main/res/drawable-hdpi/ic_ic_stat_tor.png create mode 100644 OpenKeychain/src/main/res/drawable-hdpi/ic_stat_tor.png create mode 100644 OpenKeychain/src/main/res/drawable-hdpi/ic_stat_tor_off.png create mode 100644 OpenKeychain/src/main/res/drawable-mdpi/ic_ic_stat_tor.png create mode 100644 OpenKeychain/src/main/res/drawable-mdpi/ic_stat_tor.png create mode 100644 OpenKeychain/src/main/res/drawable-mdpi/ic_stat_tor_off.png create mode 100644 OpenKeychain/src/main/res/drawable-xhdpi/ic_ic_stat_tor.png create mode 100644 OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_tor.png create mode 100644 OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_tor_off.png create mode 100644 OpenKeychain/src/main/res/drawable-xxhdpi/ic_ic_stat_tor.png create mode 100644 OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_tor.png create mode 100644 OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_tor_off.png create mode 100644 OpenKeychain/src/main/res/drawable-xxxhdpi/ic_ic_stat_tor.png create mode 100644 OpenKeychain/src/main/res/drawable-xxxhdpi/ic_stat_tor.png create mode 100644 OpenKeychain/src/main/res/drawable-xxxhdpi/ic_stat_tor_off.png (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java index 11d543f49..c50f6a6e9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java @@ -63,8 +63,6 @@ public class KeyserverSyncAdapterService extends Service { public int onStartCommand(final Intent intent, int flags, final int startId) { Log.e("PHILIP", "Sync adapter service starting" + intent.getAction()); - NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT); switch (intent.getAction()) { case ACTION_CANCEL: { mCancelled.set(true); @@ -88,10 +86,14 @@ public class KeyserverSyncAdapterService extends Service { break; } case ACTION_IGNORE_TOR: { + NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT); asyncKeyUpdate(this, new CryptoInputParcel(ParcelableProxy.getForNoProxy())); break; } case ACTION_START_ORBOT: { + NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT); Intent startOrbot = new Intent(this, OrbotRequiredDialogActivity.class); startOrbot.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startOrbot.putExtra(OrbotRequiredDialogActivity.EXTRA_START_ORBOT, true); @@ -126,7 +128,8 @@ public class KeyserverSyncAdapterService extends Service { break; } case ACTION_DISMISS_NOTIFICATION: { - // notification is dismissed at the beginning + NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + manager.cancel(Constants.Notification.KEYSERVER_SYNC_FAIL_ORBOT); stopSelf(startId); break; } @@ -417,7 +420,6 @@ public class KeyserverSyncAdapterService extends Service { } private Notification getOrbotNoification(Context context) { - // TODO: PHILIP work in progress NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setSmallIcon(R.drawable.ic_stat_notify_24dp) .setLargeIcon(getBitmap(R.drawable.ic_launcher, context)) @@ -435,7 +437,7 @@ public class KeyserverSyncAdapterService extends Service { PendingIntent.FLAG_CANCEL_CURRENT ); - builder.addAction(R.drawable.abc_ic_clear_mtrl_alpha, + builder.addAction(R.drawable.ic_stat_tor_off, context.getString(R.string.keyserver_sync_orbot_notif_ignore), ignoreTorPi); @@ -448,7 +450,7 @@ public class KeyserverSyncAdapterService extends Service { PendingIntent.FLAG_CANCEL_CURRENT ); - builder.addAction(R.drawable.abc_ic_commit_search_api_mtrl_alpha, + builder.addAction(R.drawable.ic_stat_tor, context.getString(R.string.keyserver_sync_orbot_notif_start), startOrbotPi ); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java index d12b3fc22..0e70cda14 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/OrbotRequiredDialogActivity.java @@ -26,11 +26,13 @@ import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.support.v4.app.FragmentActivity; +import android.view.ContextThemeWrapper; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.ui.util.ThemeChanger; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ParcelableProxy; import org.sufficientlysecure.keychain.util.orbot.OrbotHelper; @@ -75,7 +77,8 @@ public class OrbotRequiredDialogActivity extends FragmentActivity boolean startOrbotDirect = getIntent().getBooleanExtra(EXTRA_START_ORBOT, false); if (startOrbotDirect) { - mShowOrbotProgressDialog = new ProgressDialog(this); + ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(this); + mShowOrbotProgressDialog = new ProgressDialog(theme); mShowOrbotProgressDialog.setTitle(R.string.progress_starting_orbot); mShowOrbotProgressDialog.setCancelable(false); mShowOrbotProgressDialog.show(); diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_ic_stat_tor.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_ic_stat_tor.png new file mode 100644 index 000000000..b6e040adb Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-hdpi/ic_ic_stat_tor.png differ diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_stat_tor.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_stat_tor.png new file mode 100644 index 000000000..b6e040adb Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-hdpi/ic_stat_tor.png differ diff --git a/OpenKeychain/src/main/res/drawable-hdpi/ic_stat_tor_off.png b/OpenKeychain/src/main/res/drawable-hdpi/ic_stat_tor_off.png new file mode 100644 index 000000000..e72d7ca4b Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-hdpi/ic_stat_tor_off.png differ diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_ic_stat_tor.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_ic_stat_tor.png new file mode 100644 index 000000000..49b475fcb Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-mdpi/ic_ic_stat_tor.png differ diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_stat_tor.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_stat_tor.png new file mode 100644 index 000000000..49b475fcb Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-mdpi/ic_stat_tor.png differ diff --git a/OpenKeychain/src/main/res/drawable-mdpi/ic_stat_tor_off.png b/OpenKeychain/src/main/res/drawable-mdpi/ic_stat_tor_off.png new file mode 100644 index 000000000..9d6447799 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-mdpi/ic_stat_tor_off.png differ diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_ic_stat_tor.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_ic_stat_tor.png new file mode 100644 index 000000000..e76c09f8d Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xhdpi/ic_ic_stat_tor.png differ diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_tor.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_tor.png new file mode 100644 index 000000000..e76c09f8d Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_tor.png differ diff --git a/OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_tor_off.png b/OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_tor_off.png new file mode 100644 index 000000000..5b1777c8e Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xhdpi/ic_stat_tor_off.png differ diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_ic_stat_tor.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_ic_stat_tor.png new file mode 100644 index 000000000..5fdedd3b9 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_ic_stat_tor.png differ diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_tor.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_tor.png new file mode 100644 index 000000000..5fdedd3b9 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_tor.png differ diff --git a/OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_tor_off.png b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_tor_off.png new file mode 100644 index 000000000..2fb280a1b Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xxhdpi/ic_stat_tor_off.png differ diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_ic_stat_tor.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_ic_stat_tor.png new file mode 100644 index 000000000..306b94793 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_ic_stat_tor.png differ diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_stat_tor.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_stat_tor.png new file mode 100644 index 000000000..306b94793 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_stat_tor.png differ diff --git a/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_stat_tor_off.png b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_stat_tor_off.png new file mode 100644 index 000000000..317c86717 Binary files /dev/null and b/OpenKeychain/src/main/res/drawable-xxxhdpi/ic_stat_tor_off.png differ -- cgit v1.2.3 From 3f8f70b0a99554aae52fd80d31c29f32a34df5d2 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Mon, 17 Aug 2015 03:08:42 +0530 Subject: added sync preferences --- .../org/sufficientlysecure/keychain/Constants.java | 3 + .../service/KeyserverSyncAdapterService.java | 10 +++- .../keychain/ui/SettingsActivity.java | 64 +++++++++++++++++++++- OpenKeychain/src/main/res/values/strings.xml | 6 ++ .../src/main/res/xml/preference_headers.xml | 3 + OpenKeychain/src/main/res/xml/sync_preferences.xml | 12 ++++ 6 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 OpenKeychain/src/main/res/xml/sync_preferences.xml (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index 03d39f6be..be38c6dba 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -104,6 +104,9 @@ public final class Constants { public static final String PROXY_PORT = "proxyPort"; public static final String PROXY_TYPE = "proxyType"; public static final String THEME = "theme"; + // keyserver sync settings + public static final String SYNC_CONTACTS = "syncContacts"; + public static final String SYNC_KEYSERVER = "syncKeyserver"; public static final class Theme { public static final String LIGHT = "light"; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java index c50f6a6e9..baf649701 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java @@ -162,6 +162,12 @@ public class KeyserverSyncAdapterService extends Service { postponeSync(); } } + + @Override + public void onSyncCanceled() { + super.onSyncCanceled(); + cancelUpdates(KeyserverSyncAdapterService.this); + } } @Override @@ -402,7 +408,9 @@ public class KeyserverSyncAdapterService extends Service { } /** - * will cancel an update already in progress + * will cancel an update already in progress. We send an Intent to cancel it instead of simply + * modifying a static variable sync the service is running in a process that is different from + * the default application process where the UI code runs. * * @param context used to send an Intent to the service requesting cancellation. */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java index c18156428..0ae0c62a5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java @@ -18,11 +18,12 @@ package org.sufficientlysecure.keychain.ui; -import android.annotation.TargetApi; +import android.accounts.Account; +import android.accounts.AccountManager; import android.app.Activity; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.os.Build; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; @@ -31,6 +32,7 @@ import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; +import android.provider.ContactsContract; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.view.View; @@ -467,11 +469,69 @@ public class SettingsActivity extends AppCompatPreferenceActivity { } } + /** + * This fragment shows the keyserver/contacts sync preferences + */ + public static class SyncSettingsFragment extends PreferenceFragment { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.sync_preferences); + } + + @Override + public void onResume() { + super.onResume(); + // this needs to be done in onResume since the user can change sync values from Android + // settings and we need to reflect that change when the user navigates back + AccountManager manager = AccountManager.get(getActivity()); + final Account account = manager.getAccountsByType(Constants.ACCOUNT_TYPE)[0]; + // for keyserver sync + initializeSyncCheckBox( + (CheckBoxPreference) findPreference(Constants.Pref.SYNC_KEYSERVER), + account, + Constants.PROVIDER_AUTHORITY + ); + // for contacts sync + initializeSyncCheckBox( + (CheckBoxPreference) findPreference(Constants.Pref.SYNC_CONTACTS), + account, + ContactsContract.AUTHORITY + ); + } + + private void initializeSyncCheckBox(CheckBoxPreference syncCheckBox, final Account account, + final String authority) { + boolean syncEnabled = ContentResolver.getSyncAutomatically(account, authority); + syncCheckBox.setChecked(syncEnabled); + + syncCheckBox.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + boolean syncEnabled = (Boolean) newValue; + if (syncEnabled) { + ContentResolver.setSyncAutomatically(account, authority, true); + } else { + // disable syncs + ContentResolver.setSyncAutomatically(account, authority, false); + // cancel any ongoing/pending syncs + ContentResolver.cancelSync(account, authority); + } + return true; + } + }); + } + } + protected boolean isValidFragment(String fragmentName) { return AdvancedPrefsFragment.class.getName().equals(fragmentName) || CloudSearchPrefsFragment.class.getName().equals(fragmentName) || ProxyPrefsFragment.class.getName().equals(fragmentName) || GuiPrefsFragment.class.getName().equals(fragmentName) + || SyncSettingsFragment.class.getName().equals(fragmentName) || super.isValidFragment(fragmentName); } diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 495660a22..ba5be593f 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -51,6 +51,7 @@ "Password/PIN Handling" "Proxy Settings" "Interface" + "Sync Settings" "Confirm" "Actions" "Key" @@ -175,6 +176,11 @@ "keybase.io" "Search keys on keybase.io" + "Automatically update keys" + "Updates keys older than a week, from the preferred keyserver" + "Sync Contacts with Keys" + "Associates contacts with imported keys, based on email, completely offline" + "Enable Tor" "Requires Orbot to be installed" diff --git a/OpenKeychain/src/main/res/xml/preference_headers.xml b/OpenKeychain/src/main/res/xml/preference_headers.xml index b7512b062..606196c1e 100644 --- a/OpenKeychain/src/main/res/xml/preference_headers.xml +++ b/OpenKeychain/src/main/res/xml/preference_headers.xml @@ -11,4 +11,7 @@
+
diff --git a/OpenKeychain/src/main/res/xml/sync_preferences.xml b/OpenKeychain/src/main/res/xml/sync_preferences.xml new file mode 100644 index 000000000..d4ea81591 --- /dev/null +++ b/OpenKeychain/src/main/res/xml/sync_preferences.xml @@ -0,0 +1,12 @@ + + + + -- cgit v1.2.3 From f625a26bbd9e4e1049480028b7738ff4e37fd712 Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Mon, 17 Aug 2015 03:39:24 +0530 Subject: added on/off summaries --- .../keychain/ui/SettingsActivity.java | 27 +++++++++++++++++++++- OpenKeychain/src/main/res/values/strings.xml | 9 +++++--- OpenKeychain/src/main/res/xml/sync_preferences.xml | 6 ++--- 3 files changed, 34 insertions(+), 8 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java index 0ae0c62a5..842059da5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java @@ -503,10 +503,12 @@ public class SettingsActivity extends AppCompatPreferenceActivity { ); } - private void initializeSyncCheckBox(CheckBoxPreference syncCheckBox, final Account account, + private void initializeSyncCheckBox(final CheckBoxPreference syncCheckBox, + final Account account, final String authority) { boolean syncEnabled = ContentResolver.getSyncAutomatically(account, authority); syncCheckBox.setChecked(syncEnabled); + setSummary(syncCheckBox, authority, syncEnabled); syncCheckBox.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override @@ -520,10 +522,33 @@ public class SettingsActivity extends AppCompatPreferenceActivity { // cancel any ongoing/pending syncs ContentResolver.cancelSync(account, authority); } + setSummary(syncCheckBox, authority, syncEnabled); return true; } }); } + + private void setSummary(CheckBoxPreference syncCheckBox, String authority, + boolean checked) { + switch (authority) { + case Constants.PROVIDER_AUTHORITY: { + if (checked) { + syncCheckBox.setSummary(R.string.label_sync_settings_keyserver_summary_on); + } else { + syncCheckBox.setSummary(R.string.label_sync_settings_keyserver_summary_off); + } + break; + } + case ContactsContract.AUTHORITY: { + if (checked) { + syncCheckBox.setSummary(R.string.label_sync_settings_contacts_summary_on); + } else { + syncCheckBox.setSummary(R.string.label_sync_settings_contacts_summary_off); + } + break; + } + } + } } protected boolean isValidFragment(String fragmentName) { diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index ba5be593f..2d9b22852 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -177,9 +177,13 @@ "Search keys on keybase.io" "Automatically update keys" - "Updates keys older than a week, from the preferred keyserver" + "Keys older than a week are updated from the preferred keyserver" + "Keys not automatically updated" "Sync Contacts with Keys" - "Associates contacts with imported keys, based on email, completely offline" + "Keys linked to contacts with matching emails, happens completely offline" + "New keys will not be linked to contacts" + + "Automatically update keys" "Enable Tor" @@ -1358,7 +1362,6 @@ "Password" - "Update Keys from Cloud" "Sync From Cloud requires Orbot" "Tap to start orbot" "Start Orbot" diff --git a/OpenKeychain/src/main/res/xml/sync_preferences.xml b/OpenKeychain/src/main/res/xml/sync_preferences.xml index d4ea81591..e870be9ec 100644 --- a/OpenKeychain/src/main/res/xml/sync_preferences.xml +++ b/OpenKeychain/src/main/res/xml/sync_preferences.xml @@ -2,11 +2,9 @@ + android:title="@string/label_sync_settings_keyserver_title"/> + android:title="@string/label_sync_settings_contacts_title" /> -- cgit v1.2.3 From 0251f0e41695d3961dde553ba9ab76fa46583abb Mon Sep 17 00:00:00 2001 From: Adithya Abraham Philip Date: Wed, 19 Aug 2015 01:13:12 +0530 Subject: introduced constants for keyserver sync, fixed sync issue --- .../org/sufficientlysecure/keychain/Constants.java | 3 +- .../keychain/KeychainApplication.java | 20 +----- .../keychain/keyimport/HkpKeyserver.java | 2 +- .../keychain/operations/ImportOperation.java | 2 +- .../keychain/operations/RevokeOperation.java | 4 +- .../operations/results/OperationResult.java | 5 +- .../keychain/provider/ProviderHelper.java | 13 ++-- .../service/ContactSyncAdapterService.java | 2 +- .../service/KeyserverSyncAdapterService.java | 82 ++++++++++++++-------- .../keychain/util/Preferences.java | 9 ++- .../keychain/util/orbot/OrbotHelper.java | 2 +- OpenKeychain/src/main/res/values/strings.xml | 1 - 12 files changed, 77 insertions(+), 68 deletions(-) (limited to 'OpenKeychain/src/main') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index be38c6dba..a244972fb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -29,6 +29,7 @@ public final class Constants { public static final boolean DEBUG = BuildConfig.DEBUG; public static final boolean DEBUG_LOG_DB_QUERIES = false; public static final boolean DEBUG_SYNC_REMOVE_CONTACTS = false; + public static final boolean DEBUG_KEYSERVER_SYNC = false; public static final String TAG = DEBUG ? "Keychain D" : "Keychain"; @@ -126,7 +127,7 @@ public final class Constants { public static final class Defaults { public static final String KEY_SERVERS = "hkps://hkps.pool.sks-keyservers.net, hkps://pgp.mit.edu"; - public static final int PREF_VERSION = 5; + public static final int PREF_VERSION = 6; } public static final class key { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index 1d6de260d..311ef2d3b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -23,12 +23,10 @@ import android.app.Application; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Build; -import android.os.Bundle; import android.os.Environment; import android.provider.ContactsContract; import android.widget.Toast; @@ -36,7 +34,7 @@ import android.widget.Toast; import org.spongycastle.jce.provider.BouncyCastleProvider; import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; -import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.KeyserverSyncAdapterService; import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.util.Log; @@ -45,7 +43,6 @@ import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.TlsHelper; import java.security.Security; -import java.util.Arrays; import java.util.HashMap; @@ -99,7 +96,7 @@ public class KeychainApplication extends Application { setupAccountAsNeeded(this); // Update keyserver list as needed - Preferences.getPreferences(this).upgradePreferences(); + Preferences.getPreferences(this).upgradePreferences(this); TlsHelper.addStaticCA("pool.sks-keyservers.net", getAssets(), "sks-keyservers.netCA.cer"); @@ -151,18 +148,7 @@ public class KeychainApplication extends Application { // for contact sync ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1); ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true); - // for keyserver sync - ContentResolver.setIsSyncable(account, Constants.PROVIDER_AUTHORITY, 1); - ContentResolver.setSyncAutomatically(account, Constants.PROVIDER_AUTHORITY, - true); - // TODO: Increase periodic update time after testing - Log.e("PHILIP", "enabled periodic keyserversync"); - ContentResolver.addPeriodicSync( - new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE), - Constants.PROVIDER_AUTHORITY, - new Bundle(), - 60 - ); + KeyserverSyncAdapterService.enableKeyserverSync(context); } else { Log.e(Constants.TAG, "Adding account failed!"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java index 5aac05712..558b8ce7d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java @@ -360,7 +360,7 @@ public class HkpKeyserver extends Keyserver { try { data = query(request, proxy); } catch (HttpError httpError) { - Log.e(Constants.TAG, "Failed to get key at HkpKeyserver", httpError); + Log.d(Constants.TAG, "Failed to get key at HkpKeyserver", httpError); throw new QueryFailedException("not found"); } Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(data); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java index bde161db7..4b991ddda 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java @@ -232,7 +232,7 @@ public class ImportOperation extends BaseOperation { log.add(LogType.MSG_IMPORT_FETCH_ERROR_DECODE, 3); } } catch (Keyserver.QueryFailedException e) { - Log.e(Constants.TAG, "query failed", e); + Log.d(Constants.TAG, "query failed", e); log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER_ERROR, 3, e.getMessage()); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java index 9aceb946c..975cf541a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/RevokeOperation.java @@ -93,13 +93,13 @@ public class RevokeOperation extends BaseOperation { log.add(OperationResult.LogType.MSG_REVOKE_OK, 1); return new RevokeResult(RevokeResult.RESULT_OK, log, masterKeyId); } else { - log.add(OperationResult.LogType.MSG_REVOKE_KEY_FAIL, 1); + log.add(OperationResult.LogType.MSG_REVOKE_ERROR_KEY_FAIL, 1); return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId); } } catch (PgpKeyNotFoundException | ProviderHelper.NotFoundException e) { Log.e(Constants.TAG, "could not find key to revoke", e); - log.add(OperationResult.LogType.MSG_REVOKE_KEY_FAIL, 1); + log.add(OperationResult.LogType.MSG_REVOKE_ERROR_KEY_FAIL, 1); return new RevokeResult(RevokeResult.RESULT_ERROR, log, masterKeyId); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index d498bd9a1..5ac1e89bb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -763,10 +763,9 @@ public abstract class OperationResult implements Parcelable { MSG_DEL_FAIL (LogLevel.WARN, R.plurals.msg_del_fail), MSG_REVOKE_ERROR_EMPTY (LogLevel.ERROR, R.string.msg_revoke_error_empty), - MSG_REVOKE_ERROR_MULTI_SECRET (LogLevel.DEBUG, R.string.msg_revoke_error_multi_secret), - MSG_REVOKE_ERROR_NOT_FOUND (LogLevel.DEBUG, R.string.msg_revoke_error_multi_secret), + MSG_REVOKE_ERROR_NOT_FOUND (LogLevel.ERROR, R.string.msg_revoke_error_not_found), MSG_REVOKE (LogLevel.DEBUG, R.string.msg_revoke_key), - MSG_REVOKE_KEY_FAIL (LogLevel.ERROR, R.string.msg_revoke_key_fail), + MSG_REVOKE_ERROR_KEY_FAIL (LogLevel.ERROR, R.string.msg_revoke_key_fail), MSG_REVOKE_OK (LogLevel.OK, R.string.msg_revoke_ok), // keybase verification diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index e8eea6831..cbb71276c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -700,20 +700,14 @@ public class ProviderHelper { new String[]{"" + masterKeyId}, null ); - ContentValues lastUpdatedEntry = null; if (lastUpdatedCursor.moveToNext()) { - lastUpdatedEntry = new ContentValues(2); + // there was an entry to re-insert + // this operation must happen after the new key is inserted + ContentValues lastUpdatedEntry = new ContentValues(2); lastUpdatedEntry.put(UpdatedKeys.MASTER_KEY_ID, lastUpdatedCursor.getLong(INDEX_MASTER_KEY_ID)); lastUpdatedEntry.put(UpdatedKeys.LAST_UPDATED, lastUpdatedCursor.getLong(INDEX_LAST_UPDATED)); - Log.e("PHILIP", "cv: " + lastUpdatedEntry + " actual: " + masterKeyId); - } - lastUpdatedCursor.close(); - - if (lastUpdatedEntry != null) { - // there was an entry to re-insert - // this operation must happen after the new key is inserted operations.add( ContentProviderOperation .newInsert(UpdatedKeys.CONTENT_URI) @@ -721,6 +715,7 @@ public class ProviderHelper { .build() ); } + lastUpdatedCursor.close(); try { // delete old version of this keyRing, which also deletes all keys and userIds on cascade diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java index 7688b9252..b36d23775 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java @@ -45,7 +45,7 @@ public class ContactSyncAdapterService extends Service { @Override public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, final SyncResult syncResult) { - Log.d(Constants.TAG, "Performing a sync!"); + Log.d(Constants.TAG, "Performing a contact sync!"); // TODO: Import is currently disabled for 2.8, until we implement proper origin management // importDone.set(false); // KeychainApplication.setupAccountAsNeeded(ContactSyncAdapterService.this); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java index baf649701..3243df1a8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeyserverSyncAdapterService.java @@ -1,6 +1,7 @@ package org.sufficientlysecure.keychain.service; import android.accounts.Account; +import android.accounts.AccountManager; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; @@ -25,6 +26,7 @@ import android.os.Messenger; import android.os.PowerManager; import android.os.SystemClock; import android.support.v4.app.NotificationCompat; +import android.widget.Toast; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -50,6 +52,20 @@ import java.util.concurrent.atomic.AtomicBoolean; public class KeyserverSyncAdapterService extends Service { + // how often a sync should be initiated, in s + public static final long SYNC_INTERVAL = + Constants.DEBUG_KEYSERVER_SYNC + ? TimeUnit.MINUTES.toSeconds(2) : TimeUnit.DAYS.toSeconds(3); + // time since last update after which a key should be updated again, in s + public static final long KEY_UPDATE_LIMIT = + Constants.DEBUG_KEYSERVER_SYNC ? 1 : TimeUnit.DAYS.toSeconds(7); + // time by which a sync is postponed in case of a + public static final long SYNC_POSTPONE_TIME = + Constants.DEBUG_KEYSERVER_SYNC ? 30 * 1000 : TimeUnit.MINUTES.toMillis(5); + // Time taken by Orbot before a new circuit is created + public static final int ORBOT_CIRCUIT_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(10); + + private static final String ACTION_IGNORE_TOR = "ignore_tor"; private static final String ACTION_UPDATE_ALL = "update_all"; private static final String ACTION_SYNC_NOW = "sync_now"; @@ -61,8 +77,6 @@ public class KeyserverSyncAdapterService extends Service { @Override public int onStartCommand(final Intent intent, int flags, final int startId) { - Log.e("PHILIP", "Sync adapter service starting" + intent.getAction()); - switch (intent.getAction()) { case ACTION_CANCEL: { mCancelled.set(true); @@ -103,7 +117,6 @@ public class KeyserverSyncAdapterService extends Service { public void handleMessage(Message msg) { switch (msg.what) { case OrbotRequiredDialogActivity.MESSAGE_ORBOT_STARTED: { - Log.e("PHILIP", "orbot activity returned"); asyncKeyUpdate(KeyserverSyncAdapterService.this, new CryptoInputParcel()); break; @@ -177,10 +190,8 @@ public class KeyserverSyncAdapterService extends Service { private void handleUpdateResult(ImportKeyResult result) { if (result.isPending()) { - Log.e(Constants.TAG, "Keyserver sync pending result: " - + result.getRequiredInputParcel().mType); // result is pending due to Orbot not being started - // try to start it silently, if disabled show notificationaa + // try to start it silently, if disabled show notifications new OrbotHelper.SilentStartManager() { @Override protected void onOrbotStarted() { @@ -199,7 +210,8 @@ public class KeyserverSyncAdapterService extends Service { } }.startOrbotAndListen(this, false); } else if (isUpdateCancelled()) { - Log.d(Constants.TAG, "Keyserver sync cancelled"); + Log.d(Constants.TAG, "Keyserver sync cancelled, postponing by" + SYNC_POSTPONE_TIME + + "ms"); postponeSync(); } else { Log.d(Constants.TAG, "Keyserver sync completed: Updated: " + result.mUpdatedKeys @@ -216,14 +228,13 @@ public class KeyserverSyncAdapterService extends Service { PendingIntent.FLAG_UPDATE_CURRENT); alarmManager.set( AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + 30 * 1000, + SystemClock.elapsedRealtime() + SYNC_POSTPONE_TIME, pi ); } private void asyncKeyUpdate(final Context context, final CryptoInputParcel cryptoInputParcel) { - Log.e("PHILIP", "async key update starting"); new Thread(new Runnable() { @Override public void run() { @@ -234,7 +245,7 @@ public class KeyserverSyncAdapterService extends Service { } private synchronized ImportKeyResult updateKeysFromKeyserver(final Context context, - final CryptoInputParcel cryptoInputParcel) { + final CryptoInputParcel cryptoInputParcel) { mCancelled.set(false); ArrayList keyList = getKeysToUpdate(context); @@ -278,10 +289,6 @@ public class KeyserverSyncAdapterService extends Service { private ImportKeyResult staggeredUpdate(Context context, ArrayList keyList, CryptoInputParcel cryptoInputParcel) { Log.d(Constants.TAG, "Starting staggered update"); - // assuming maxCircuitDirtiness is 10min in Tor - // final int MAX_CIRCUIT_DIRTINESS = (int) TimeUnit.MINUTES.toSeconds(10); - // TODO: PHILIP remove after testing - final int MAX_CIRCUIT_DIRTINESS = (int) TimeUnit.MINUTES.toSeconds(1); // final int WEEK_IN_SECONDS = (int) TimeUnit.DAYS.toSeconds(7); final int WEEK_IN_SECONDS = 0; ImportOperation.KeyImportAccumulator accumulator @@ -289,10 +296,10 @@ public class KeyserverSyncAdapterService extends Service { for (ParcelableKeyRing keyRing : keyList) { int waitTime; int staggeredTime = new Random().nextInt(1 + 2 * (WEEK_IN_SECONDS / keyList.size())); - if (staggeredTime >= MAX_CIRCUIT_DIRTINESS) { + if (staggeredTime >= ORBOT_CIRCUIT_TIMEOUT) { waitTime = staggeredTime; } else { - waitTime = MAX_CIRCUIT_DIRTINESS + new Random().nextInt(MAX_CIRCUIT_DIRTINESS); + waitTime = ORBOT_CIRCUIT_TIMEOUT + new Random().nextInt(ORBOT_CIRCUIT_TIMEOUT); } Log.d(Constants.TAG, "Updating key with fingerprint " + keyRing.mExpectedFingerprint + " with a wait time of " + waitTime + "s"); @@ -342,18 +349,14 @@ public class KeyserverSyncAdapterService extends Service { final int INDEX_LAST_UPDATED = 1; // all time in seconds not milliseconds - // TODO: PHILIP correct TIME_MAX after testing - // final long TIME_MAX = TimeUnit.DAYS.toSeconds(7); - final long TIME_MAX = 1; final long CURRENT_TIME = GregorianCalendar.getInstance().getTimeInMillis() / 1000; - Log.e("PHILIP", "week: " + TIME_MAX + " current: " + CURRENT_TIME); Cursor updatedKeysCursor = context.getContentResolver().query( KeychainContract.UpdatedKeys.CONTENT_URI, new String[]{ KeychainContract.UpdatedKeys.MASTER_KEY_ID, KeychainContract.UpdatedKeys.LAST_UPDATED }, - "? - " + KeychainContract.UpdatedKeys.LAST_UPDATED + " < " + TIME_MAX, + "? - " + KeychainContract.UpdatedKeys.LAST_UPDATED + " < " + KEY_UPDATE_LIMIT, new String[]{"" + CURRENT_TIME}, null ); @@ -361,7 +364,7 @@ public class KeyserverSyncAdapterService extends Service { ArrayList ignoreMasterKeyIds = new ArrayList<>(); while (updatedKeysCursor.moveToNext()) { long masterKeyId = updatedKeysCursor.getLong(INDEX_UPDATED_KEYS_MASTER_KEY_ID); - Log.d(Constants.TAG, "Keyserver sync: {" + masterKeyId + "} last updated at {" + Log.d(Constants.TAG, "Keyserver sync: Ignoring {" + masterKeyId + "} last updated at {" + updatedKeysCursor.getLong(INDEX_LAST_UPDATED) + "}s"); ignoreMasterKeyIds.add(masterKeyId); } @@ -391,6 +394,7 @@ public class KeyserverSyncAdapterService extends Service { if (ignoreMasterKeyIds.contains(keyId)) { continue; } + Log.d(Constants.TAG, "Keyserver sync: Updating {" + keyId + "}"); String fingerprint = KeyFormattingUtils .convertFingerprintToHex(keyCursor.getBlob(INDEX_FINGERPRINT)); String hexKeyId = KeyFormattingUtils @@ -420,13 +424,6 @@ public class KeyserverSyncAdapterService extends Service { context.startService(intent); } - // TODO: PHILIP remove! - @Override - public void onDestroy() { - Log.e("PHILIP", "onDestroy"); - super.onDestroy(); - } - private Notification getOrbotNoification(Context context) { NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setSmallIcon(R.drawable.ic_stat_notify_24dp) @@ -467,6 +464,33 @@ public class KeyserverSyncAdapterService extends Service { return builder.build(); } + public static void enableKeyserverSync(Context context) { + try { + AccountManager manager = AccountManager.get(context); + Account[] accounts = manager.getAccountsByType(Constants.ACCOUNT_TYPE); + + Account account = new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE); + if (accounts.length == 0) { + if (!manager.addAccountExplicitly(account, null, null)) { + Log.e(Constants.TAG, "Adding account failed!"); + } + } + // for keyserver sync + ContentResolver.setIsSyncable(account, Constants.PROVIDER_AUTHORITY, 1); + ContentResolver.setSyncAutomatically(account, Constants.PROVIDER_AUTHORITY, + true); + ContentResolver.addPeriodicSync( + account, + Constants.PROVIDER_AUTHORITY, + new Bundle(), + SYNC_INTERVAL + ); + } catch (SecurityException e) { + Log.e(Constants.TAG, "SecurityException when adding the account", e); + Toast.makeText(context, R.string.reinstall_openkeychain, Toast.LENGTH_LONG).show(); + } + } + // from de.azapps.mirakel.helper.Helpers from https://github.com/MirakelX/mirakel-android private Bitmap getBitmap(int resId, Context context) { int mLargeIconWidth = (int) context.getResources().getDimension( diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java index 0596b0079..370511c4f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java @@ -26,6 +26,7 @@ import android.preference.PreferenceManager; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants.Pref; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.KeyserverSyncAdapterService; import java.net.Proxy; import java.util.ArrayList; @@ -306,7 +307,7 @@ public class Preferences { return new ProxyPrefs(true, false, Constants.Orbot.PROXY_HOST, Constants.Orbot.PROXY_PORT, Constants.Orbot.PROXY_TYPE); } else if (useNormalProxy) { - return new ProxyPrefs(useTor, useNormalProxy, getProxyHost(), getProxyPort(), getProxyType()); + return new ProxyPrefs(false, true, getProxyHost(), getProxyPort(), getProxyType()); } else { return new ProxyPrefs(false, false, null, -1, null); } @@ -356,7 +357,7 @@ public class Preferences { } } - public void upgradePreferences() { + public void upgradePreferences(Context context) { if (mSharedPreferences.getInt(Constants.Pref.PREF_DEFAULT_VERSION, 0) != Constants.Defaults.PREF_VERSION) { switch (mSharedPreferences.getInt(Constants.Pref.PREF_DEFAULT_VERSION, 0)) { @@ -394,6 +395,10 @@ public class Preferences { } // fall through case 5: { + KeyserverSyncAdapterService.enableKeyserverSync(context); + } + // fall through + case 6: { } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java index 6305d2033..d85ad9128 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java @@ -409,7 +409,7 @@ public class OrbotHelper { private ProgressDialog mProgressDialog; public void startOrbotAndListen(final Context context, final boolean showProgress) { - Log.e("PHILIP", "starting orbot listener"); + Log.d(Constants.TAG, "starting orbot listener"); if (showProgress) { showProgressDialog(context); } diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 2d9b22852..643f41004 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1314,7 +1314,6 @@ "Nothing to revoke!" - "Secret keys can only be revoked individually!" "Cannot find key to revoke!" "Revoking key %s" "Failed revoking key" -- cgit v1.2.3