mirror of
https://github.com/moparisthebest/open-keychain
synced 2025-01-31 23:20:20 -05:00
completly new PasswordCacheService (more energy efficient), reworked Password dialogs
This commit is contained in:
parent
be49597882
commit
4b8400685a
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -49,7 +50,7 @@
|
||||
android:theme="@style/Theme.Sherlock.Light.ForceOverflow" >
|
||||
<activity
|
||||
android:name=".ui.MainActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@ -59,7 +60,7 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.PublicKeyListActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_managePublicKeys"
|
||||
android:launchMode="singleTop"
|
||||
android:uiOptions="splitActionBarWhenNarrow" >
|
||||
@ -73,7 +74,7 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.SecretKeyListActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_manageSecretKeys"
|
||||
android:launchMode="singleTop"
|
||||
android:uiOptions="splitActionBarWhenNarrow" >
|
||||
@ -87,7 +88,7 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.EditKeyActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_editKey"
|
||||
android:uiOptions="splitActionBarWhenNarrow"
|
||||
android:windowSoftInputMode="stateHidden" >
|
||||
@ -100,7 +101,7 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.SelectPublicKeyListActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_selectRecipients"
|
||||
android:launchMode="singleTop"
|
||||
android:uiOptions="splitActionBarWhenNarrow" >
|
||||
@ -119,7 +120,7 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.SelectSecretKeyListActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_selectSignature"
|
||||
android:launchMode="singleTop" >
|
||||
<intent-filter>
|
||||
@ -137,7 +138,7 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.EncryptActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_encrypt"
|
||||
android:uiOptions="splitActionBarWhenNarrow"
|
||||
android:windowSoftInputMode="stateHidden" >
|
||||
@ -154,7 +155,7 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.DecryptActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_decrypt"
|
||||
android:uiOptions="splitActionBarWhenNarrow"
|
||||
android:windowSoftInputMode="stateHidden" >
|
||||
@ -170,7 +171,7 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".deprecated.GeneralActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Dialog" >
|
||||
<intent-filter>
|
||||
@ -202,39 +203,39 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.MailListActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_mailInbox" />
|
||||
<activity
|
||||
android:name=".ui.KeyServerQueryActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_keyServerQuery" />
|
||||
<activity
|
||||
android:name=".ui.KeyServerUploadActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_sendKey" />
|
||||
<activity
|
||||
android:name=".ui.PreferencesActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_preferences" />
|
||||
<activity
|
||||
android:name=".ui.PreferencesKeyServerActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_keyServerPreference"
|
||||
android:uiOptions="splitActionBarWhenNarrow"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
<activity
|
||||
android:name=".ui.SignKeyActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_signKey" />
|
||||
<activity
|
||||
android:name=".ui.ImportFromQRCodeActivity"
|
||||
android:configChanges="keyboardHidden|orientation|keyboard"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_importFromQRCode" />
|
||||
<activity
|
||||
android:name=".ui.HelpActivity"
|
||||
android:label="@string/title_help" />
|
||||
|
||||
<service android:name=".service.password.PassphraseCacheService" />
|
||||
<service android:name=".service.PassphraseCacheService" />
|
||||
<service android:name=".service.ApgService" />
|
||||
|
||||
<!-- TODO: need to be moved into new service model -->
|
||||
|
@ -33,6 +33,7 @@
|
||||
android:id="@+id/passphrase_passphrase"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="textPassword"
|
||||
android:padding="4dp" />
|
||||
|
||||
|
@ -54,6 +54,7 @@
|
||||
android:id="@+id/passphrase_passphrase_again"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="textPassword"
|
||||
android:padding="4dp" />
|
||||
</TableRow>
|
||||
|
@ -38,7 +38,8 @@ public class ApgApplication extends Application {
|
||||
super.onCreate();
|
||||
|
||||
/* Start passphrase cache service */
|
||||
PassphraseCacheService.startCacheService(this);
|
||||
// TODO: not needed anymore!
|
||||
// PassphraseCacheService.startCacheService(this);
|
||||
|
||||
// TODO: Do it better than this!
|
||||
// this initializes the database to be used in PGPMain
|
||||
|
@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.thialfihar.android.apg.deprecated;
|
||||
|
||||
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.spongycastle.openpgp.PGPException;
|
||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.thialfihar.android.apg.Id;
|
||||
import org.thialfihar.android.apg.R;
|
||||
import org.thialfihar.android.apg.helper.PGPHelper;
|
||||
import org.thialfihar.android.apg.helper.PGPMain;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import org.thialfihar.android.apg.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* - Use new PassphraseDialogFragment!
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class AskForPassphrase {
|
||||
public static interface PassPhraseCallbackInterface {
|
||||
void passPhraseCallback(long keyId, String passPhrase);
|
||||
}
|
||||
|
||||
public static Dialog createDialog(Activity context, long secretKeyId,
|
||||
PassPhraseCallbackInterface callback) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(context);
|
||||
|
||||
alert.setTitle(R.string.title_authentication);
|
||||
|
||||
final PGPSecretKey secretKey;
|
||||
final Activity activity = context;
|
||||
|
||||
if (secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none) {
|
||||
secretKey = null;
|
||||
alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption));
|
||||
} else {
|
||||
secretKey = PGPHelper.getMasterKey(PGPMain.getSecretKeyRing(secretKeyId));
|
||||
if (secretKey == null) {
|
||||
alert.setTitle(R.string.title_keyNotFound);
|
||||
alert.setMessage(context.getString(R.string.keyNotFound, secretKeyId));
|
||||
alert.setPositiveButton(android.R.string.ok, new OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
activity.removeDialog(Id.dialog.pass_phrase);
|
||||
}
|
||||
});
|
||||
alert.setCancelable(false);
|
||||
return alert.create();
|
||||
}
|
||||
String userId = PGPHelper.getMainUserIdSafe(context, secretKey);
|
||||
alert.setMessage(context.getString(R.string.passPhraseFor, userId));
|
||||
}
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View view = inflater.inflate(R.layout.passphrase, null);
|
||||
final EditText input = (EditText) view.findViewById(R.id.passphrase_passphrase);
|
||||
|
||||
final TextView labelNotUsed = (TextView) view
|
||||
.findViewById(R.id.passphrase_label_passphrase_again);
|
||||
labelNotUsed.setVisibility(View.GONE);
|
||||
final EditText inputNotUsed = (EditText) view
|
||||
.findViewById(R.id.passphrase_passphrase_again);
|
||||
inputNotUsed.setVisibility(View.GONE);
|
||||
|
||||
alert.setView(view);
|
||||
|
||||
final PassPhraseCallbackInterface cb = callback;
|
||||
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
activity.removeDialog(Id.dialog.pass_phrase);
|
||||
String passPhrase = input.getText().toString();
|
||||
long keyId;
|
||||
if (secretKey != null) {
|
||||
try {
|
||||
PGPPrivateKey testKey = secretKey.extractPrivateKey(
|
||||
passPhrase.toCharArray(), new BouncyCastleProvider());
|
||||
if (testKey == null) {
|
||||
Toast.makeText(activity, R.string.error_couldNotExtractPrivateKey,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
} catch (PGPException e) {
|
||||
Toast.makeText(activity, R.string.wrongPassPhrase, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
keyId = secretKey.getKeyID();
|
||||
} else {
|
||||
keyId = Id.key.symmetric;
|
||||
}
|
||||
|
||||
// cache again
|
||||
PGPMain.setCachedPassPhrase(keyId, passPhrase);
|
||||
// return by callback
|
||||
cb.passPhraseCallback(keyId, passPhrase);
|
||||
}
|
||||
});
|
||||
|
||||
alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
activity.removeDialog(Id.dialog.pass_phrase);
|
||||
}
|
||||
});
|
||||
|
||||
// check if the key has no passphrase
|
||||
if (secretKey != null) {
|
||||
try {
|
||||
Log.d("APG", "check if key has no passphrase...");
|
||||
PGPPrivateKey testKey = secretKey.extractPrivateKey("".toCharArray(),
|
||||
new BouncyCastleProvider());
|
||||
if (testKey != null) {
|
||||
Log.d("APG", "Key has no passphrase!");
|
||||
|
||||
// cache null
|
||||
PGPMain.setCachedPassPhrase(secretKey.getKeyID(), null);
|
||||
// return by callback
|
||||
cb.passPhraseCallback(secretKey.getKeyID(), null);
|
||||
|
||||
return null;
|
||||
}
|
||||
} catch (PGPException e) {
|
||||
|
||||
}
|
||||
}
|
||||
return alert.create();
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ import android.os.Handler;
|
||||
import android.os.Message;
|
||||
|
||||
public class BaseActivity extends SherlockFragmentActivity implements Runnable,
|
||||
ProgressDialogUpdater, AskForPassphrase.PassPhraseCallbackInterface {
|
||||
ProgressDialogUpdater {
|
||||
|
||||
private ProgressDialog mProgressDialog = null;
|
||||
// private PausableThread mRunningThread = null;
|
||||
@ -363,11 +363,11 @@ public class BaseActivity extends SherlockFragmentActivity implements Runnable,
|
||||
//
|
||||
// Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
||||
// }
|
||||
|
||||
public void passPhraseCallback(long keyId, String passPhrase) {
|
||||
// TODO: Not needed anymore, now implemented in AskForSecretKeyPass
|
||||
PGPMain.setCachedPassPhrase(keyId, passPhrase);
|
||||
}
|
||||
//
|
||||
// public void passPhraseCallback(long keyId, String passPhrase) {
|
||||
// // TODO: Not needed anymore, now implemented in AskForSecretKeyPass
|
||||
// PGPMain.setCachedPassPhrase(keyId, passPhrase);
|
||||
// }
|
||||
|
||||
// public void sendMessage(Message msg) {
|
||||
// mHandler.sendMessage(msg);
|
||||
|
@ -78,7 +78,6 @@ import org.thialfihar.android.apg.provider.KeyRings;
|
||||
import org.thialfihar.android.apg.provider.Keys;
|
||||
import org.thialfihar.android.apg.provider.UserIds;
|
||||
import org.thialfihar.android.apg.service.ApgService;
|
||||
import org.thialfihar.android.apg.service.CachedPassphrase;
|
||||
import org.thialfihar.android.apg.util.HkpKeyServer;
|
||||
import org.thialfihar.android.apg.util.InputData;
|
||||
import org.thialfihar.android.apg.util.PositionAwareInputStream;
|
||||
@ -121,9 +120,7 @@ import java.security.Security;
|
||||
import java.security.SignatureException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -185,7 +182,6 @@ public class PGPMain {
|
||||
".*?(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----).*",
|
||||
Pattern.DOTALL);
|
||||
|
||||
private static HashMap<Long, CachedPassphrase> mPassPhraseCache = new HashMap<Long, CachedPassphrase>();
|
||||
private static String mEditPassPhrase = null;
|
||||
|
||||
private static Database mDatabase = null;
|
||||
@ -224,58 +220,6 @@ public class PGPMain {
|
||||
return mEditPassPhrase;
|
||||
}
|
||||
|
||||
public static void setCachedPassPhrase(long keyId, String passPhrase) {
|
||||
mPassPhraseCache.put(keyId, new CachedPassphrase(new Date().getTime(), passPhrase));
|
||||
}
|
||||
|
||||
public static String getCachedPassPhrase(long keyId) {
|
||||
long realId = keyId;
|
||||
if (realId != Id.key.symmetric) {
|
||||
PGPSecretKeyRing keyRing = getSecretKeyRing(keyId);
|
||||
if (keyRing == null) {
|
||||
return null;
|
||||
}
|
||||
PGPSecretKey masterKey = PGPHelper.getMasterKey(keyRing);
|
||||
if (masterKey == null) {
|
||||
return null;
|
||||
}
|
||||
realId = masterKey.getKeyID();
|
||||
}
|
||||
CachedPassphrase cpp = mPassPhraseCache.get(realId);
|
||||
if (cpp == null) {
|
||||
return null;
|
||||
}
|
||||
// set it again to reset the cache life cycle
|
||||
setCachedPassPhrase(realId, cpp.passPhrase);
|
||||
return cpp.passPhrase;
|
||||
}
|
||||
|
||||
public static int cleanUpCache(int ttl, int initialDelay) {
|
||||
int delay = initialDelay;
|
||||
long realTtl = ttl * 1000;
|
||||
long now = new Date().getTime();
|
||||
Vector<Long> oldKeys = new Vector<Long>();
|
||||
for (Map.Entry<Long, CachedPassphrase> pair : mPassPhraseCache.entrySet()) {
|
||||
long lived = now - pair.getValue().timestamp;
|
||||
if (lived >= realTtl) {
|
||||
oldKeys.add(pair.getKey());
|
||||
} else {
|
||||
// see, whether the remaining time for this cache entry improves our
|
||||
// check delay
|
||||
long nextCheck = realTtl - lived + 1000;
|
||||
if (nextCheck < delay) {
|
||||
delay = (int) nextCheck;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (long keyId : oldKeys) {
|
||||
mPassPhraseCache.remove(keyId);
|
||||
}
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new secret key. The returned PGPSecretKeyRing contains only one newly generated key
|
||||
* when this key is the new masterkey. If a masterkey is supplied in the parameters
|
||||
@ -1268,11 +1212,10 @@ public class PGPMain {
|
||||
progress.setProgress(R.string.progress_done, 100, 100);
|
||||
}
|
||||
|
||||
public static PGPPublicKeyRing signKey(Context context, long masterKeyId, long pubKeyId)
|
||||
throws GeneralException, NoSuchAlgorithmException, NoSuchProviderException,
|
||||
PGPException, SignatureException {
|
||||
String signaturePassPhrase = PGPMain.getCachedPassPhrase(masterKeyId);
|
||||
if (signaturePassPhrase == null || signaturePassPhrase.length() <= 0) {
|
||||
public static PGPPublicKeyRing signKey(Context context, long masterKeyId, long pubKeyId,
|
||||
String passphrase) throws GeneralException, NoSuchAlgorithmException,
|
||||
NoSuchProviderException, PGPException, SignatureException {
|
||||
if (passphrase == null || passphrase.length() <= 0) {
|
||||
throw new GeneralException("Unable to obtain passphrase");
|
||||
} else {
|
||||
PGPPublicKeyRing pubring = PGPMain.getPublicKeyRing(pubKeyId);
|
||||
@ -1283,7 +1226,7 @@ public class PGPMain {
|
||||
}
|
||||
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||
BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassPhrase.toCharArray());
|
||||
BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
|
||||
PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
|
||||
if (signaturePrivateKey == null) {
|
||||
throw new GeneralException(
|
||||
|
@ -70,6 +70,25 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
|
||||
public static final String EXTRA_ACTION = "action";
|
||||
public static final String EXTRA_DATA = "data";
|
||||
|
||||
/* possible EXTRA_ACTIONs */
|
||||
public static final int ACTION_ENCRYPT_SIGN = 10;
|
||||
|
||||
public static final int ACTION_DECRYPT_VERIFY = 20;
|
||||
|
||||
public static final int ACTION_SAVE_KEYRING = 30;
|
||||
public static final int ACTION_GENERATE_KEY = 31;
|
||||
public static final int ACTION_GENERATE_DEFAULT_RSA_KEYS = 32;
|
||||
|
||||
public static final int ACTION_DELETE_FILE_SECURELY = 40;
|
||||
|
||||
public static final int ACTION_IMPORT_KEY = 50;
|
||||
public static final int ACTION_EXPORT_KEY = 51;
|
||||
|
||||
public static final int ACTION_UPLOAD_KEY = 60;
|
||||
public static final int ACTION_QUERY_KEY = 61;
|
||||
|
||||
public static final int ACTION_SIGN_KEY = 70;
|
||||
|
||||
/* keys for data bundle */
|
||||
|
||||
// encrypt, decrypt, import export
|
||||
@ -143,25 +162,6 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
|
||||
public static final String SIGN_KEY_MASTER_KEY_ID = "signKeyMasterKeyId";
|
||||
public static final String SIGN_KEY_PUB_KEY_ID = "signKeyPubKeyId";
|
||||
|
||||
/* possible EXTRA_ACTIONs */
|
||||
public static final int ACTION_ENCRYPT_SIGN = 10;
|
||||
|
||||
public static final int ACTION_DECRYPT_VERIFY = 20;
|
||||
|
||||
public static final int ACTION_SAVE_KEYRING = 30;
|
||||
public static final int ACTION_GENERATE_KEY = 31;
|
||||
public static final int ACTION_GENERATE_DEFAULT_RSA_KEYS = 32;
|
||||
|
||||
public static final int ACTION_DELETE_FILE_SECURELY = 40;
|
||||
|
||||
public static final int ACTION_IMPORT_KEY = 50;
|
||||
public static final int ACTION_EXPORT_KEY = 51;
|
||||
|
||||
public static final int ACTION_UPLOAD_KEY = 60;
|
||||
public static final int ACTION_QUERY_KEY = 61;
|
||||
|
||||
public static final int ACTION_SIGN_KEY = 70;
|
||||
|
||||
/* possible data keys as result send over messenger */
|
||||
// keys
|
||||
public static final String RESULT_NEW_KEY = "newKey";
|
||||
@ -320,19 +320,21 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
|
||||
if (generateSignature) {
|
||||
Log.d(Constants.TAG, "generating signature...");
|
||||
PGPMain.generateSignature(this, inputData, outStream, useAsciiArmour, false,
|
||||
secretKeyId, PGPMain.getCachedPassPhrase(secretKeyId), Preferences
|
||||
.getPreferences(this).getDefaultHashAlgorithm(), Preferences
|
||||
.getPreferences(this).getForceV3Signatures(), this);
|
||||
secretKeyId, PassphraseCacheService.getCachedPassphrase(this,
|
||||
secretKeyId), Preferences.getPreferences(this)
|
||||
.getDefaultHashAlgorithm(), Preferences.getPreferences(this)
|
||||
.getForceV3Signatures(), this);
|
||||
} else if (signOnly) {
|
||||
Log.d(Constants.TAG, "sign only...");
|
||||
PGPMain.signText(this, inputData, outStream, secretKeyId, PGPMain
|
||||
.getCachedPassPhrase(secretKeyId), Preferences.getPreferences(this)
|
||||
.getDefaultHashAlgorithm(), Preferences.getPreferences(this)
|
||||
.getForceV3Signatures(), this);
|
||||
PGPMain.signText(this, inputData, outStream, secretKeyId,
|
||||
PassphraseCacheService.getCachedPassphrase(this, secretKeyId),
|
||||
Preferences.getPreferences(this).getDefaultHashAlgorithm(), Preferences
|
||||
.getPreferences(this).getForceV3Signatures(), this);
|
||||
} else {
|
||||
Log.d(Constants.TAG, "encrypt...");
|
||||
PGPMain.encrypt(this, inputData, outStream, useAsciiArmour, encryptionKeyIds,
|
||||
signatureKeyId, PGPMain.getCachedPassPhrase(signatureKeyId), this,
|
||||
signatureKeyId,
|
||||
PassphraseCacheService.getCachedPassphrase(this, signatureKeyId), this,
|
||||
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm(),
|
||||
Preferences.getPreferences(this).getDefaultHashAlgorithm(),
|
||||
compressionId, Preferences.getPreferences(this).getForceV3Signatures(),
|
||||
@ -478,7 +480,7 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
|
||||
this);
|
||||
} else {
|
||||
resultData = PGPMain.decrypt(this, inputData, outStream,
|
||||
PGPMain.getCachedPassPhrase(secretKeyId), this,
|
||||
PassphraseCacheService.getCachedPassphrase(this, secretKeyId), this,
|
||||
assumeSymmetricEncryption);
|
||||
}
|
||||
|
||||
@ -539,7 +541,7 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
|
||||
/* Operation */
|
||||
PGPMain.buildSecretKey(this, userIds, keys, keysUsages, masterKeyId, oldPassPhrase,
|
||||
newPassPhrase, this);
|
||||
PGPMain.setCachedPassPhrase(masterKeyId, newPassPhrase);
|
||||
PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassPhrase);
|
||||
|
||||
/* Output */
|
||||
sendMessageToHandler(ApgServiceHandler.MESSAGE_OKAY);
|
||||
@ -798,7 +800,11 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
|
||||
long pubKeyId = data.getLong(SIGN_KEY_PUB_KEY_ID);
|
||||
|
||||
/* Operation */
|
||||
PGPPublicKeyRing signedPubKeyRing = PGPMain.signKey(this, masterKeyId, pubKeyId);
|
||||
String signaturePassPhrase = PassphraseCacheService.getCachedPassphrase(this,
|
||||
masterKeyId);
|
||||
|
||||
PGPPublicKeyRing signedPubKeyRing = PGPMain.signKey(this, masterKeyId, pubKeyId,
|
||||
signaturePassPhrase);
|
||||
|
||||
// store the signed key in our local cache
|
||||
int retval = PGPMain.storeKeyRingInCache(signedPubKeyRing);
|
||||
|
@ -15,19 +15,27 @@
|
||||
package org.thialfihar.android.apg.service;
|
||||
|
||||
public class CachedPassphrase {
|
||||
public final long timestamp;
|
||||
public final String passPhrase;
|
||||
private final long timestamp;
|
||||
private final String passphrase;
|
||||
|
||||
public CachedPassphrase(long timestamp, String passPhrase) {
|
||||
super();
|
||||
this.timestamp = timestamp;
|
||||
this.passPhrase = passPhrase;
|
||||
this.passphrase = passPhrase;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public String getPassphrase() {
|
||||
return passphrase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc1 = (int) (this.timestamp & 0xffffffff);
|
||||
int hc2 = (this.passPhrase == null ? 0 : this.passPhrase.hashCode());
|
||||
int hc2 = (this.passphrase == null ? 0 : this.passphrase.hashCode());
|
||||
return (hc1 + hc2) * hc2 + hc1;
|
||||
}
|
||||
|
||||
@ -42,12 +50,12 @@ public class CachedPassphrase {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (passPhrase != o.passPhrase) {
|
||||
if (passPhrase == null || o.passPhrase == null) {
|
||||
if (passphrase != o.passphrase) {
|
||||
if (passphrase == null || o.passphrase == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!passPhrase.equals(o.passPhrase)) {
|
||||
if (!passphrase.equals(o.passphrase)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
@ -14,90 +16,211 @@
|
||||
|
||||
package org.thialfihar.android.apg.service;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.thialfihar.android.apg.Constants;
|
||||
import org.thialfihar.android.apg.Id;
|
||||
import org.thialfihar.android.apg.helper.PGPHelper;
|
||||
import org.thialfihar.android.apg.helper.PGPMain;
|
||||
import org.thialfihar.android.apg.helper.Preferences;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.Log;
|
||||
|
||||
public class PassphraseCacheService extends Service {
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
public static final String BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE = Constants.INTENT_PREFIX
|
||||
+ "PASSPHRASE_CACHE_SERVICE";
|
||||
|
||||
public static final String EXTRA_TTL = "ttl";
|
||||
public static final String EXTRA_KEY_ID = "keyId";
|
||||
public static final String EXTRA_PASSPHRASE = "passphrase";
|
||||
|
||||
private static final int REQUEST_ID = 0;
|
||||
private static final long DEFAULT_TTL = 15;
|
||||
|
||||
private BroadcastReceiver mIntentReceiver;
|
||||
|
||||
// TODO: This is static to be easily retrieved by getCachedPassphrase()
|
||||
// To avoid static we would need a messenger from the service back to the activity?
|
||||
private static HashMap<Long, CachedPassphrase> mPassphraseCache = new HashMap<Long, CachedPassphrase>();
|
||||
|
||||
/**
|
||||
* This caches a new passphrase by sending a new command to the service. An android service is
|
||||
* only run once. Thus when it is already started new commands just add new BroadcastReceivers
|
||||
* for cached passphrases
|
||||
*
|
||||
* @param context
|
||||
* @param keyId
|
||||
* @param passphrase
|
||||
*/
|
||||
public static void addCachedPassphrase(Context context, long keyId, String passphrase) {
|
||||
Log.d(Constants.TAG, "cacheNewPassphrase() for " + keyId);
|
||||
|
||||
public static void startCacheService(Context context) {
|
||||
Intent intent = new Intent(context, PassphraseCacheService.class);
|
||||
intent.putExtra(PassphraseCacheService.EXTRA_TTL, Preferences.getPreferences(context).getPassPhraseCacheTtl());
|
||||
intent.putExtra(EXTRA_TTL, Preferences.getPreferences(context).getPassPhraseCacheTtl());
|
||||
intent.putExtra(EXTRA_PASSPHRASE, passphrase);
|
||||
intent.putExtra(EXTRA_KEY_ID, keyId);
|
||||
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
private int mPassPhraseCacheTtl = 15;
|
||||
private Handler mCacheHandler = new Handler();
|
||||
private Runnable mCacheTask = new Runnable() {
|
||||
public void run() {
|
||||
// check every ttl/2 seconds, which shouldn't be heavy on the device (even if ttl = 15),
|
||||
// and makes sure the longest a pass phrase survives in the cache is 1.5 * ttl
|
||||
int delay = mPassPhraseCacheTtl * 1000 / 2;
|
||||
// also make sure the delay is not longer than one minute
|
||||
if (delay > 60000) {
|
||||
delay = 60000;
|
||||
/**
|
||||
* Gets a cached passphrase from memory
|
||||
*
|
||||
* @param context
|
||||
* @param keyId
|
||||
* @return
|
||||
*/
|
||||
public static String getCachedPassphrase(Context context, long keyId) {
|
||||
// try to get real key id
|
||||
long realId = keyId;
|
||||
if (realId != Id.key.symmetric) {
|
||||
PGPSecretKeyRing keyRing = PGPMain.getSecretKeyRing(keyId);
|
||||
if (keyRing == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
delay = PGPMain.cleanUpCache(mPassPhraseCacheTtl, delay);
|
||||
// don't check too often, even if we were close
|
||||
if (delay < 5000) {
|
||||
delay = 5000;
|
||||
PGPSecretKey masterKey = PGPHelper.getMasterKey(keyRing);
|
||||
if (masterKey == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
mCacheHandler.postDelayed(this, delay);
|
||||
realId = masterKey.getKeyID();
|
||||
}
|
||||
};
|
||||
|
||||
static private boolean mIsRunning = false;
|
||||
// get cached passphrase
|
||||
CachedPassphrase cpp = mPassphraseCache.get(realId);
|
||||
if (cpp == null) {
|
||||
return null;
|
||||
}
|
||||
// set it again to reset the cache life cycle
|
||||
addCachedPassphrase(context, realId, cpp.getPassphrase());
|
||||
|
||||
return cpp.getPassphrase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register BroadcastReceiver that is unregistered when service is destroyed. This
|
||||
* BroadcastReceiver hears on intents with ACTION_PASSPHRASE_CACHE_SERVICE to timeout
|
||||
* passphrases in memory.
|
||||
*/
|
||||
private void registerReceiver() {
|
||||
if (mIntentReceiver == null) {
|
||||
mIntentReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
|
||||
if (action.equals(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE)) {
|
||||
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
|
||||
timeout(context, keyId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE);
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(mIntentReceiver, filter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build pending intent that is executed by alarm manager when one passphrase times out
|
||||
*
|
||||
* @param context
|
||||
* @param keyId
|
||||
* @return
|
||||
*/
|
||||
private static PendingIntent buildIntent(Context context, long keyId) {
|
||||
Intent intent = new Intent(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE);
|
||||
intent.putExtra(EXTRA_KEY_ID, keyId);
|
||||
PendingIntent sender = PendingIntent.getBroadcast(context, REQUEST_ID, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
||||
return sender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Log.d(Constants.TAG, "PassphraseCacheService created!");
|
||||
}
|
||||
|
||||
mIsRunning = true;
|
||||
/**
|
||||
* Executed when service is started by intent
|
||||
*/
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Log.d(Constants.TAG, "PassphraseCacheService started");
|
||||
|
||||
// register broadcastreceiver
|
||||
registerReceiver();
|
||||
|
||||
if (intent != null) {
|
||||
long ttl = intent.getLongExtra(EXTRA_TTL, DEFAULT_TTL);
|
||||
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
|
||||
String passphrase = intent.getStringExtra(EXTRA_PASSPHRASE);
|
||||
|
||||
Log.d(Constants.TAG, "received intent with keyId: " + keyId + ", ttl: " + ttl);
|
||||
|
||||
// add keyId and passphrase to memory
|
||||
mPassphraseCache.put(keyId,
|
||||
new CachedPassphrase(System.currentTimeMillis(), passphrase));
|
||||
|
||||
// register new alarm with keyId for this passphrase
|
||||
long triggerTime = System.currentTimeMillis() + ttl;
|
||||
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
|
||||
am.set(AlarmManager.RTC_WAKEUP, triggerTime, buildIntent(this, keyId));
|
||||
}
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when one specific passphrase for keyId timed out
|
||||
*
|
||||
* @param context
|
||||
* @param keyId
|
||||
*/
|
||||
private void timeout(Context context, long keyId) {
|
||||
Log.d(Constants.TAG, "Timeout of " + keyId);
|
||||
|
||||
// remove passphrase corresponding to keyId from memory
|
||||
mPassphraseCache.remove(keyId);
|
||||
|
||||
// stop whole service if no cached passphrases remaining
|
||||
if (mPassphraseCache.isEmpty()) {
|
||||
Log.d(Constants.TAG, "No passphrases remaining in memory, stopping service!");
|
||||
stopSelf();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mIsRunning = false;
|
||||
Log.d(Constants.TAG, "PassphraseCacheService destroyed!");
|
||||
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mIntentReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(Intent intent, int startId) {
|
||||
super.onStart(intent, startId);
|
||||
|
||||
if (intent != null) {
|
||||
mPassPhraseCacheTtl = intent.getIntExtra(EXTRA_TTL, 15);
|
||||
}
|
||||
if (mPassPhraseCacheTtl < 15) {
|
||||
mPassPhraseCacheTtl = 15;
|
||||
}
|
||||
mCacheHandler.removeCallbacks(mCacheTask);
|
||||
mCacheHandler.postDelayed(mCacheTask, 1000);
|
||||
}
|
||||
|
||||
static public boolean isRunning() {
|
||||
return mIsRunning;
|
||||
}
|
||||
|
||||
public class LocalBinder extends Binder {
|
||||
PassphraseCacheService getService() {
|
||||
public class PassphraseCacheBinder extends Binder {
|
||||
public PassphraseCacheService getService() {
|
||||
return PassphraseCacheService.this;
|
||||
}
|
||||
}
|
||||
|
||||
private final IBinder mBinder = new PassphraseCacheBinder();
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -25,6 +25,7 @@ import org.thialfihar.android.apg.helper.PGPHelper;
|
||||
import org.thialfihar.android.apg.helper.PGPMain;
|
||||
import org.thialfihar.android.apg.service.ApgServiceHandler;
|
||||
import org.thialfihar.android.apg.service.ApgService;
|
||||
import org.thialfihar.android.apg.service.PassphraseCacheService;
|
||||
import org.thialfihar.android.apg.ui.dialog.DeleteFileDialogFragment;
|
||||
import org.thialfihar.android.apg.ui.dialog.FileDialogFragment;
|
||||
import org.thialfihar.android.apg.ui.dialog.LookupUnknownKeyDialogFragment;
|
||||
@ -513,7 +514,7 @@ public class DecryptActivity extends SherlockFragmentActivity {
|
||||
|
||||
// if we need a symmetric passphrase or a passphrase to use a secret key ask for it
|
||||
if (getSecretKeyId() == Id.key.symmetric
|
||||
|| PGPMain.getCachedPassPhrase(getSecretKeyId()) == null) {
|
||||
|| PassphraseCacheService.getCachedPassphrase(this, getSecretKeyId()) == null) {
|
||||
showPassphraseDialog();
|
||||
} else {
|
||||
if (mDecryptTarget == Id.target.file) {
|
||||
@ -548,7 +549,7 @@ public class DecryptActivity extends SherlockFragmentActivity {
|
||||
Messenger messenger = new Messenger(returnHandler);
|
||||
|
||||
try {
|
||||
PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(
|
||||
PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(this,
|
||||
messenger, mSecretKeyId);
|
||||
|
||||
passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog");
|
||||
|
@ -30,6 +30,7 @@ import org.thialfihar.android.apg.helper.PGPMain;
|
||||
import org.thialfihar.android.apg.helper.Preferences;
|
||||
import org.thialfihar.android.apg.service.ApgServiceHandler;
|
||||
import org.thialfihar.android.apg.service.ApgService;
|
||||
import org.thialfihar.android.apg.service.PassphraseCacheService;
|
||||
import org.thialfihar.android.apg.ui.dialog.DeleteFileDialogFragment;
|
||||
import org.thialfihar.android.apg.ui.dialog.FileDialogFragment;
|
||||
import org.thialfihar.android.apg.ui.dialog.PassphraseDialogFragment;
|
||||
@ -659,7 +660,8 @@ public class EncryptActivity extends SherlockFragmentActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getSecretKeyId() != 0 && PGPMain.getCachedPassPhrase(getSecretKeyId()) == null) {
|
||||
if (getSecretKeyId() != 0
|
||||
&& PassphraseCacheService.getCachedPassphrase(this, getSecretKeyId()) == null) {
|
||||
showPassphraseDialog();
|
||||
|
||||
return;
|
||||
@ -697,7 +699,7 @@ public class EncryptActivity extends SherlockFragmentActivity {
|
||||
|
||||
try {
|
||||
PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(
|
||||
messenger, mSecretKeyId);
|
||||
EncryptActivity.this, messenger, mSecretKeyId);
|
||||
|
||||
passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog");
|
||||
} catch (PGPMain.GeneralException e) {
|
||||
|
@ -69,7 +69,8 @@ public class PreferencesActivity extends SherlockPreferenceActivity {
|
||||
mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString()));
|
||||
|
||||
// restart cache service with new ttl
|
||||
PassphraseCacheService.startCacheService(PreferencesActivity.this);
|
||||
// TODO: not needed anymore!
|
||||
// PassphraseCacheService.startCacheService(PreferencesActivity.this);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
@ -21,6 +21,7 @@ import org.thialfihar.android.apg.Constants;
|
||||
import org.thialfihar.android.apg.Id;
|
||||
import org.thialfihar.android.apg.helper.PGPHelper;
|
||||
import org.thialfihar.android.apg.helper.PGPMain;
|
||||
import org.thialfihar.android.apg.service.PassphraseCacheService;
|
||||
import org.thialfihar.android.apg.ui.dialog.PassphraseDialogFragment;
|
||||
import org.thialfihar.android.apg.util.Log;
|
||||
|
||||
@ -137,7 +138,7 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli
|
||||
|
||||
public void checkPassPhraseAndEdit() {
|
||||
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
|
||||
String passPhrase = PGPMain.getCachedPassPhrase(keyId);
|
||||
String passPhrase = PassphraseCacheService.getCachedPassphrase(this, keyId);
|
||||
if (passPhrase == null) {
|
||||
showPassphraseDialog(keyId);
|
||||
} else {
|
||||
@ -152,7 +153,8 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli
|
||||
@Override
|
||||
public void handleMessage(Message message) {
|
||||
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
|
||||
String passPhrase = PGPMain.getCachedPassPhrase(secretKeyId);
|
||||
String passPhrase = PassphraseCacheService.getCachedPassphrase(
|
||||
SecretKeyListActivity.this, secretKeyId);
|
||||
PGPMain.setEditPassPhrase(passPhrase);
|
||||
editKey();
|
||||
}
|
||||
@ -164,7 +166,7 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli
|
||||
|
||||
try {
|
||||
PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(
|
||||
messenger, secretKeyId);
|
||||
SecretKeyListActivity.this, messenger, secretKeyId);
|
||||
|
||||
passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog");
|
||||
} catch (PGPMain.GeneralException e) {
|
||||
|
@ -27,6 +27,7 @@ import org.thialfihar.android.apg.helper.PGPMain;
|
||||
import org.thialfihar.android.apg.helper.Preferences;
|
||||
import org.thialfihar.android.apg.service.ApgService;
|
||||
import org.thialfihar.android.apg.service.ApgServiceHandler;
|
||||
import org.thialfihar.android.apg.service.PassphraseCacheService;
|
||||
import org.thialfihar.android.apg.ui.dialog.PassphraseDialogFragment;
|
||||
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
@ -141,7 +142,7 @@ public class SignKeyActivity extends SherlockFragmentActivity {
|
||||
Messenger messenger = new Messenger(returnHandler);
|
||||
|
||||
try {
|
||||
PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(
|
||||
PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(this,
|
||||
messenger, secretKeyId);
|
||||
|
||||
passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog");
|
||||
@ -175,7 +176,7 @@ public class SignKeyActivity extends SherlockFragmentActivity {
|
||||
/*
|
||||
* get the user's passphrase for this key (if required)
|
||||
*/
|
||||
String passphrase = PGPMain.getCachedPassPhrase(mMasterKeyId);
|
||||
String passphrase = PassphraseCacheService.getCachedPassphrase(this, mMasterKeyId);
|
||||
if (passphrase == null) {
|
||||
showPassphraseDialog(mMasterKeyId);
|
||||
return; // bail out; need to wait until the user has entered the passphrase
|
||||
|
@ -31,6 +31,7 @@ import org.thialfihar.android.apg.R;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.os.Bundle;
|
||||
@ -38,13 +39,22 @@ import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
|
||||
import org.thialfihar.android.apg.service.PassphraseCacheService;
|
||||
import org.thialfihar.android.apg.util.Log;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class PassphraseDialogFragment extends DialogFragment {
|
||||
public class PassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
|
||||
|
||||
private Messenger mMessenger;
|
||||
|
||||
@ -53,6 +63,8 @@ public class PassphraseDialogFragment extends DialogFragment {
|
||||
|
||||
public static final int MESSAGE_OKAY = 1;
|
||||
|
||||
private EditText mPassphraseEditText;
|
||||
|
||||
/**
|
||||
* Creates new instance of this dialog fragment
|
||||
*
|
||||
@ -63,11 +75,11 @@ public class PassphraseDialogFragment extends DialogFragment {
|
||||
* @return
|
||||
* @throws GeneralException
|
||||
*/
|
||||
public static PassphraseDialogFragment newInstance(Messenger messenger, long secretKeyId)
|
||||
throws GeneralException {
|
||||
public static PassphraseDialogFragment newInstance(Context context, Messenger messenger,
|
||||
long secretKeyId) throws GeneralException {
|
||||
// check if secret key has a passphrase
|
||||
if (!(secretKeyId == Id.key.symmetric || secretKeyId == Id.key.none)) {
|
||||
if (!hasPassphrase(secretKeyId)) {
|
||||
if (!hasPassphrase(context, secretKeyId)) {
|
||||
throw new PGPMain.GeneralException("No passphrase! No passphrase dialog needed!");
|
||||
}
|
||||
}
|
||||
@ -88,7 +100,7 @@ public class PassphraseDialogFragment extends DialogFragment {
|
||||
* @param secretKeyId
|
||||
* @return true if it has a passphrase
|
||||
*/
|
||||
private static boolean hasPassphrase(long secretKeyId) {
|
||||
private static boolean hasPassphrase(Context context, long secretKeyId) {
|
||||
// check if the key has no passphrase
|
||||
try {
|
||||
PGPSecretKey secretKey = PGPHelper.getMasterKey(PGPMain.getSecretKeyRing(secretKeyId));
|
||||
@ -101,7 +113,7 @@ public class PassphraseDialogFragment extends DialogFragment {
|
||||
Log.d(Constants.TAG, "Key has no passphrase! Caches empty passphrase!");
|
||||
|
||||
// cache empty passphrase
|
||||
PGPMain.setCachedPassPhrase(secretKey.getKeyID(), "");
|
||||
PassphraseCacheService.addCachedPassphrase(context, secretKey.getKeyID(), "");
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -112,6 +124,11 @@ public class PassphraseDialogFragment extends DialogFragment {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates dialog
|
||||
*/
|
||||
@ -154,13 +171,13 @@ public class PassphraseDialogFragment extends DialogFragment {
|
||||
View view = inflater.inflate(R.layout.passphrase, null);
|
||||
alert.setView(view);
|
||||
|
||||
final EditText input = (EditText) view.findViewById(R.id.passphrase_passphrase);
|
||||
mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase);
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dismiss();
|
||||
|
||||
String passPhrase = input.getText().toString();
|
||||
String passPhrase = mPassphraseEditText.getText().toString();
|
||||
long keyId;
|
||||
if (secretKey != null) {
|
||||
try {
|
||||
@ -185,7 +202,7 @@ public class PassphraseDialogFragment extends DialogFragment {
|
||||
|
||||
// cache the new passphrase
|
||||
Log.d(Constants.TAG, "Everything okay! Caching entered passphrase");
|
||||
PGPMain.setCachedPassPhrase(keyId, passPhrase);
|
||||
PassphraseCacheService.addCachedPassphrase(activity, keyId, passPhrase);
|
||||
|
||||
sendMessageToHandler(MESSAGE_OKAY);
|
||||
}
|
||||
@ -200,6 +217,32 @@ public class PassphraseDialogFragment extends DialogFragment {
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle arg0) {
|
||||
super.onActivityCreated(arg0);
|
||||
|
||||
// request focus and open soft keyboard
|
||||
mPassphraseEditText.requestFocus();
|
||||
getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||
|
||||
mPassphraseEditText.setOnEditorActionListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the "done" button on the soft keyboard with the okay button in the view
|
||||
*/
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (EditorInfo.IME_ACTION_DONE == actionId) {
|
||||
AlertDialog dialog = ((AlertDialog) getDialog());
|
||||
Button bt = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
|
||||
bt.performClick();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message back to handler which is initialized in a activity
|
||||
*
|
||||
@ -218,4 +261,5 @@ public class PassphraseDialogFragment extends DialogFragment {
|
||||
Log.w(Constants.TAG, "Messenger is null!", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -29,12 +29,19 @@ import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import org.thialfihar.android.apg.util.Log;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
|
||||
public class SetPassphraseDialogFragment extends DialogFragment {
|
||||
public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
|
||||
private Messenger mMessenger;
|
||||
|
||||
private static final String ARG_MESSENGER = "messenger";
|
||||
@ -44,6 +51,9 @@ public class SetPassphraseDialogFragment extends DialogFragment {
|
||||
|
||||
public static final String MESSAGE_NEW_PASSPHRASE = "new_passphrase";
|
||||
|
||||
private EditText mPassphraseEditText;
|
||||
private EditText mPassphraseAgainEditText;
|
||||
|
||||
/**
|
||||
* Creates new instance of this dialog fragment
|
||||
*
|
||||
@ -81,17 +91,17 @@ public class SetPassphraseDialogFragment extends DialogFragment {
|
||||
|
||||
LayoutInflater inflater = activity.getLayoutInflater();
|
||||
View view = inflater.inflate(R.layout.passphrase_repeat, null);
|
||||
final EditText input1 = (EditText) view.findViewById(R.id.passphrase_passphrase);
|
||||
final EditText input2 = (EditText) view.findViewById(R.id.passphrase_passphrase_again);
|
||||
|
||||
alert.setView(view);
|
||||
|
||||
mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase);
|
||||
mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again);
|
||||
|
||||
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dismiss();
|
||||
|
||||
String passPhrase1 = input1.getText().toString();
|
||||
String passPhrase2 = input2.getText().toString();
|
||||
String passPhrase1 = mPassphraseEditText.getText().toString();
|
||||
String passPhrase2 = mPassphraseAgainEditText.getText().toString();
|
||||
if (!passPhrase1.equals(passPhrase2)) {
|
||||
Toast.makeText(
|
||||
activity,
|
||||
@ -127,6 +137,32 @@ public class SetPassphraseDialogFragment extends DialogFragment {
|
||||
return alert.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle arg0) {
|
||||
super.onActivityCreated(arg0);
|
||||
|
||||
// request focus and open soft keyboard
|
||||
mPassphraseEditText.requestFocus();
|
||||
getDialog().getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||
|
||||
mPassphraseAgainEditText.setOnEditorActionListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the "done" button on the soft keyboard with the okay button in the view
|
||||
*/
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (EditorInfo.IME_ACTION_DONE == actionId) {
|
||||
AlertDialog dialog = ((AlertDialog) getDialog());
|
||||
Button bt = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
|
||||
bt.performClick();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message back to handler which is initialized in a activity
|
||||
*
|
||||
|
@ -23,6 +23,7 @@ import org.thialfihar.android.apg.helper.PGPMain;
|
||||
import org.thialfihar.android.apg.helper.PGPConversionHelper;
|
||||
import org.thialfihar.android.apg.service.ApgServiceHandler;
|
||||
import org.thialfihar.android.apg.service.ApgService;
|
||||
import org.thialfihar.android.apg.service.PassphraseCacheService;
|
||||
import org.thialfihar.android.apg.ui.dialog.ProgressDialogFragment;
|
||||
import org.thialfihar.android.apg.ui.widget.Editor.EditorListener;
|
||||
import org.thialfihar.android.apg.util.Choice;
|
||||
@ -259,7 +260,8 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
|
||||
String passPhrase;
|
||||
if (mEditors.getChildCount() > 0) {
|
||||
PGPSecretKey masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue();
|
||||
passPhrase = PGPMain.getCachedPassPhrase(masterKey.getKeyID());
|
||||
passPhrase = PassphraseCacheService
|
||||
.getCachedPassphrase(mActivity, masterKey.getKeyID());
|
||||
|
||||
data.putByteArray(ApgService.MASTER_KEY,
|
||||
PGPConversionHelper.PGPSecretKeyToBytes(masterKey));
|
||||
|
@ -20,7 +20,6 @@ import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
Loading…
Reference in New Issue
Block a user