aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
diff options
context:
space:
mode:
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java149
1 files changed, 137 insertions, 12 deletions
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 28f230f71..13d9b497f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -20,11 +20,13 @@ package org.sufficientlysecure.keychain.service;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -32,11 +34,15 @@ import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
+
import android.support.v4.util.LongSparseArray;
+import android.support.v4.app.NotificationCompat;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log;
@@ -54,6 +60,8 @@ public class PassphraseCacheService extends Service {
+ "PASSPHRASE_CACHE_ADD";
public static final String ACTION_PASSPHRASE_CACHE_GET = Constants.INTENT_PREFIX
+ "PASSPHRASE_CACHE_GET";
+ public static final String ACTION_PASSPHRASE_CACHE_CLEAR = Constants.INTENT_PREFIX
+ + "PASSPHRASE_CACHE_CLEAR";
public static final String BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE = Constants.INTENT_PREFIX
+ "PASSPHRASE_CACHE_BROADCAST";
@@ -62,13 +70,16 @@ public class PassphraseCacheService extends Service {
public static final String EXTRA_KEY_ID = "key_id";
public static final String EXTRA_PASSPHRASE = "passphrase";
public static final String EXTRA_MESSENGER = "messenger";
+ public static final String EXTRA_USERID = "userid";
private static final int REQUEST_ID = 0;
private static final long DEFAULT_TTL = 15;
+ private static final int NOTIFICATION_ID = 1;
+
private BroadcastReceiver mIntentReceiver;
- private LongSparseArray<String> mPassphraseCache = new LongSparseArray<String>();
+ private LongSparseArray<CachedPassphrase> mPassphraseCache = new LongSparseArray<CachedPassphrase>();
Context mContext;
@@ -81,14 +92,17 @@ public class PassphraseCacheService extends Service {
* @param keyId
* @param passphrase
*/
- public static void addCachedPassphrase(Context context, long keyId, String passphrase) {
+ public static void addCachedPassphrase(Context context, long keyId, String passphrase,
+ String primaryUserId) {
Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + keyId);
Intent intent = new Intent(context, PassphraseCacheService.class);
intent.setAction(ACTION_PASSPHRASE_CACHE_ADD);
+
intent.putExtra(EXTRA_TTL, Preferences.getPreferences(context).getPassphraseCacheTtl());
intent.putExtra(EXTRA_PASSPHRASE, passphrase);
intent.putExtra(EXTRA_KEY_ID, keyId);
+ intent.putExtra(EXTRA_USERID, primaryUserId);
context.startService(intent);
}
@@ -159,11 +173,11 @@ public class PassphraseCacheService extends Service {
// passphrase for symmetric encryption?
if (keyId == Constants.key.symmetric) {
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption");
- String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric);
+ String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric).getPassphrase();
if (cachedPassphrase == null) {
return null;
}
- addCachedPassphrase(this, Constants.key.symmetric, cachedPassphrase);
+ addCachedPassphrase(this, Constants.key.symmetric, cachedPassphrase, getString(R.string.passp_cache_notif_pwd));
return cachedPassphrase;
}
@@ -176,12 +190,16 @@ public class PassphraseCacheService extends Service {
if (!key.hasPassphrase()) {
Log.d(Constants.TAG, "Key has no passphrase! Caches and returns empty passphrase!");
- addCachedPassphrase(this, keyId, "");
+ try {
+ addCachedPassphrase(this, keyId, "", key.getPrimaryUserIdWithFallback());
+ } catch (PgpGeneralException e) {
+ Log.d(Constants.TAG, "PgpGeneralException occured");
+ }
return "";
}
// get cached passphrase
- String cachedPassphrase = mPassphraseCache.get(keyId);
+ CachedPassphrase cachedPassphrase = mPassphraseCache.get(keyId);
if (cachedPassphrase == null) {
Log.d(Constants.TAG, "PassphraseCacheService Passphrase not (yet) cached, returning null");
// not really an error, just means the passphrase is not cached but not empty either
@@ -190,8 +208,8 @@ public class PassphraseCacheService extends Service {
// set it again to reset the cache life cycle
Log.d(Constants.TAG, "PassphraseCacheService Cache passphrase again when getting it!");
- addCachedPassphrase(this, keyId, cachedPassphrase);
- return cachedPassphrase;
+ addCachedPassphrase(this, keyId, cachedPassphrase.getPassphrase(), cachedPassphrase.getPrimaryUserID());
+ return cachedPassphrase.getPassphrase();
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "PassphraseCacheService Passphrase for unknown key was requested!");
@@ -256,14 +274,16 @@ public class PassphraseCacheService extends Service {
if (ACTION_PASSPHRASE_CACHE_ADD.equals(intent.getAction())) {
long ttl = intent.getLongExtra(EXTRA_TTL, DEFAULT_TTL);
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
+
String passphrase = intent.getStringExtra(EXTRA_PASSPHRASE);
+ String primaryUserID = intent.getStringExtra(EXTRA_USERID);
Log.d(Constants.TAG,
"PassphraseCacheService Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with keyId: "
- + keyId + ", ttl: " + ttl);
+ + keyId + ", ttl: " + ttl + ", usrId: " + primaryUserID);
- // add keyId and passphrase to memory
- mPassphraseCache.put(keyId, passphrase);
+ // add keyId, passphrase and primary user id to memory
+ mPassphraseCache.put(keyId, new CachedPassphrase(passphrase, primaryUserID));
if (ttl > 0) {
// register new alarm with keyId for this passphrase
@@ -271,6 +291,9 @@ public class PassphraseCacheService extends Service {
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, keyId));
}
+
+ updateNotifications();
+
} else if (ACTION_PASSPHRASE_CACHE_GET.equals(intent.getAction())) {
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);
@@ -286,6 +309,17 @@ public class PassphraseCacheService extends Service {
} catch (RemoteException e) {
Log.e(Constants.TAG, "PassphraseCacheService Sending message failed", e);
}
+ } else if (ACTION_PASSPHRASE_CACHE_CLEAR.equals(intent.getAction())) {
+ AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
+
+ // Stop all ttl alarms
+ for(int i = 0; i < mPassphraseCache.size(); i++) {
+ am.cancel(buildIntent(this, mPassphraseCache.keyAt(i)));
+ }
+
+ mPassphraseCache.clear();
+
+ updateNotifications();
} else {
Log.e(Constants.TAG, "PassphraseCacheService Intent or Intent Action not supported!");
}
@@ -311,6 +345,74 @@ public class PassphraseCacheService extends Service {
Log.d(Constants.TAG, "PassphraseCacheServic No passphrases remaining in memory, stopping service!");
stopSelf();
}
+
+ updateNotifications();
+ }
+
+ private void updateNotifications() {
+ NotificationManager notificationManager =
+ (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+
+ if(mPassphraseCache.size() > 0) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
+
+ builder.setSmallIcon(R.drawable.ic_launcher)
+ .setContentTitle(getString(R.string.app_name))
+ .setContentText(String.format(getString(R.string.passp_cache_notif_n_keys), mPassphraseCache.size()));
+
+ NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
+
+ inboxStyle.setBigContentTitle(getString(R.string.passp_cache_notif_keys));
+
+ // Moves events into the big view
+ for (int i = 0; i < mPassphraseCache.size(); i++) {
+ inboxStyle.addLine(mPassphraseCache.valueAt(i).getPrimaryUserID());
+ }
+
+ // Moves the big view style object into the notification object.
+ builder.setStyle(inboxStyle);
+
+ // Add purging action
+ Intent intent = new Intent(getApplicationContext(), PassphraseCacheService.class);
+ intent.setAction(ACTION_PASSPHRASE_CACHE_CLEAR);
+ builder.addAction(
+ R.drawable.abc_ic_clear_normal,
+ getString(R.string.passp_cache_notif_clear),
+ PendingIntent.getService(
+ getApplicationContext(),
+ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ )
+ );
+
+ notificationManager.notify(NOTIFICATION_ID, builder.build());
+ } else { // Fallback, since expandable notifications weren't available back then
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
+
+ builder.setSmallIcon(R.drawable.ic_launcher)
+ .setContentTitle(String.format(getString(R.string.passp_cache_notif_n_keys, mPassphraseCache.size())))
+ .setContentText(getString(R.string.passp_cache_notif_click_to_clear));
+
+ Intent intent = new Intent(getApplicationContext(), PassphraseCacheService.class);
+ intent.setAction(ACTION_PASSPHRASE_CACHE_CLEAR);
+
+ builder.setContentIntent(
+ PendingIntent.getService(
+ getApplicationContext(),
+ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ )
+ );
+
+ notificationManager.notify(NOTIFICATION_ID, builder.build());
+ }
+
+ } else {
+ notificationManager.cancel(NOTIFICATION_ID);
+ }
}
@Override
@@ -341,4 +443,27 @@ public class PassphraseCacheService extends Service {
private final IBinder mBinder = new PassphraseCacheBinder();
-}
+ public class CachedPassphrase {
+ private String primaryUserID;
+ private String passphrase;
+
+ public CachedPassphrase(String passphrase, String primaryUserID) {
+ setPassphrase(passphrase);
+ setPrimaryUserID(primaryUserID);
+ }
+
+ public String getPrimaryUserID() {
+ return primaryUserID;
+ }
+ public String getPassphrase() {
+ return passphrase;
+ }
+
+ public void setPrimaryUserID(String primaryUserID) {
+ this.primaryUserID = primaryUserID;
+ }
+ public void setPassphrase(String passphrase) {
+ this.passphrase = passphrase;
+ }
+ }
+} \ No newline at end of file