mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-30 12:32:17 -05:00
Merge pull request #513 from Valodim/db-overhaul
Get everything working again after db overhaul
This commit is contained in:
commit
72ade58a7a
@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.Id;
|
import org.sufficientlysecure.keychain.Id;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||||
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||||
@ -48,22 +49,20 @@ public class ExportHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void deleteKey(Uri dataUri, Handler deleteHandler) {
|
public void deleteKey(Uri dataUri, Handler deleteHandler) {
|
||||||
long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment());
|
|
||||||
|
|
||||||
// Create a new Messenger for the communication back
|
// Create a new Messenger for the communication back
|
||||||
Messenger messenger = new Messenger(deleteHandler);
|
Messenger messenger = new Messenger(deleteHandler);
|
||||||
|
long masterKeyId = ProviderHelper.getMasterKeyId(mActivity, dataUri);
|
||||||
|
|
||||||
DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
|
DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
|
||||||
new long[]{keyRingRowId});
|
new long[]{ masterKeyId });
|
||||||
|
|
||||||
deleteKeyDialog.show(mActivity.getSupportFragmentManager(), "deleteKeyDialog");
|
deleteKeyDialog.show(mActivity.getSupportFragmentManager(), "deleteKeyDialog");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show dialog where to export keys
|
* Show dialog where to export keys
|
||||||
*/
|
*/
|
||||||
public void showExportKeysDialog(final long[] masterKeyIds, final int keyType,
|
public void showExportKeysDialog(final long[] masterKeyIds, final String exportFilename,
|
||||||
final String exportFilename, final String checkboxString) {
|
final boolean showSecretCheckbox) {
|
||||||
mExportFilename = exportFilename;
|
mExportFilename = exportFilename;
|
||||||
|
|
||||||
// Message is received after file is selected
|
// Message is received after file is selected
|
||||||
@ -72,14 +71,9 @@ public class ExportHelper {
|
|||||||
public void handleMessage(Message message) {
|
public void handleMessage(Message message) {
|
||||||
if (message.what == FileDialogFragment.MESSAGE_OKAY) {
|
if (message.what == FileDialogFragment.MESSAGE_OKAY) {
|
||||||
Bundle data = message.getData();
|
Bundle data = message.getData();
|
||||||
int type = keyType;
|
|
||||||
mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
|
mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
|
||||||
|
|
||||||
if (data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED)) {
|
exportKeys(masterKeyIds, data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED));
|
||||||
type = Id.type.public_secret_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
exportKeys(masterKeyIds, type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -99,9 +93,11 @@ public class ExportHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String message = mActivity.getString(R.string.specify_file_to_export_to);
|
String message = mActivity.getString(R.string.specify_file_to_export_to);
|
||||||
|
String checkMsg = showSecretCheckbox ?
|
||||||
|
mActivity.getString(R.string.also_export_secret_keys) : null;
|
||||||
|
|
||||||
mFileDialog = FileDialogFragment.newInstance(messenger, title, message,
|
mFileDialog = FileDialogFragment.newInstance(messenger, title, message,
|
||||||
exportFilename, checkboxString);
|
exportFilename, checkMsg);
|
||||||
|
|
||||||
mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog");
|
mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog");
|
||||||
}
|
}
|
||||||
@ -111,7 +107,7 @@ public class ExportHelper {
|
|||||||
/**
|
/**
|
||||||
* Export keys
|
* Export keys
|
||||||
*/
|
*/
|
||||||
public void exportKeys(long[] masterKeyIds, int keyType) {
|
public void exportKeys(long[] masterKeyIds, boolean exportSecret) {
|
||||||
Log.d(Constants.TAG, "exportKeys started");
|
Log.d(Constants.TAG, "exportKeys started");
|
||||||
|
|
||||||
// Send all information needed to service to export key in other thread
|
// Send all information needed to service to export key in other thread
|
||||||
@ -123,7 +119,7 @@ public class ExportHelper {
|
|||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
|
|
||||||
data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename);
|
data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename);
|
||||||
data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType);
|
data.putBoolean(KeychainIntentService.EXPORT_SECRET, exportSecret);
|
||||||
|
|
||||||
if (masterKeyIds == null) {
|
if (masterKeyIds == null) {
|
||||||
data.putBoolean(KeychainIntentService.EXPORT_ALL, true);
|
data.putBoolean(KeychainIntentService.EXPORT_ALL, true);
|
||||||
|
@ -53,6 +53,7 @@ import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactory
|
|||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
@ -66,6 +67,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.security.SignatureException;
|
import java.security.SignatureException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -232,16 +234,21 @@ public class PgpDecryptVerify {
|
|||||||
updateProgress(R.string.progress_finding_key, currentProgress, 100);
|
updateProgress(R.string.progress_finding_key, currentProgress, 100);
|
||||||
|
|
||||||
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
|
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
|
||||||
secretKey = ProviderHelper.getPGPSecretKeyByKeyId(mContext, encData.getKeyID());
|
long masterKeyId = ProviderHelper.getMasterKeyId(mContext,
|
||||||
if (secretKey != null) {
|
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(encData.getKeyID()))
|
||||||
|
);
|
||||||
|
PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRing(mContext, masterKeyId);
|
||||||
|
if (secretKeyRing == null) {
|
||||||
|
throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
|
||||||
|
}
|
||||||
|
secretKey = secretKeyRing.getSecretKey(encData.getKeyID());
|
||||||
|
if (secretKey == null) {
|
||||||
|
throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
|
||||||
|
}
|
||||||
// secret key exists in database
|
// secret key exists in database
|
||||||
|
|
||||||
// allow only a specific key for decryption?
|
// allow only a specific key for decryption?
|
||||||
if (mAllowedKeyIds != null) {
|
if (mAllowedKeyIds != null) {
|
||||||
// TODO: improve this code! get master key directly!
|
|
||||||
PGPSecretKeyRing secretKeyRing =
|
|
||||||
ProviderHelper.getPGPSecretKeyRingWithKeyId(mContext, encData.getKeyID());
|
|
||||||
long masterKeyId = PgpKeyHelper.getMasterKey(secretKeyRing).getKeyID();
|
|
||||||
Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID());
|
Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID());
|
||||||
Log.d(Constants.TAG, "allowedKeyIds: " + mAllowedKeyIds);
|
Log.d(Constants.TAG, "allowedKeyIds: " + mAllowedKeyIds);
|
||||||
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
|
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
|
||||||
@ -258,12 +265,12 @@ public class PgpDecryptVerify {
|
|||||||
if (mPassphrase == null) {
|
if (mPassphrase == null) {
|
||||||
// returns "" if key has no passphrase
|
// returns "" if key has no passphrase
|
||||||
mPassphrase =
|
mPassphrase =
|
||||||
PassphraseCacheService.getCachedPassphrase(mContext, encData.getKeyID());
|
PassphraseCacheService.getCachedPassphrase(mContext, masterKeyId);
|
||||||
|
|
||||||
// if passphrase was not cached, return here
|
// if passphrase was not cached, return here
|
||||||
// indicating that a passphrase is missing!
|
// indicating that a passphrase is missing!
|
||||||
if (mPassphrase == null) {
|
if (mPassphrase == null) {
|
||||||
returnData.setKeyIdPassphraseNeeded(encData.getKeyID());
|
returnData.setKeyIdPassphraseNeeded(masterKeyId);
|
||||||
returnData.setStatus(PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED);
|
returnData.setStatus(PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED);
|
||||||
return returnData;
|
return returnData;
|
||||||
}
|
}
|
||||||
@ -272,7 +279,6 @@ public class PgpDecryptVerify {
|
|||||||
// break out of while, only get first object here
|
// break out of while, only get first object here
|
||||||
// TODO???: There could be more pgp objects, which are not decrypted!
|
// TODO???: There could be more pgp objects, which are not decrypted!
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
} else if (mAllowSymmetricDecryption && obj instanceof PGPPBEEncryptedData) {
|
} else if (mAllowSymmetricDecryption && obj instanceof PGPPBEEncryptedData) {
|
||||||
symmetricPacketFound = true;
|
symmetricPacketFound = true;
|
||||||
|
|
||||||
@ -362,7 +368,7 @@ public class PgpDecryptVerify {
|
|||||||
for (int i = 0; i < sigList.size(); ++i) {
|
for (int i = 0; i < sigList.size(); ++i) {
|
||||||
signature = sigList.get(i);
|
signature = sigList.get(i);
|
||||||
signatureKey = ProviderHelper
|
signatureKey = ProviderHelper
|
||||||
.getPGPPublicKeyByKeyId(mContext, signature.getKeyID());
|
.getPGPPublicKeyRing(mContext, signature.getKeyID()).getPublicKey();
|
||||||
if (signatureKeyId == 0) {
|
if (signatureKeyId == 0) {
|
||||||
signatureKeyId = signature.getKeyID();
|
signatureKeyId = signature.getKeyID();
|
||||||
}
|
}
|
||||||
@ -375,7 +381,7 @@ public class PgpDecryptVerify {
|
|||||||
PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId(
|
PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId(
|
||||||
mContext, signatureKeyId);
|
mContext, signatureKeyId);
|
||||||
if (signKeyRing != null) {
|
if (signKeyRing != null) {
|
||||||
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
|
userId = PgpKeyHelper.getMainUserId(signKeyRing.getPublicKey());
|
||||||
}
|
}
|
||||||
signatureResult.setUserId(userId);
|
signatureResult.setUserId(userId);
|
||||||
break;
|
break;
|
||||||
@ -545,26 +551,28 @@ public class PgpDecryptVerify {
|
|||||||
long signatureKeyId = 0;
|
long signatureKeyId = 0;
|
||||||
PGPPublicKey signatureKey = null;
|
PGPPublicKey signatureKey = null;
|
||||||
for (int i = 0; i < sigList.size(); ++i) {
|
for (int i = 0; i < sigList.size(); ++i) {
|
||||||
|
|
||||||
signature = sigList.get(i);
|
signature = sigList.get(i);
|
||||||
signatureKey = ProviderHelper.getPGPPublicKeyByKeyId(mContext, signature.getKeyID());
|
|
||||||
if (signatureKeyId == 0) {
|
|
||||||
signatureKeyId = signature.getKeyID();
|
signatureKeyId = signature.getKeyID();
|
||||||
|
|
||||||
|
// find data about this subkey
|
||||||
|
HashMap<String, Object> data = ProviderHelper.getGenericData(mContext,
|
||||||
|
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(signature.getKeyID())),
|
||||||
|
new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID },
|
||||||
|
new int[] { ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_STRING });
|
||||||
|
// any luck? otherwise, try next.
|
||||||
|
if(data.get(KeyRings.MASTER_KEY_ID) == null) {
|
||||||
|
signature = null;
|
||||||
|
// do NOT reset signatureKeyId, that one is shown when no known one is found!
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signatureKey == null) {
|
// this one can't fail now (yay database constraints)
|
||||||
signature = null;
|
signatureKey = ProviderHelper.getPGPPublicKeyRing(mContext, (Long) data.get(KeyRings.MASTER_KEY_ID)).getPublicKey();
|
||||||
} else {
|
signatureResult.setUserId((String) data.get(KeyRings.USER_ID));
|
||||||
signatureKeyId = signature.getKeyID();
|
|
||||||
String userId = null;
|
|
||||||
PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId(mContext,
|
|
||||||
signatureKeyId);
|
|
||||||
if (signKeyRing != null) {
|
|
||||||
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
|
|
||||||
}
|
|
||||||
signatureResult.setUserId(userId);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
signatureResult.setKeyId(signatureKeyId);
|
signatureResult.setKeyId(signatureKeyId);
|
||||||
|
|
||||||
@ -624,7 +632,7 @@ public class PgpDecryptVerify {
|
|||||||
signatureKeyId);
|
signatureKeyId);
|
||||||
PGPPublicKey mKey = null;
|
PGPPublicKey mKey = null;
|
||||||
if (signKeyRing != null) {
|
if (signKeyRing != null) {
|
||||||
mKey = PgpKeyHelper.getMasterKey(signKeyRing);
|
mKey = signKeyRing.getPublicKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signature.getKeyID() != mKey.getKeyID()) {
|
if (signature.getKeyID() != mKey.getKeyID()) {
|
||||||
|
@ -260,7 +260,6 @@ public class PgpImportExport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (save) {
|
if (save) {
|
||||||
ProviderHelper.saveKeyRing(mContext, secretKeyRing);
|
|
||||||
// TODO: preserve certifications
|
// TODO: preserve certifications
|
||||||
// (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?)
|
// (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?)
|
||||||
PGPPublicKeyRing newPubRing = null;
|
PGPPublicKeyRing newPubRing = null;
|
||||||
@ -275,6 +274,7 @@ public class PgpImportExport {
|
|||||||
if (newPubRing != null) {
|
if (newPubRing != null) {
|
||||||
ProviderHelper.saveKeyRing(mContext, newPubRing);
|
ProviderHelper.saveKeyRing(mContext, newPubRing);
|
||||||
}
|
}
|
||||||
|
ProviderHelper.saveKeyRing(mContext, secretKeyRing);
|
||||||
// TODO: remove status returns, use exceptions!
|
// TODO: remove status returns, use exceptions!
|
||||||
status = Id.return_value.ok;
|
status = Id.return_value.ok;
|
||||||
}
|
}
|
||||||
|
@ -60,34 +60,6 @@ public class PgpKeyHelper {
|
|||||||
return key.getPublicKey().getCreationTime();
|
return key.getPublicKey().getCreationTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static PGPPublicKey getMasterKey(PGPPublicKeyRing keyRing) {
|
|
||||||
if (keyRing == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) {
|
|
||||||
if (key.isMasterKey()) {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static PGPSecretKey getMasterKey(PGPSecretKeyRing keyRing) {
|
|
||||||
if (keyRing == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
|
|
||||||
if (key.isMasterKey()) {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) {
|
public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) {
|
||||||
long cnt = 0;
|
long cnt = 0;
|
||||||
|
@ -306,7 +306,7 @@ public class PgpSignEncrypt {
|
|||||||
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
|
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
|
||||||
signatureGenerator.init(signatureType, signaturePrivateKey);
|
signatureGenerator.init(signatureType, signaturePrivateKey);
|
||||||
|
|
||||||
String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
|
String userId = PgpKeyHelper.getMainUserId(signingKeyRing.getSecretKey());
|
||||||
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
|
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
|
||||||
spGen.setSignerUserID(false, userId);
|
spGen.setSignerUserID(false, userId);
|
||||||
signatureGenerator.setHashedSubpackets(spGen.generate());
|
signatureGenerator.setHashedSubpackets(spGen.generate());
|
||||||
@ -505,7 +505,7 @@ public class PgpSignEncrypt {
|
|||||||
signatureGenerator.init(type, signaturePrivateKey);
|
signatureGenerator.init(type, signaturePrivateKey);
|
||||||
|
|
||||||
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
|
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
|
||||||
String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
|
String userId = PgpKeyHelper.getMainUserId(signingKeyRing.getSecretKey());
|
||||||
spGen.setSignerUserID(false, userId);
|
spGen.setSignerUserID(false, userId);
|
||||||
signatureGenerator.setHashedSubpackets(spGen.generate());
|
signatureGenerator.setHashedSubpackets(spGen.generate());
|
||||||
}
|
}
|
||||||
|
@ -83,10 +83,9 @@ public class KeychainContract {
|
|||||||
|
|
||||||
public static final String PATH_UNIFIED = "unified";
|
public static final String PATH_UNIFIED = "unified";
|
||||||
|
|
||||||
public static final String PATH_BY_MASTER_KEY_ID = "master_key_id";
|
public static final String PATH_FIND = "find";
|
||||||
public static final String PATH_BY_KEY_ID = "key_id";
|
public static final String PATH_BY_EMAIL = "email";
|
||||||
public static final String PATH_BY_EMAILS = "emails";
|
public static final String PATH_BY_SUBKEY = "subkey";
|
||||||
public static final String PATH_BY_LIKE_EMAIL = "like_email";
|
|
||||||
|
|
||||||
public static final String PATH_PUBLIC = "public";
|
public static final String PATH_PUBLIC = "public";
|
||||||
public static final String PATH_SECRET = "secret";
|
public static final String PATH_SECRET = "secret";
|
||||||
@ -96,31 +95,49 @@ public class KeychainContract {
|
|||||||
public static final String BASE_API_APPS = "api_apps";
|
public static final String BASE_API_APPS = "api_apps";
|
||||||
public static final String PATH_ACCOUNTS = "accounts";
|
public static final String PATH_ACCOUNTS = "accounts";
|
||||||
|
|
||||||
public static class KeyRings implements KeyRingsColumns, BaseColumns {
|
public static class KeyRings implements BaseColumns, KeysColumns, UserIdsColumns {
|
||||||
|
public static final String MASTER_KEY_ID = "master_key_id";
|
||||||
|
public static final String HAS_SECRET = "has_secret";
|
||||||
|
|
||||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
||||||
.appendPath(BASE_KEY_RINGS).build();
|
.appendPath(BASE_KEY_RINGS).build();
|
||||||
|
|
||||||
/**
|
|
||||||
* Use if multiple items get returned
|
|
||||||
*/
|
|
||||||
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring";
|
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring";
|
||||||
|
|
||||||
/**
|
|
||||||
* Use if a single item is returned
|
|
||||||
*/
|
|
||||||
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring";
|
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring";
|
||||||
|
|
||||||
public static Uri buildUnifiedKeyRingsUri() {
|
public static Uri buildUnifiedKeyRingsUri() {
|
||||||
return CONTENT_URI.buildUpon().appendPath(PATH_UNIFIED).build();
|
return CONTENT_URI.buildUpon().appendPath(PATH_UNIFIED).build();
|
||||||
}
|
}
|
||||||
public static Uri buildUnifiedKeyRingsByEmailUri(String email) {
|
|
||||||
return CONTENT_URI.buildUpon().appendPath("email:" + email).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Uri buildGenericKeyRingUri(String masterKeyId) {
|
public static Uri buildGenericKeyRingUri(String masterKeyId) {
|
||||||
return CONTENT_URI.buildUpon().appendPath(masterKeyId).build();
|
return CONTENT_URI.buildUpon().appendPath(masterKeyId).build();
|
||||||
}
|
}
|
||||||
|
public static Uri buildUnifiedKeyRingUri(String masterKeyId) {
|
||||||
|
return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_UNIFIED).build();
|
||||||
|
}
|
||||||
|
public static Uri buildUnifiedKeyRingUri(Uri uri) {
|
||||||
|
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_UNIFIED).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Uri buildUnifiedKeyRingsFindByEmailUri(String email) {
|
||||||
|
return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_EMAIL).appendPath(email).build();
|
||||||
|
}
|
||||||
|
public static Uri buildUnifiedKeyRingsFindBySubkeyUri(String subkey) {
|
||||||
|
return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_SUBKEY).appendPath(subkey).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class KeyRingData implements KeyRingsColumns, BaseColumns {
|
||||||
|
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
||||||
|
.appendPath(BASE_KEY_RINGS).build();
|
||||||
|
|
||||||
|
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring_data";
|
||||||
|
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring_data";
|
||||||
|
|
||||||
|
public static Uri buildPublicKeyRingUri() {
|
||||||
|
return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).build();
|
||||||
|
}
|
||||||
public static Uri buildPublicKeyRingUri(String masterKeyId) {
|
public static Uri buildPublicKeyRingUri(String masterKeyId) {
|
||||||
return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_PUBLIC).build();
|
return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_PUBLIC).build();
|
||||||
}
|
}
|
||||||
@ -135,12 +152,6 @@ public class KeychainContract {
|
|||||||
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_SECRET).build();
|
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_SECRET).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri buildUnifiedKeyRingUri(String masterKeyId) {
|
|
||||||
return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_UNIFIED).build();
|
|
||||||
}
|
|
||||||
public static Uri buildUnifiedKeyRingUri(Uri uri) {
|
|
||||||
return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_UNIFIED).build();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Keys implements KeysColumns, BaseColumns {
|
public static class Keys implements KeysColumns, BaseColumns {
|
||||||
|
@ -124,7 +124,6 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
|||||||
KeychainDatabase(Context context) {
|
KeychainDatabase(Context context) {
|
||||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||||
|
|
||||||
|
|
||||||
// make sure this is only done once, on the first instance!
|
// make sure this is only done once, on the first instance!
|
||||||
boolean iAmIt = false;
|
boolean iAmIt = false;
|
||||||
synchronized(apg_hack) {
|
synchronized(apg_hack) {
|
||||||
|
@ -26,19 +26,15 @@ import android.database.sqlite.SQLiteConstraintException;
|
|||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteQueryBuilder;
|
import android.database.sqlite.SQLiteQueryBuilder;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.BaseColumns;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
@ -46,13 +42,9 @@ import java.util.Arrays;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class KeychainProvider extends ContentProvider {
|
public class KeychainProvider extends ContentProvider {
|
||||||
// public static final String ACTION_BROADCAST_DATABASE_CHANGE = Constants.PACKAGE_NAME
|
|
||||||
// + ".action.DATABASE_CHANGE";
|
|
||||||
//
|
|
||||||
// public static final String EXTRA_BROADCAST_KEY_TYPE = "key_type";
|
|
||||||
// public static final String EXTRA_BROADCAST_CONTENT_ITEM_TYPE = "contentItemType";
|
|
||||||
|
|
||||||
private static final int KEY_RINGS_UNIFIED = 101;
|
private static final int KEY_RINGS_UNIFIED = 101;
|
||||||
|
private static final int KEY_RINGS_PUBLIC = 102;
|
||||||
|
|
||||||
private static final int KEY_RING_UNIFIED = 200;
|
private static final int KEY_RING_UNIFIED = 200;
|
||||||
private static final int KEY_RING_KEYS = 201;
|
private static final int KEY_RING_KEYS = 201;
|
||||||
@ -65,7 +57,10 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
private static final int API_ACCOUNTS = 304;
|
private static final int API_ACCOUNTS = 304;
|
||||||
private static final int API_ACCOUNTS_BY_ACCOUNT_NAME = 306;
|
private static final int API_ACCOUNTS_BY_ACCOUNT_NAME = 306;
|
||||||
|
|
||||||
// private static final int DATA_STREAM = 401;
|
private static final int KEY_RINGS_FIND_BY_EMAIL = 400;
|
||||||
|
private static final int KEY_RINGS_FIND_BY_SUBKEY = 401;
|
||||||
|
|
||||||
|
// private static final int DATA_STREAM = 501;
|
||||||
|
|
||||||
protected UriMatcher mUriMatcher;
|
protected UriMatcher mUriMatcher;
|
||||||
|
|
||||||
@ -79,18 +74,36 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
String authority = KeychainContract.CONTENT_AUTHORITY;
|
String authority = KeychainContract.CONTENT_AUTHORITY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* select from key_ring
|
* list key_rings
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* key_rings/unified
|
* key_rings/unified
|
||||||
|
* key_rings/public
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS
|
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS
|
||||||
+ "/" + KeychainContract.PATH_UNIFIED,
|
+ "/" + KeychainContract.PATH_UNIFIED,
|
||||||
KEY_RINGS_UNIFIED);
|
KEY_RINGS_UNIFIED);
|
||||||
|
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS
|
||||||
|
+ "/" + KeychainContract.PATH_PUBLIC,
|
||||||
|
KEY_RINGS_PUBLIC);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* select from key_ring
|
* find by criteria other than master key id
|
||||||
|
*
|
||||||
|
* key_rings/find/email/_
|
||||||
|
* key_rings/find/subkey/_
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
|
||||||
|
+ KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_EMAIL + "/*",
|
||||||
|
KEY_RINGS_FIND_BY_EMAIL);
|
||||||
|
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
|
||||||
|
+ KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_SUBKEY + "/*",
|
||||||
|
KEY_RINGS_FIND_BY_SUBKEY);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list key_ring specifics
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* key_rings/_/unified
|
* key_rings/_/unified
|
||||||
@ -155,10 +168,15 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onCreate() {
|
public boolean onCreate() {
|
||||||
mUriMatcher = buildUriMatcher();
|
mUriMatcher = buildUriMatcher();
|
||||||
mKeychainDatabase = new KeychainDatabase(getContext());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KeychainDatabase getDb() {
|
||||||
|
if(mKeychainDatabase == null)
|
||||||
|
mKeychainDatabase = new KeychainDatabase(getContext());
|
||||||
|
return mKeychainDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@ -204,7 +222,6 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
Log.v(Constants.TAG, "query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")");
|
Log.v(Constants.TAG, "query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")");
|
||||||
|
|
||||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||||
SQLiteDatabase db = mKeychainDatabase.getReadableDatabase();
|
|
||||||
|
|
||||||
int match = mUriMatcher.match(uri);
|
int match = mUriMatcher.match(uri);
|
||||||
|
|
||||||
@ -213,59 +230,67 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
|
|
||||||
switch (match) {
|
switch (match) {
|
||||||
case KEY_RING_UNIFIED:
|
case KEY_RING_UNIFIED:
|
||||||
case KEY_RINGS_UNIFIED: {
|
case KEY_RINGS_UNIFIED:
|
||||||
|
case KEY_RINGS_FIND_BY_EMAIL:
|
||||||
|
case KEY_RINGS_FIND_BY_SUBKEY: {
|
||||||
HashMap<String, String> projectionMap = new HashMap<String, String>();
|
HashMap<String, String> projectionMap = new HashMap<String, String>();
|
||||||
projectionMap.put(BaseColumns._ID, Tables.KEYS + ".oid AS _id");
|
projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id");
|
||||||
projectionMap.put(KeysColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID);
|
projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
|
||||||
projectionMap.put(KeysColumns.RANK, Tables.KEYS + "." + KeysColumns.RANK);
|
projectionMap.put(KeyRings.KEY_ID, Keys.KEY_ID);
|
||||||
projectionMap.put(KeysColumns.KEY_ID, KeysColumns.KEY_ID);
|
projectionMap.put(KeyRings.KEY_SIZE, Keys.KEY_SIZE);
|
||||||
projectionMap.put(KeysColumns.KEY_SIZE, KeysColumns.KEY_SIZE);
|
projectionMap.put(KeyRings.IS_REVOKED, Keys.IS_REVOKED);
|
||||||
projectionMap.put(KeysColumns.IS_REVOKED, KeysColumns.IS_REVOKED);
|
projectionMap.put(KeyRings.CAN_CERTIFY, Keys.CAN_CERTIFY);
|
||||||
projectionMap.put(KeysColumns.CAN_CERTIFY, KeysColumns.CAN_CERTIFY);
|
projectionMap.put(KeyRings.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
|
||||||
projectionMap.put(KeysColumns.CAN_ENCRYPT, KeysColumns.CAN_ENCRYPT);
|
projectionMap.put(KeyRings.CAN_SIGN, Keys.CAN_SIGN);
|
||||||
projectionMap.put(KeysColumns.CAN_SIGN, KeysColumns.CAN_SIGN);
|
projectionMap.put(KeyRings.CREATION, Keys.CREATION);
|
||||||
projectionMap.put(KeysColumns.CREATION, KeysColumns.CREATION);
|
projectionMap.put(KeyRings.EXPIRY, Keys.EXPIRY);
|
||||||
projectionMap.put(KeysColumns.EXPIRY, KeysColumns.EXPIRY);
|
projectionMap.put(KeyRings.ALGORITHM, Keys.ALGORITHM);
|
||||||
projectionMap.put(KeysColumns.ALGORITHM, KeysColumns.ALGORITHM);
|
projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT);
|
||||||
projectionMap.put(KeysColumns.FINGERPRINT, KeysColumns.FINGERPRINT);
|
projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID);
|
||||||
projectionMap.put(UserIdsColumns.USER_ID, UserIdsColumns.USER_ID);
|
projectionMap.put(KeyRings.HAS_SECRET, "(" + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NOT NULL) AS " + KeyRings.HAS_SECRET);
|
||||||
projectionMap.put(Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID, Tables.KEY_RINGS_SECRET + "." + KeyRingsColumns.MASTER_KEY_ID);
|
|
||||||
qb.setProjectionMap(projectionMap);
|
qb.setProjectionMap(projectionMap);
|
||||||
|
|
||||||
qb.setTables(
|
qb.setTables(
|
||||||
Tables.KEYS
|
Tables.KEYS
|
||||||
+ " INNER JOIN " + Tables.USER_IDS + " ON ("
|
+ " INNER JOIN " + Tables.USER_IDS + " ON ("
|
||||||
+ Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID
|
+ Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||||
+ " = "
|
+ " = "
|
||||||
+ Tables.USER_IDS + "." + UserIdsColumns.MASTER_KEY_ID
|
+ Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID
|
||||||
+ " AND " + Tables.USER_IDS + "." + UserIdsColumns.RANK + " = 0"
|
+ " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = 0"
|
||||||
+ ") LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON ("
|
+ ") LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON ("
|
||||||
+ Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID
|
+ Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||||
+ " = "
|
+ " = "
|
||||||
+ Tables.KEY_RINGS_SECRET + "." + KeyRingsColumns.MASTER_KEY_ID
|
+ Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID
|
||||||
+ ")"
|
+ ")"
|
||||||
);
|
);
|
||||||
qb.appendWhere(Tables.KEYS + "." + KeysColumns.RANK + " = 0");
|
qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0");
|
||||||
|
|
||||||
if(match == KEY_RING_UNIFIED) {
|
switch(match) {
|
||||||
qb.appendWhere(" AND " + Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID + " = ");
|
case KEY_RING_UNIFIED: {
|
||||||
|
qb.appendWhere(" AND " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = ");
|
||||||
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
||||||
} else if (TextUtils.isEmpty(sortOrder)) {
|
|
||||||
sortOrder =
|
|
||||||
Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL DESC"
|
|
||||||
+ Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC";
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*case SECRET_KEY_RING_BY_EMAILS:
|
case KEY_RINGS_FIND_BY_SUBKEY: {
|
||||||
case PUBLIC_KEY_RING_BY_EMAILS:
|
try {
|
||||||
qb = buildKeyRingQuery(qb, match);
|
String subkey = Long.valueOf(uri.getLastPathSegment()).toString();
|
||||||
|
qb.appendWhere(" AND EXISTS ("
|
||||||
String emails = uri.getLastPathSegment();
|
+ " SELECT 1 FROM " + Tables.KEYS + " AS tmp"
|
||||||
String chunks[] = emails.split(" *, *");
|
+ " WHERE tmp." + UserIds.MASTER_KEY_ID
|
||||||
|
+ " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||||
|
+ " AND tmp." + Keys.KEY_ID + " = " + subkey + ""
|
||||||
|
+ ")");
|
||||||
|
} catch(NumberFormatException e) {
|
||||||
|
Log.e(Constants.TAG, "Malformed find by subkey query!", e);
|
||||||
|
qb.appendWhere(" AND 0");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KEY_RINGS_FIND_BY_EMAIL: {
|
||||||
|
String chunks[] = uri.getLastPathSegment().split(" *, *");
|
||||||
boolean gotCondition = false;
|
boolean gotCondition = false;
|
||||||
String emailWhere = "";
|
String emailWhere = "";
|
||||||
|
// JAVA ♥
|
||||||
for (int i = 0; i < chunks.length; ++i) {
|
for (int i = 0; i < chunks.length; ++i) {
|
||||||
if (chunks[i].length() == 0) {
|
if (chunks[i].length() == 0) {
|
||||||
continue;
|
continue;
|
||||||
@ -273,38 +298,58 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
emailWhere += " OR ";
|
emailWhere += " OR ";
|
||||||
}
|
}
|
||||||
emailWhere += "tmp." + UserIdsColumns.USER_ID + " LIKE ";
|
emailWhere += "tmp." + UserIds.USER_ID + " LIKE ";
|
||||||
// match '*<email>', so it has to be at the *end* of the user id
|
// match '*<email>', so it has to be at the *end* of the user id
|
||||||
emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">");
|
emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">");
|
||||||
gotCondition = true;
|
gotCondition = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gotCondition) {
|
if(gotCondition) {
|
||||||
qb.appendWhere(" AND EXISTS (SELECT tmp." + BaseColumns._ID + " FROM "
|
qb.appendWhere(" AND EXISTS ("
|
||||||
+ Tables.USER_IDS + " AS tmp WHERE tmp." + UserIdsColumns.KEY_RING_ROW_ID
|
+ " SELECT 1 FROM " + Tables.USER_IDS + " AS tmp"
|
||||||
+ " = " + Tables.KEY_RINGS + "." + BaseColumns._ID + " AND (" + emailWhere
|
+ " WHERE tmp." + UserIds.MASTER_KEY_ID
|
||||||
+ "))");
|
+ " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||||
}*/
|
+ " AND (" + emailWhere + ")"
|
||||||
|
+ ")");
|
||||||
|
} else {
|
||||||
|
// TODO better way to do this?
|
||||||
|
Log.e(Constants.TAG, "Malformed find by email query!");
|
||||||
|
qb.appendWhere(" AND 0");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TextUtils.isEmpty(sortOrder)) {
|
||||||
|
sortOrder =
|
||||||
|
Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL ASC, "
|
||||||
|
+ Tables.USER_IDS + "." + UserIds.USER_ID + " ASC";
|
||||||
|
}
|
||||||
|
|
||||||
|
// uri to watch is all /key_rings/
|
||||||
|
uri = KeyRings.CONTENT_URI;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case KEY_RING_KEYS: {
|
case KEY_RING_KEYS: {
|
||||||
HashMap<String, String> projectionMap = new HashMap<String, String>();
|
HashMap<String, String> projectionMap = new HashMap<String, String>();
|
||||||
projectionMap.put(BaseColumns._ID, Tables.KEYS + ".oid AS _id");
|
projectionMap.put(Keys._ID, Tables.KEYS + ".oid AS _id");
|
||||||
projectionMap.put(KeysColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID);
|
projectionMap.put(Keys.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
|
||||||
projectionMap.put(KeysColumns.RANK, Tables.KEYS + "." + KeysColumns.RANK);
|
projectionMap.put(Keys.RANK, Tables.KEYS + "." + Keys.RANK);
|
||||||
projectionMap.put(KeysColumns.KEY_ID, KeysColumns.KEY_ID);
|
projectionMap.put(Keys.KEY_ID, Keys.KEY_ID);
|
||||||
projectionMap.put(KeysColumns.KEY_SIZE, KeysColumns.KEY_SIZE);
|
projectionMap.put(Keys.KEY_SIZE, Keys.KEY_SIZE);
|
||||||
projectionMap.put(KeysColumns.IS_REVOKED, KeysColumns.IS_REVOKED);
|
projectionMap.put(Keys.IS_REVOKED, Keys.IS_REVOKED);
|
||||||
projectionMap.put(KeysColumns.CAN_CERTIFY, KeysColumns.CAN_CERTIFY);
|
projectionMap.put(Keys.CAN_CERTIFY, Keys.CAN_CERTIFY);
|
||||||
projectionMap.put(KeysColumns.CAN_ENCRYPT, KeysColumns.CAN_ENCRYPT);
|
projectionMap.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
|
||||||
projectionMap.put(KeysColumns.CAN_SIGN, KeysColumns.CAN_SIGN);
|
projectionMap.put(Keys.CAN_SIGN, Keys.CAN_SIGN);
|
||||||
projectionMap.put(KeysColumns.CREATION, KeysColumns.CREATION);
|
projectionMap.put(Keys.CREATION, Keys.CREATION);
|
||||||
projectionMap.put(KeysColumns.EXPIRY, KeysColumns.EXPIRY);
|
projectionMap.put(Keys.EXPIRY, Keys.EXPIRY);
|
||||||
projectionMap.put(KeysColumns.ALGORITHM, KeysColumns.ALGORITHM);
|
projectionMap.put(Keys.ALGORITHM, Keys.ALGORITHM);
|
||||||
projectionMap.put(KeysColumns.FINGERPRINT, KeysColumns.FINGERPRINT);
|
projectionMap.put(Keys.FINGERPRINT, Keys.FINGERPRINT);
|
||||||
qb.setProjectionMap(projectionMap);
|
qb.setProjectionMap(projectionMap);
|
||||||
|
|
||||||
qb.setTables(Tables.KEYS);
|
qb.setTables(Tables.KEYS);
|
||||||
qb.appendWhere(KeysColumns.MASTER_KEY_ID + " = ");
|
qb.appendWhere(Keys.MASTER_KEY_ID + " = ");
|
||||||
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -312,7 +357,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
|
|
||||||
case KEY_RING_USER_IDS: {
|
case KEY_RING_USER_IDS: {
|
||||||
HashMap<String, String> projectionMap = new HashMap<String, String>();
|
HashMap<String, String> projectionMap = new HashMap<String, String>();
|
||||||
projectionMap.put(BaseColumns._ID, Tables.USER_IDS + ".oid AS _id");
|
projectionMap.put(UserIds._ID, Tables.USER_IDS + ".oid AS _id");
|
||||||
projectionMap.put(UserIds.MASTER_KEY_ID, UserIds.MASTER_KEY_ID);
|
projectionMap.put(UserIds.MASTER_KEY_ID, UserIds.MASTER_KEY_ID);
|
||||||
projectionMap.put(UserIds.USER_ID, UserIds.USER_ID);
|
projectionMap.put(UserIds.USER_ID, UserIds.USER_ID);
|
||||||
projectionMap.put(UserIds.RANK, UserIds.RANK);
|
projectionMap.put(UserIds.RANK, UserIds.RANK);
|
||||||
@ -320,36 +365,44 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
qb.setProjectionMap(projectionMap);
|
qb.setProjectionMap(projectionMap);
|
||||||
|
|
||||||
qb.setTables(Tables.USER_IDS);
|
qb.setTables(Tables.USER_IDS);
|
||||||
qb.appendWhere(UserIdsColumns.MASTER_KEY_ID + " = ");
|
qb.appendWhere(UserIds.MASTER_KEY_ID + " = ");
|
||||||
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
||||||
|
|
||||||
|
if (TextUtils.isEmpty(sortOrder)) {
|
||||||
|
sortOrder = UserIds.RANK + " ASC";
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case KEY_RINGS_PUBLIC:
|
||||||
case KEY_RING_PUBLIC: {
|
case KEY_RING_PUBLIC: {
|
||||||
HashMap<String, String> projectionMap = new HashMap<String, String>();
|
HashMap<String, String> projectionMap = new HashMap<String, String>();
|
||||||
projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS_PUBLIC + ".oid AS _id");
|
projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_PUBLIC + ".oid AS _id");
|
||||||
projectionMap.put(KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID);
|
projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID);
|
||||||
projectionMap.put(KeyRings.KEY_RING_DATA, KeyRings.KEY_RING_DATA);
|
projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA);
|
||||||
qb.setProjectionMap(projectionMap);
|
qb.setProjectionMap(projectionMap);
|
||||||
|
|
||||||
qb.setTables(Tables.KEY_RINGS_PUBLIC);
|
qb.setTables(Tables.KEY_RINGS_PUBLIC);
|
||||||
qb.appendWhere(KeyRingsColumns.MASTER_KEY_ID + " = ");
|
|
||||||
|
if(match == KEY_RING_PUBLIC) {
|
||||||
|
qb.appendWhere(KeyRings.MASTER_KEY_ID + " = ");
|
||||||
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case KEY_RING_SECRET: {
|
case KEY_RING_SECRET: {
|
||||||
HashMap<String, String> projectionMap = new HashMap<String, String>();
|
HashMap<String, String> projectionMap = new HashMap<String, String>();
|
||||||
projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS_SECRET + ".oid AS _id");
|
projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_SECRET + ".oid AS _id");
|
||||||
projectionMap.put(KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID);
|
projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID);
|
||||||
projectionMap.put(KeyRings.KEY_RING_DATA, KeyRings.KEY_RING_DATA);
|
projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA);
|
||||||
qb.setProjectionMap(projectionMap);
|
qb.setProjectionMap(projectionMap);
|
||||||
|
|
||||||
qb.setTables(Tables.KEY_RINGS_SECRET);
|
qb.setTables(Tables.KEY_RINGS_SECRET);
|
||||||
qb.appendWhere(KeyRingsColumns.MASTER_KEY_ID + " = ");
|
qb.appendWhere(KeyRings.MASTER_KEY_ID + " = ");
|
||||||
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -381,7 +434,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown URI " + uri);
|
throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,6 +446,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
orderBy = sortOrder;
|
orderBy = sortOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SQLiteDatabase db = getDb().getReadableDatabase();
|
||||||
Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, having, orderBy);
|
Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, having, orderBy);
|
||||||
|
|
||||||
// Tell the cursor what uri to watch, so it knows when its source data changes
|
// Tell the cursor what uri to watch, so it knows when its source data changes
|
||||||
@ -416,7 +470,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
public Uri insert(Uri uri, ContentValues values) {
|
public Uri insert(Uri uri, ContentValues values) {
|
||||||
Log.d(Constants.TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")");
|
Log.d(Constants.TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")");
|
||||||
|
|
||||||
final SQLiteDatabase db = mKeychainDatabase.getWritableDatabase();
|
final SQLiteDatabase db = getDb().getWritableDatabase();
|
||||||
|
|
||||||
Uri rowUri = null;
|
Uri rowUri = null;
|
||||||
Long keyId = null;
|
Long keyId = null;
|
||||||
@ -426,23 +480,23 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
switch (match) {
|
switch (match) {
|
||||||
case KEY_RING_PUBLIC:
|
case KEY_RING_PUBLIC:
|
||||||
db.insertOrThrow(Tables.KEY_RINGS_PUBLIC, null, values);
|
db.insertOrThrow(Tables.KEY_RINGS_PUBLIC, null, values);
|
||||||
keyId = values.getAsLong(KeyRingsColumns.MASTER_KEY_ID);
|
keyId = values.getAsLong(KeyRings.MASTER_KEY_ID);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_RING_SECRET:
|
case KEY_RING_SECRET:
|
||||||
db.insertOrThrow(Tables.KEY_RINGS_SECRET, null, values);
|
db.insertOrThrow(Tables.KEY_RINGS_SECRET, null, values);
|
||||||
keyId = values.getAsLong(KeyRingsColumns.MASTER_KEY_ID);
|
keyId = values.getAsLong(KeyRings.MASTER_KEY_ID);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_RING_KEYS:
|
case KEY_RING_KEYS:
|
||||||
Log.d(Constants.TAG, "keys");
|
Log.d(Constants.TAG, "keys");
|
||||||
db.insertOrThrow(Tables.KEYS, null, values);
|
db.insertOrThrow(Tables.KEYS, null, values);
|
||||||
keyId = values.getAsLong(KeysColumns.MASTER_KEY_ID);
|
keyId = values.getAsLong(Keys.MASTER_KEY_ID);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_RING_USER_IDS:
|
case KEY_RING_USER_IDS:
|
||||||
db.insertOrThrow(Tables.USER_IDS, null, values);
|
db.insertOrThrow(Tables.USER_IDS, null, values);
|
||||||
keyId = values.getAsLong(UserIdsColumns.MASTER_KEY_ID);
|
keyId = values.getAsLong(UserIds.MASTER_KEY_ID);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case API_APPS:
|
case API_APPS:
|
||||||
@ -489,7 +543,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
public int delete(Uri uri, String additionalSelection, String[] selectionArgs) {
|
public int delete(Uri uri, String additionalSelection, String[] selectionArgs) {
|
||||||
Log.v(Constants.TAG, "delete(uri=" + uri + ")");
|
Log.v(Constants.TAG, "delete(uri=" + uri + ")");
|
||||||
|
|
||||||
final SQLiteDatabase db = mKeychainDatabase.getWritableDatabase();
|
final SQLiteDatabase db = getDb().getWritableDatabase();
|
||||||
|
|
||||||
int count;
|
int count;
|
||||||
final int match = mUriMatcher.match(uri);
|
final int match = mUriMatcher.match(uri);
|
||||||
@ -503,6 +557,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
// corresponding keys and userIds are deleted by ON DELETE CASCADE
|
// corresponding keys and userIds are deleted by ON DELETE CASCADE
|
||||||
count = db.delete(Tables.KEY_RINGS_PUBLIC, selection, selectionArgs);
|
count = db.delete(Tables.KEY_RINGS_PUBLIC, selection, selectionArgs);
|
||||||
|
uri = KeyRings.buildGenericKeyRingUri(uri.getPathSegments().get(1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case KEY_RING_SECRET: {
|
case KEY_RING_SECRET: {
|
||||||
@ -512,6 +567,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
selection += " AND (" + additionalSelection + ")";
|
selection += " AND (" + additionalSelection + ")";
|
||||||
}
|
}
|
||||||
count = db.delete(Tables.KEY_RINGS_SECRET, selection, selectionArgs);
|
count = db.delete(Tables.KEY_RINGS_SECRET, selection, selectionArgs);
|
||||||
|
uri = KeyRings.buildGenericKeyRingUri(uri.getPathSegments().get(1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,10 @@ import android.content.ContentValues;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.OperationApplicationException;
|
import android.content.OperationApplicationException;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.database.CursorWindow;
|
||||||
|
import android.database.CursorWrapper;
|
||||||
import android.database.DatabaseUtils;
|
import android.database.DatabaseUtils;
|
||||||
|
import android.database.sqlite.SQLiteCursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
|
||||||
@ -40,9 +43,9 @@ import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
|||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
|
|
||||||
import org.sufficientlysecure.keychain.remote.AccountSettings;
|
import org.sufficientlysecure.keychain.remote.AccountSettings;
|
||||||
import org.sufficientlysecure.keychain.remote.AppSettings;
|
import org.sufficientlysecure.keychain.remote.AppSettings;
|
||||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||||
@ -52,21 +55,81 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class ProviderHelper {
|
public class ProviderHelper {
|
||||||
|
|
||||||
/**
|
// If we ever switch to api level 11, we can ditch this whole mess!
|
||||||
* Private helper method to get PGPKeyRing from database
|
public static final int FIELD_TYPE_NULL = 1;
|
||||||
|
// this is called integer to stay coherent with the constants in Cursor (api level 11)
|
||||||
|
public static final int FIELD_TYPE_INTEGER = 2;
|
||||||
|
public static final int FIELD_TYPE_FLOAT = 3;
|
||||||
|
public static final int FIELD_TYPE_STRING = 4;
|
||||||
|
public static final int FIELD_TYPE_BLOB = 5;
|
||||||
|
|
||||||
|
public static Object getGenericData(Context context, Uri uri, String column, int type) {
|
||||||
|
return getGenericData(context, uri, new String[] { column }, new int[] { type }).get(column);
|
||||||
|
}
|
||||||
|
public static HashMap<String,Object> getGenericData(Context context, Uri uri, String[] proj, int[] types) {
|
||||||
|
Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
|
||||||
|
|
||||||
|
HashMap<String, Object> result = new HashMap<String, Object>(proj.length);
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
int pos = 0;
|
||||||
|
for(String p : proj) {
|
||||||
|
switch(types[pos]) {
|
||||||
|
case FIELD_TYPE_NULL: result.put(p, cursor.isNull(pos)); break;
|
||||||
|
case FIELD_TYPE_INTEGER: result.put(p, cursor.getLong(pos)); break;
|
||||||
|
case FIELD_TYPE_FLOAT: result.put(p, cursor.getFloat(pos)); break;
|
||||||
|
case FIELD_TYPE_STRING: result.put(p, cursor.getString(pos)); break;
|
||||||
|
case FIELD_TYPE_BLOB: result.put(p, cursor.getBlob(pos)); break;
|
||||||
|
}
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object getUnifiedData(Context context, long masterKeyId, String column, int type) {
|
||||||
|
return getUnifiedData(context, masterKeyId, new String[] { column }, new int[] { type }).get(column);
|
||||||
|
}
|
||||||
|
public static HashMap<String,Object> getUnifiedData(Context context, long masterKeyId, String[] proj, int[] types) {
|
||||||
|
return getGenericData(context, KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)), proj, types);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Find the master key id related to a given query. The id will either be extracted from the
|
||||||
|
* query, which should work for all specific /key_rings/ queries, or will be queried if it can't.
|
||||||
*/
|
*/
|
||||||
|
public static long getMasterKeyId(Context context, Uri queryUri) {
|
||||||
|
// try extracting from the uri first
|
||||||
|
String firstSegment = queryUri.getPathSegments().get(1);
|
||||||
|
if(!firstSegment.equals("find")) try {
|
||||||
|
return Long.parseLong(firstSegment);
|
||||||
|
} catch(NumberFormatException e) {
|
||||||
|
// didn't work? oh well.
|
||||||
|
Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying...");
|
||||||
|
}
|
||||||
|
Object data = getGenericData(context, queryUri, KeyRings.MASTER_KEY_ID, FIELD_TYPE_INTEGER);
|
||||||
|
if(data != null)
|
||||||
|
return (Long) data;
|
||||||
|
// TODO better error handling?
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) {
|
public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) {
|
||||||
Cursor cursor = context.getContentResolver().query(queryUri,
|
Cursor cursor = context.getContentResolver().query(queryUri,
|
||||||
new String[]{KeyRings._ID, KeyRings.KEY_RING_DATA}, null, null, null);
|
new String[]{KeyRings._ID, KeyRingData.KEY_RING_DATA}, null, null, null);
|
||||||
|
|
||||||
PGPKeyRing keyRing = null;
|
PGPKeyRing keyRing = null;
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
int keyRingDataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA);
|
int keyRingDataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
|
||||||
|
|
||||||
byte[] data = cursor.getBlob(keyRingDataCol);
|
byte[] data = cursor.getBlob(keyRingDataCol);
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
@ -81,19 +144,18 @@ public class ProviderHelper {
|
|||||||
return keyRing;
|
return keyRing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long keyId) {
|
|
||||||
return getPGPPublicKeyRingWithKeyId(context, keyId).getPublicKey(keyId);
|
|
||||||
}
|
|
||||||
public static PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(Context context, long keyId) {
|
public static PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(Context context, long keyId) {
|
||||||
// todo do
|
Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId));
|
||||||
|
long masterKeyId = getMasterKeyId(context, uri);
|
||||||
|
if(masterKeyId != 0)
|
||||||
|
return getPGPPublicKeyRing(context, masterKeyId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PGPSecretKey getPGPSecretKeyByKeyId(Context context, long keyId) {
|
|
||||||
return getPGPSecretKeyRingWithKeyId(context, keyId).getSecretKey(keyId);
|
|
||||||
}
|
|
||||||
public static PGPSecretKeyRing getPGPSecretKeyRingWithKeyId(Context context, long keyId) {
|
public static PGPSecretKeyRing getPGPSecretKeyRingWithKeyId(Context context, long keyId) {
|
||||||
// todo do
|
Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId));
|
||||||
|
long masterKeyId = getMasterKeyId(context, uri);
|
||||||
|
if(masterKeyId != 0)
|
||||||
|
return getPGPSecretKeyRing(context, masterKeyId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +164,7 @@ public class ProviderHelper {
|
|||||||
*/
|
*/
|
||||||
public static PGPPublicKeyRing getPGPPublicKeyRing(Context context,
|
public static PGPPublicKeyRing getPGPPublicKeyRing(Context context,
|
||||||
long masterKeyId) {
|
long masterKeyId) {
|
||||||
Uri queryUri = KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId));
|
Uri queryUri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId));
|
||||||
return (PGPPublicKeyRing) getPGPKeyRing(context, queryUri);
|
return (PGPPublicKeyRing) getPGPKeyRing(context, queryUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +173,7 @@ public class ProviderHelper {
|
|||||||
*/
|
*/
|
||||||
public static PGPSecretKeyRing getPGPSecretKeyRing(Context context,
|
public static PGPSecretKeyRing getPGPSecretKeyRing(Context context,
|
||||||
long masterKeyId) {
|
long masterKeyId) {
|
||||||
Uri queryUri = KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId));
|
Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
|
||||||
return (PGPSecretKeyRing) getPGPKeyRing(context, queryUri);
|
return (PGPSecretKeyRing) getPGPKeyRing(context, queryUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,12 +186,11 @@ public class ProviderHelper {
|
|||||||
long masterKeyId = masterKey.getKeyID();
|
long masterKeyId = masterKey.getKeyID();
|
||||||
|
|
||||||
// IF there is a secret key, preserve it!
|
// IF there is a secret key, preserve it!
|
||||||
// TODO This even necessary?
|
PGPSecretKeyRing secretRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId);
|
||||||
// PGPSecretKeyRing secretRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId);
|
|
||||||
|
|
||||||
// delete old version of this keyRing, which also deletes all keys and userIds on cascade
|
// delete old version of this keyRing, which also deletes all keys and userIds on cascade
|
||||||
try {
|
try {
|
||||||
context.getContentResolver().delete(KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null);
|
context.getContentResolver().delete(KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null);
|
||||||
} catch (UnsupportedOperationException e) {
|
} catch (UnsupportedOperationException e) {
|
||||||
Log.e(Constants.TAG, "Key could not be deleted! Maybe we are creating a new one!", e);
|
Log.e(Constants.TAG, "Key could not be deleted! Maybe we are creating a new one!", e);
|
||||||
}
|
}
|
||||||
@ -139,11 +200,11 @@ public class ProviderHelper {
|
|||||||
// NOTE: If we would not use the same _ID again,
|
// NOTE: If we would not use the same _ID again,
|
||||||
// getting back to the ViewKeyActivity would result in Nullpointer,
|
// getting back to the ViewKeyActivity would result in Nullpointer,
|
||||||
// because the currently loaded key would be gone from the database
|
// because the currently loaded key would be gone from the database
|
||||||
values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
|
values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
|
||||||
values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
|
values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded());
|
||||||
|
|
||||||
// insert new version of this keyRing
|
// insert new version of this keyRing
|
||||||
Uri uri = KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId));
|
Uri uri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId));
|
||||||
Uri insertedUri = context.getContentResolver().insert(uri, values);
|
Uri insertedUri = context.getContentResolver().insert(uri, values);
|
||||||
|
|
||||||
// save all keys and userIds included in keyRing object in database
|
// save all keys and userIds included in keyRing object in database
|
||||||
@ -179,31 +240,43 @@ public class ProviderHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save the saved keyring (if any)
|
// Save the saved keyring (if any)
|
||||||
// TODO this even necessary? see above...
|
if(secretRing != null) {
|
||||||
// if(secretRing != null)
|
saveKeyRing(context, secretRing);
|
||||||
// saveKeyRing(context, secretRing);
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves PGPSecretKeyRing with its keys and userIds in DB
|
* Saves a PGPSecretKeyRing in the DB. This will only work if a corresponding public keyring
|
||||||
|
* is already in the database!
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static void saveKeyRing(Context context, PGPSecretKeyRing keyRing) throws IOException {
|
public static void saveKeyRing(Context context, PGPSecretKeyRing keyRing) throws IOException {
|
||||||
PGPSecretKey masterKey = keyRing.getSecretKey();
|
long masterKeyId = keyRing.getPublicKey().getKeyID();
|
||||||
long masterKeyId = masterKey.getKeyID();
|
|
||||||
|
|
||||||
// TODO Make sure there is a public key for this secret key in the db (create one maybe)
|
// save secret keyring
|
||||||
|
|
||||||
{
|
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
|
values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
|
||||||
values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
|
values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded());
|
||||||
// insert new version of this keyRing
|
// insert new version of this keyRing
|
||||||
Uri uri = KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId));
|
Uri uri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
|
||||||
context.getContentResolver().insert(uri, values);
|
context.getContentResolver().insert(uri, values);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves (or updates) a pair of public and secret KeyRings in the database
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static void saveKeyRing(Context context, PGPPublicKeyRing pubRing, PGPSecretKeyRing privRing) throws IOException {
|
||||||
|
long masterKeyId = pubRing.getPublicKey().getKeyID();
|
||||||
|
|
||||||
|
// delete secret keyring (so it isn't unnecessarily saved by public-saveKeyRing below)
|
||||||
|
context.getContentResolver().delete(KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null);
|
||||||
|
|
||||||
|
// save public keyring
|
||||||
|
saveKeyRing(context, pubRing);
|
||||||
|
saveKeyRing(context, privRing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -260,190 +333,22 @@ public class ProviderHelper {
|
|||||||
return ContentProviderOperation.newInsert(uri).withValues(values).build();
|
return ContentProviderOperation.newInsert(uri).withValues(values).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Private helper method
|
|
||||||
*/
|
|
||||||
private static ArrayList<Long> getKeyRingsMasterKeyIds(Context context, Uri queryUri) {
|
|
||||||
Cursor cursor = context.getContentResolver().query(queryUri,
|
|
||||||
new String[]{KeyRings.MASTER_KEY_ID}, null, null, null);
|
|
||||||
|
|
||||||
ArrayList<Long> masterKeyIds = new ArrayList<Long>();
|
|
||||||
if (cursor != null) {
|
|
||||||
int masterKeyIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
do {
|
|
||||||
masterKeyIds.add(cursor.getLong(masterKeyIdCol));
|
|
||||||
} while (cursor.moveToNext());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return masterKeyIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deletePublicKeyRing(Context context, long masterKeyId) {
|
|
||||||
ContentResolver cr = context.getContentResolver();
|
|
||||||
cr.delete(KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteSecretKeyRing(Context context, long masterKeyId) {
|
|
||||||
ContentResolver cr = context.getContentResolver();
|
|
||||||
cr.delete(KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean getMasterKeyCanCertify(Context context, Uri queryUri) {
|
|
||||||
// TODO redo
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
String[] projection = new String[]{
|
|
||||||
KeyRings.MASTER_KEY_ID,
|
|
||||||
"(SELECT COUNT(sign_keys." + Keys._ID + ") FROM " + Tables.KEYS
|
|
||||||
+ " AS sign_keys WHERE sign_keys." + Keys.KEY_RING_ROW_ID + " = "
|
|
||||||
+ KeychainDatabase.Tables.KEY_RINGS + "." + KeyRings._ID
|
|
||||||
+ " AND sign_keys." + Keys.CAN_CERTIFY + " = '1' AND " + Keys.IS_MASTER_KEY
|
|
||||||
+ " = 1) AS sign",};
|
|
||||||
|
|
||||||
ContentResolver cr = context.getContentResolver();
|
|
||||||
Cursor cursor = cr.query(queryUri, projection, null, null, null);
|
|
||||||
|
|
||||||
long masterKeyId = -1;
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
int masterKeyIdCol = cursor.getColumnIndex("sign");
|
|
||||||
|
|
||||||
masterKeyId = cursor.getLong(masterKeyIdCol);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (masterKeyId > 0);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasSecretKeyByMasterKeyId(Context context, long masterKeyId) {
|
public static boolean hasSecretKeyByMasterKeyId(Context context, long masterKeyId) {
|
||||||
Uri queryUri = KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId));
|
Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
|
||||||
// see if we can get our master key id back from the uri
|
// see if we can get our master key id back from the uri
|
||||||
return getMasterKeyId(context, queryUri) == masterKeyId;
|
return getMasterKeyId(context, queryUri) == masterKeyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static ArrayList<String> getKeyRingsAsArmoredString(Context context, long[] masterKeyIds) {
|
||||||
* Get master key id of key
|
|
||||||
*/
|
|
||||||
public static long getMasterKeyId(Context context, Uri queryUri) {
|
|
||||||
String[] projection = new String[]{KeyRings.MASTER_KEY_ID};
|
|
||||||
Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null);
|
|
||||||
|
|
||||||
long masterKeyId = 0;
|
|
||||||
try {
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
int masterKeyIdCol = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID);
|
|
||||||
|
|
||||||
masterKeyId = cursor.getLong(masterKeyIdCol);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return masterKeyId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getRowId(Context context, Uri queryUri) {
|
|
||||||
String[] projection = new String[]{KeyRings._ID};
|
|
||||||
Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null);
|
|
||||||
|
|
||||||
long rowId = 0;
|
|
||||||
try {
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
int idCol = cursor.getColumnIndexOrThrow(KeyRings._ID);
|
|
||||||
|
|
||||||
rowId = cursor.getLong(idCol);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rowId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get fingerprint of key
|
|
||||||
*/
|
|
||||||
public static byte[] getFingerprint(Context context, Uri queryUri) {
|
|
||||||
String[] projection = new String[]{Keys.FINGERPRINT};
|
|
||||||
Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null);
|
|
||||||
|
|
||||||
byte[] fingerprint = null;
|
|
||||||
try {
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
int col = cursor.getColumnIndexOrThrow(Keys.FINGERPRINT);
|
|
||||||
|
|
||||||
fingerprint = cursor.getBlob(col);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FALLBACK: If fingerprint is not in database, get it from key blob!
|
|
||||||
// this could happen if the key was saved by a previous version of Keychain!
|
|
||||||
if (fingerprint == null) {
|
|
||||||
Log.d(Constants.TAG, "FALLBACK: fingerprint is not in database, get it from key blob!");
|
|
||||||
|
|
||||||
// get master key id
|
|
||||||
projection = new String[]{KeyRings.MASTER_KEY_ID};
|
|
||||||
cursor = context.getContentResolver().query(queryUri, projection, null, null, null);
|
|
||||||
long masterKeyId = 0;
|
|
||||||
try {
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
int col = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID);
|
|
||||||
|
|
||||||
masterKeyId = cursor.getLong(col);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PGPPublicKey key = ProviderHelper.getPGPPublicKeyRing(context, masterKeyId).getPublicKey();
|
|
||||||
// if it is no public key get it from your own keys...
|
|
||||||
if (key == null) {
|
|
||||||
PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId).getSecretKey();
|
|
||||||
if (secretKey == null) {
|
|
||||||
Log.e(Constants.TAG, "Key could not be found!");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
key = secretKey.getPublicKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
fingerprint = key.getFingerprint();
|
|
||||||
}
|
|
||||||
|
|
||||||
return fingerprint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ArrayList<String> getKeyRingsAsArmoredString(Context context, Uri uri,
|
|
||||||
long[] masterKeyIds) {
|
|
||||||
ArrayList<String> output = new ArrayList<String>();
|
ArrayList<String> output = new ArrayList<String>();
|
||||||
|
|
||||||
if (masterKeyIds != null && masterKeyIds.length > 0) {
|
if (masterKeyIds != null && masterKeyIds.length > 0) {
|
||||||
|
|
||||||
Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, uri, masterKeyIds);
|
Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, masterKeyIds);
|
||||||
|
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
int masterIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
|
int masterIdCol = cursor.getColumnIndex(KeyRingData.MASTER_KEY_ID);
|
||||||
int dataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA);
|
int dataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
|
||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
do {
|
do {
|
||||||
Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol));
|
Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol));
|
||||||
@ -493,48 +398,11 @@ public class ProviderHelper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static Cursor getCursorWithSelectedKeyringMasterKeyIds(Context context, long[] masterKeyIds) {
|
||||||
public static byte[] getKeyRingsAsByteArray(Context context, Uri uri, long[] masterKeyIds) {
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
if (masterKeyIds != null && masterKeyIds.length > 0) {
|
|
||||||
|
|
||||||
Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, uri, masterKeyIds);
|
|
||||||
|
|
||||||
if (cursor != null) {
|
|
||||||
int masterIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
|
|
||||||
int dataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA);
|
|
||||||
if (cursor.moveToFirst()) {
|
|
||||||
do {
|
|
||||||
Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol));
|
|
||||||
|
|
||||||
// get actual keyring data blob and write it to ByteArrayOutputStream
|
|
||||||
try {
|
|
||||||
bos.write(cursor.getBlob(dataCol));
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(Constants.TAG, "IOException", e);
|
|
||||||
}
|
|
||||||
} while (cursor.moveToNext());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log.e(Constants.TAG, "No master keys given!");
|
|
||||||
}
|
|
||||||
|
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Cursor getCursorWithSelectedKeyringMasterKeyIds(Context context, Uri baseUri,
|
|
||||||
long[] masterKeyIds) {
|
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
if (masterKeyIds != null && masterKeyIds.length > 0) {
|
if (masterKeyIds != null && masterKeyIds.length > 0) {
|
||||||
|
|
||||||
String inMasterKeyList = KeyRings.MASTER_KEY_ID + " IN (";
|
String inMasterKeyList = KeyRingData.MASTER_KEY_ID + " IN (";
|
||||||
for (int i = 0; i < masterKeyIds.length; ++i) {
|
for (int i = 0; i < masterKeyIds.length; ++i) {
|
||||||
if (i != 0) {
|
if (i != 0) {
|
||||||
inMasterKeyList += ", ";
|
inMasterKeyList += ", ";
|
||||||
@ -543,9 +411,9 @@ public class ProviderHelper {
|
|||||||
}
|
}
|
||||||
inMasterKeyList += ")";
|
inMasterKeyList += ")";
|
||||||
|
|
||||||
cursor = context.getContentResolver().query(baseUri,
|
cursor = context.getContentResolver().query(KeyRingData.buildPublicKeyRingUri(), new String[] {
|
||||||
new String[]{KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.KEY_RING_DATA},
|
KeyRingData._ID, KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA
|
||||||
inMasterKeyList, null, null);
|
}, inMasterKeyList, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cursor;
|
return cursor;
|
||||||
|
@ -35,7 +35,8 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
|
|||||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
|
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
|
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity;
|
import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity;
|
||||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||||
@ -61,15 +62,15 @@ public class OpenPgpService extends RemoteService {
|
|||||||
ArrayList<Long> keyIds = new ArrayList<Long>();
|
ArrayList<Long> keyIds = new ArrayList<Long>();
|
||||||
|
|
||||||
boolean missingUserIdsCheck = false;
|
boolean missingUserIdsCheck = false;
|
||||||
boolean dublicateUserIdsCheck = false;
|
boolean duplicateUserIdsCheck = false;
|
||||||
ArrayList<String> missingUserIds = new ArrayList<String>();
|
ArrayList<String> missingUserIds = new ArrayList<String>();
|
||||||
ArrayList<String> dublicateUserIds = new ArrayList<String>();
|
ArrayList<String> duplicateUserIds = new ArrayList<String>();
|
||||||
|
|
||||||
for (String email : encryptionUserIds) {
|
for (String email : encryptionUserIds) {
|
||||||
Uri uri = KeychainContract.KeyRings.buildUnifiedKeyRingsByEmailUri(email);
|
Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email);
|
||||||
Cursor cur = getContentResolver().query(uri, null, null, null, null);
|
Cursor cur = getContentResolver().query(uri, null, null, null, null);
|
||||||
if (cur.moveToFirst()) {
|
if (cur.moveToFirst()) {
|
||||||
long id = cur.getLong(cur.getColumnIndex(KeychainContract.KeyRings.MASTER_KEY_ID));
|
long id = cur.getLong(cur.getColumnIndex(KeyRings.MASTER_KEY_ID));
|
||||||
keyIds.add(id);
|
keyIds.add(id);
|
||||||
} else {
|
} else {
|
||||||
missingUserIdsCheck = true;
|
missingUserIdsCheck = true;
|
||||||
@ -77,8 +78,8 @@ public class OpenPgpService extends RemoteService {
|
|||||||
Log.d(Constants.TAG, "user id missing");
|
Log.d(Constants.TAG, "user id missing");
|
||||||
}
|
}
|
||||||
if (cur.moveToNext()) {
|
if (cur.moveToNext()) {
|
||||||
dublicateUserIdsCheck = true;
|
duplicateUserIdsCheck = true;
|
||||||
dublicateUserIds.add(email);
|
duplicateUserIds.add(email);
|
||||||
Log.d(Constants.TAG, "more than one user id with the same email");
|
Log.d(Constants.TAG, "more than one user id with the same email");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,13 +91,13 @@ public class OpenPgpService extends RemoteService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allow the user to verify pub key selection
|
// allow the user to verify pub key selection
|
||||||
if (missingUserIdsCheck || dublicateUserIdsCheck) {
|
if (missingUserIdsCheck || duplicateUserIdsCheck) {
|
||||||
// build PendingIntent
|
// build PendingIntent
|
||||||
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
|
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
|
||||||
intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS);
|
intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
|
intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
|
intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds);
|
intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, duplicateUserIds);
|
||||||
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
|
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
|
||||||
|
|
||||||
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
|
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
|
||||||
@ -351,7 +352,7 @@ public class OpenPgpService extends RemoteService {
|
|||||||
try {
|
try {
|
||||||
long keyId = data.getLongExtra(OpenPgpApi.EXTRA_KEY_ID, 0);
|
long keyId = data.getLongExtra(OpenPgpApi.EXTRA_KEY_ID, 0);
|
||||||
|
|
||||||
if (ProviderHelper.getPGPPublicKeyByKeyId(this, keyId) == null) {
|
if (ProviderHelper.getPGPPublicKeyRing(this, keyId) == null) {
|
||||||
Intent result = new Intent();
|
Intent result = new Intent();
|
||||||
|
|
||||||
// If keys are not in db we return an additional PendingIntent
|
// If keys are not in db we return an additional PendingIntent
|
||||||
@ -462,7 +463,7 @@ public class OpenPgpService extends RemoteService {
|
|||||||
String currentPkg = getCurrentCallingPackage();
|
String currentPkg = getCurrentCallingPackage();
|
||||||
Set<Long> allowedKeyIds =
|
Set<Long> allowedKeyIds =
|
||||||
ProviderHelper.getAllKeyIdsForApp(mContext,
|
ProviderHelper.getAllKeyIdsForApp(mContext,
|
||||||
KeychainContract.ApiAccounts.buildBaseUri(currentPkg));
|
ApiAccounts.buildBaseUri(currentPkg));
|
||||||
return decryptAndVerifyImpl(data, input, output, allowedKeyIds);
|
return decryptAndVerifyImpl(data, input, output, allowedKeyIds);
|
||||||
} else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
|
} else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
|
||||||
return getKeyImpl(data);
|
return getKeyImpl(data);
|
||||||
|
@ -34,6 +34,7 @@ import com.beardedhen.androidbootstrap.BootstrapButton;
|
|||||||
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.remote.AccountSettings;
|
import org.sufficientlysecure.keychain.remote.AccountSettings;
|
||||||
import org.sufficientlysecure.keychain.ui.EditKeyActivity;
|
import org.sufficientlysecure.keychain.ui.EditKeyActivity;
|
||||||
import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment;
|
import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment;
|
||||||
@ -176,9 +177,8 @@ public class AccountSettingsFragment extends Fragment implements
|
|||||||
case REQUEST_CODE_CREATE_KEY: {
|
case REQUEST_CODE_CREATE_KEY: {
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
// select newly created key
|
// select newly created key
|
||||||
Uri newKeyUri = data.getData();
|
long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), data.getData());
|
||||||
// TODO helper method for this?
|
mSelectKeyFragment.selectKey(masterKeyId);
|
||||||
mSelectKeyFragment.selectKey(Long.parseLong(newKeyUri.getPathSegments().get(1)));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.service;
|
|||||||
|
|
||||||
import android.app.IntentService;
|
import android.app.IntentService;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
@ -50,6 +51,8 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
|
|||||||
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
|
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||||
import org.sufficientlysecure.keychain.util.HkpKeyServer;
|
import org.sufficientlysecure.keychain.util.HkpKeyServer;
|
||||||
@ -147,7 +150,7 @@ public class KeychainIntentService extends IntentService
|
|||||||
// export key
|
// export key
|
||||||
public static final String EXPORT_OUTPUT_STREAM = "export_output_stream";
|
public static final String EXPORT_OUTPUT_STREAM = "export_output_stream";
|
||||||
public static final String EXPORT_FILENAME = "export_filename";
|
public static final String EXPORT_FILENAME = "export_filename";
|
||||||
public static final String EXPORT_KEY_TYPE = "export_key_type";
|
public static final String EXPORT_SECRET = "export_secret";
|
||||||
public static final String EXPORT_ALL = "export_all";
|
public static final String EXPORT_ALL = "export_all";
|
||||||
public static final String EXPORT_KEY_RING_MASTER_KEY_ID = "export_key_ring_id";
|
public static final String EXPORT_KEY_RING_MASTER_KEY_ID = "export_key_ring_id";
|
||||||
|
|
||||||
@ -508,8 +511,8 @@ public class KeychainIntentService extends IntentService
|
|||||||
PgpKeyOperation.Pair<PGPSecretKeyRing,PGPPublicKeyRing> pair =
|
PgpKeyOperation.Pair<PGPSecretKeyRing,PGPPublicKeyRing> pair =
|
||||||
keyOperations.buildSecretKey(privkey, pubkey, saveParams);
|
keyOperations.buildSecretKey(privkey, pubkey, saveParams);
|
||||||
setProgress(R.string.progress_saving_key_ring, 90, 100);
|
setProgress(R.string.progress_saving_key_ring, 90, 100);
|
||||||
ProviderHelper.saveKeyRing(this, pair.first);
|
// save the pair
|
||||||
ProviderHelper.saveKeyRing(this, pair.second);
|
ProviderHelper.saveKeyRing(this, pair.second, pair.first);
|
||||||
setProgress(R.string.progress_done, 100, 100);
|
setProgress(R.string.progress_done, 100, 100);
|
||||||
}
|
}
|
||||||
PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase);
|
PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase);
|
||||||
@ -635,19 +638,13 @@ public class KeychainIntentService extends IntentService
|
|||||||
} else if (ACTION_EXPORT_KEYRING.equals(action)) {
|
} else if (ACTION_EXPORT_KEYRING.equals(action)) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
/* Input */
|
boolean exportSecret = data.getBoolean(EXPORT_SECRET, false);
|
||||||
int keyType = Id.type.public_key;
|
|
||||||
if (data.containsKey(EXPORT_KEY_TYPE)) {
|
|
||||||
keyType = data.getInt(EXPORT_KEY_TYPE);
|
|
||||||
}
|
|
||||||
long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
|
long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
|
||||||
String outputFile = data.getString(EXPORT_FILENAME);
|
String outputFile = data.getString(EXPORT_FILENAME);
|
||||||
|
|
||||||
// If not exporting all keys get the masterKeyIds of the keys to export from the intent
|
// If not exporting all keys get the masterKeyIds of the keys to export from the intent
|
||||||
boolean exportAll = data.getBoolean(EXPORT_ALL);
|
boolean exportAll = data.getBoolean(EXPORT_ALL);
|
||||||
|
|
||||||
/* Operation */
|
|
||||||
|
|
||||||
// check if storage is ready
|
// check if storage is ready
|
||||||
if (!FileHelper.isStorageMounted(outputFile)) {
|
if (!FileHelper.isStorageMounted(outputFile)) {
|
||||||
throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
|
throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
|
||||||
@ -655,31 +652,30 @@ public class KeychainIntentService extends IntentService
|
|||||||
|
|
||||||
ArrayList<Long> publicMasterKeyIds = new ArrayList<Long>();
|
ArrayList<Long> publicMasterKeyIds = new ArrayList<Long>();
|
||||||
ArrayList<Long> secretMasterKeyIds = new ArrayList<Long>();
|
ArrayList<Long> secretMasterKeyIds = new ArrayList<Long>();
|
||||||
// TODO redo
|
|
||||||
ArrayList<Long> allPublicMasterKeyIds = null; // ProviderHelper.getPublicKeyRingsMasterKeyIds(this);
|
|
||||||
ArrayList<Long> allSecretMasterKeyIds = null; // ProviderHelper.getSecretKeyRingsMasterKeyIds(this);
|
|
||||||
|
|
||||||
if (exportAll) {
|
String selection = null;
|
||||||
// get all public key ring MasterKey ids
|
if(!exportAll) {
|
||||||
if (keyType == Id.type.public_key || keyType == Id.type.public_secret_key) {
|
selection = KeychainDatabase.Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + " IN( ";
|
||||||
publicMasterKeyIds = allPublicMasterKeyIds;
|
for(long l : masterKeyIds) {
|
||||||
|
selection += Long.toString(l) + ",";
|
||||||
}
|
}
|
||||||
// get all secret key ring MasterKey ids
|
selection = selection.substring(0, selection.length()-1) + " )";
|
||||||
if (keyType == Id.type.secret_key || keyType == Id.type.public_secret_key) {
|
|
||||||
secretMasterKeyIds = allSecretMasterKeyIds;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
|
||||||
for (long masterKeyId : masterKeyIds) {
|
Cursor cursor = getContentResolver().query(KeyRings.buildUnifiedKeyRingsUri(),
|
||||||
if ((keyType == Id.type.public_key || keyType == Id.type.public_secret_key)
|
new String[]{ KeyRings.MASTER_KEY_ID, KeyRings.HAS_SECRET },
|
||||||
&& allPublicMasterKeyIds.contains(masterKeyId)) {
|
selection, null, null);
|
||||||
publicMasterKeyIds.add(masterKeyId);
|
try {
|
||||||
}
|
cursor.moveToFirst();
|
||||||
if ((keyType == Id.type.secret_key || keyType == Id.type.public_secret_key)
|
do {
|
||||||
&& allSecretMasterKeyIds.contains(masterKeyId)) {
|
// export public either way
|
||||||
secretMasterKeyIds.add(masterKeyId);
|
publicMasterKeyIds.add(cursor.getLong(0));
|
||||||
}
|
// add secret if available (and requested)
|
||||||
}
|
if(exportSecret && cursor.getInt(1) != 0)
|
||||||
|
secretMasterKeyIds.add(cursor.getLong(0));
|
||||||
|
} while(cursor.moveToNext());
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
PgpImportExport pgpImportExport = new PgpImportExport(this, this, this);
|
PgpImportExport pgpImportExport = new PgpImportExport(this, this, this);
|
||||||
|
@ -46,6 +46,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.Id;
|
import org.sufficientlysecure.keychain.Id;
|
||||||
import org.sufficientlysecure.keychain.helper.Preferences;
|
import org.sufficientlysecure.keychain.helper.Preferences;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -170,16 +171,12 @@ public class PassphraseCacheService extends Service {
|
|||||||
// try to get master key id which is used as an identifier for cached passphrases
|
// try to get master key id which is used as an identifier for cached passphrases
|
||||||
long masterKeyId = keyId;
|
long masterKeyId = keyId;
|
||||||
if (masterKeyId != Id.key.symmetric) {
|
if (masterKeyId != Id.key.symmetric) {
|
||||||
PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingWithKeyId(this, keyId);
|
masterKeyId = ProviderHelper.getMasterKeyId(this,
|
||||||
if (keyRing == null) {
|
KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId)));
|
||||||
|
// Failure
|
||||||
|
if(masterKeyId == 0)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
PGPSecretKey masterKey = PgpKeyHelper.getMasterKey(keyRing);
|
|
||||||
if (masterKey == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
masterKeyId = masterKey.getKeyID();
|
|
||||||
}
|
|
||||||
Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + masterKeyId);
|
Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + masterKeyId);
|
||||||
|
|
||||||
// get cached passphrase
|
// get cached passphrase
|
||||||
|
@ -57,6 +57,7 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
|||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
||||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||||
@ -276,8 +277,6 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
|
|
||||||
// get master key id using row id
|
// get master key id using row id
|
||||||
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
|
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
|
||||||
|
|
||||||
mMasterCanSign = ProviderHelper.getMasterKeyCanCertify(this, mDataUri);
|
|
||||||
finallyEdit(masterKeyId);
|
finallyEdit(masterKeyId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -312,15 +311,13 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
Toast.makeText(this, R.string.error_save_first, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.error_save_first, Toast.LENGTH_LONG).show();
|
||||||
} else {
|
} else {
|
||||||
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
|
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
|
||||||
long[] ids = new long[]{masterKeyId};
|
mExportHelper.showExportKeysDialog(
|
||||||
mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC,
|
new long[] { masterKeyId }, Constants.Path.APP_DIR_FILE_SEC, true);
|
||||||
null);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_key_edit_delete:
|
case R.id.menu_key_edit_delete:
|
||||||
long rowId= ProviderHelper.getRowId(this,mDataUri);
|
Uri convertUri = KeyRingData.buildSecretKeyRingUri(mDataUri);
|
||||||
Uri convertUri = KeychainContract.KeyRings.buildSecretKeyRingUri(Long.toString(rowId));
|
|
||||||
// Message is received after key is deleted
|
// Message is received after key is deleted
|
||||||
Handler returnHandler = new Handler() {
|
Handler returnHandler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
@ -346,7 +343,8 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
PGPSecretKey masterKey = null;
|
PGPSecretKey masterKey = null;
|
||||||
mKeyRing = ProviderHelper.getPGPSecretKeyRing(this, masterKeyId);
|
mKeyRing = ProviderHelper.getPGPSecretKeyRing(this, masterKeyId);
|
||||||
if (mKeyRing != null) {
|
if (mKeyRing != null) {
|
||||||
masterKey = PgpKeyHelper.getMasterKey(mKeyRing);
|
masterKey = mKeyRing.getSecretKey();
|
||||||
|
mMasterCanSign = PgpKeyHelper.isCertificationKey(mKeyRing.getSecretKey());
|
||||||
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(mKeyRing.getSecretKeys())) {
|
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(mKeyRing.getSecretKeys())) {
|
||||||
mKeys.add(key);
|
mKeys.add(key);
|
||||||
mKeysUsages.add(-1); // get usage when view is created
|
mKeysUsages.add(-1); // get usage when view is created
|
||||||
@ -354,6 +352,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
|
|||||||
} else {
|
} else {
|
||||||
Log.e(Constants.TAG, "Keyring not found with masterKeyId: " + masterKeyId);
|
Log.e(Constants.TAG, "Keyring not found with masterKeyId: " + masterKeyId);
|
||||||
Toast.makeText(this, R.string.error_no_secret_key_found, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.error_no_secret_key_found, Toast.LENGTH_LONG).show();
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
if (masterKey != null) {
|
if (masterKey != null) {
|
||||||
boolean isSet = false;
|
boolean isSet = false;
|
||||||
|
@ -37,8 +37,10 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
|
|||||||
import org.sufficientlysecure.keychain.Id;
|
import org.sufficientlysecure.keychain.Id;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
public class EncryptAsymmetricFragment extends Fragment {
|
public class EncryptAsymmetricFragment extends Fragment {
|
||||||
@ -145,7 +147,7 @@ public class EncryptAsymmetricFragment extends Fragment {
|
|||||||
preselectedSignatureKeyId);
|
preselectedSignatureKeyId);
|
||||||
PGPSecretKey masterKey;
|
PGPSecretKey masterKey;
|
||||||
if (keyRing != null) {
|
if (keyRing != null) {
|
||||||
masterKey = PgpKeyHelper.getMasterKey(keyRing);
|
masterKey = keyRing.getSecretKey();
|
||||||
if (masterKey != null) {
|
if (masterKey != null) {
|
||||||
Vector<PGPSecretKey> signKeys = PgpKeyHelper.getUsableSigningKeys(keyRing);
|
Vector<PGPSecretKey> signKeys = PgpKeyHelper.getUsableSigningKeys(keyRing);
|
||||||
if (signKeys.size() > 0) {
|
if (signKeys.size() > 0) {
|
||||||
@ -158,23 +160,11 @@ public class EncryptAsymmetricFragment extends Fragment {
|
|||||||
if (preselectedEncryptionKeyIds != null) {
|
if (preselectedEncryptionKeyIds != null) {
|
||||||
Vector<Long> goodIds = new Vector<Long>();
|
Vector<Long> goodIds = new Vector<Long>();
|
||||||
for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) {
|
for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) {
|
||||||
// TODO: don't use bouncy castle objects!
|
long id = ProviderHelper.getMasterKeyId(getActivity(),
|
||||||
|
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(preselectedEncryptionKeyIds[i]))
|
||||||
PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId(getActivity(),
|
);
|
||||||
preselectedEncryptionKeyIds[i]);
|
// TODO check for available encrypt keys... is this even relevant?
|
||||||
PGPPublicKey masterKey;
|
goodIds.add(id);
|
||||||
if (keyRing == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
masterKey = PgpKeyHelper.getMasterKey(keyRing);
|
|
||||||
if (masterKey == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Vector<PGPPublicKey> encryptKeys = PgpKeyHelper.getUsableEncryptKeys(keyRing);
|
|
||||||
if (encryptKeys.size() == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
goodIds.add(masterKey.getKeyID());
|
|
||||||
}
|
}
|
||||||
if (goodIds.size() > 0) {
|
if (goodIds.size() > 0) {
|
||||||
long[] keyIds = new long[goodIds.size()];
|
long[] keyIds = new long[goodIds.size()];
|
||||||
@ -202,20 +192,17 @@ public class EncryptAsymmetricFragment extends Fragment {
|
|||||||
} else {
|
} else {
|
||||||
String uid = getResources().getString(R.string.user_id_no_name);
|
String uid = getResources().getString(R.string.user_id_no_name);
|
||||||
String uidExtra = "";
|
String uidExtra = "";
|
||||||
// TODO: don't use bouncy castle objects!
|
// See if we can get a user_id from a unified query
|
||||||
PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingWithKeyId(getActivity(),
|
String user_id = (String) ProviderHelper.getUnifiedData(
|
||||||
mSecretKeyId);
|
getActivity(), mSecretKeyId, KeyRings.USER_ID, ProviderHelper.FIELD_TYPE_STRING);
|
||||||
if (keyRing != null) {
|
if(user_id != null) {
|
||||||
PGPSecretKey key = PgpKeyHelper.getMasterKey(keyRing);
|
String chunks[] = user_id.split(" <", 2);
|
||||||
if (key != null) {
|
|
||||||
String userId = PgpKeyHelper.getMainUserIdSafe(getActivity(), key);
|
|
||||||
String chunks[] = userId.split(" <", 2);
|
|
||||||
uid = chunks[0];
|
uid = chunks[0];
|
||||||
if (chunks.length > 1) {
|
if (chunks.length > 1) {
|
||||||
uidExtra = "<" + chunks[1];
|
uidExtra = "<" + chunks[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mMainUserId.setText(uid);
|
mMainUserId.setText(uid);
|
||||||
mMainUserIdRest.setText(uidExtra);
|
mMainUserIdRest.setText(uidExtra);
|
||||||
mSign.setChecked(true);
|
mSign.setChecked(true);
|
||||||
|
@ -23,7 +23,6 @@ import android.view.Menu;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.Id;
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.helper.ExportHelper;
|
import org.sufficientlysecure.keychain.helper.ExportHelper;
|
||||||
|
|
||||||
@ -55,26 +54,20 @@ public class KeyListActivity extends DrawerActivity {
|
|||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.menu_key_list_import:
|
case R.id.menu_key_list_import:
|
||||||
callIntentForDrawerItem(Constants.DrawerItems.IMPORT_KEYS);
|
callIntentForDrawerItem(Constants.DrawerItems.IMPORT_KEYS);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case R.id.menu_key_list_create:
|
case R.id.menu_key_list_create:
|
||||||
createKey();
|
createKey();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case R.id.menu_key_list_create_expert:
|
case R.id.menu_key_list_create_expert:
|
||||||
createKeyExpert();
|
createKeyExpert();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_key_list_export_public:
|
|
||||||
mExportHelper.showExportKeysDialog(null,
|
|
||||||
Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB, null);
|
|
||||||
|
|
||||||
|
case R.id.menu_key_list_export:
|
||||||
|
mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE_PUB, true);
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_key_list_secret_export:
|
|
||||||
mExportHelper.showExportKeysDialog(null, Id.type.secret_key,
|
|
||||||
Constants.Path.APP_DIR_FILE_SEC, null);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
@ -58,12 +58,8 @@ import org.sufficientlysecure.keychain.Id;
|
|||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.helper.ExportHelper;
|
import org.sufficientlysecure.keychain.helper.ExportHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
@ -71,7 +67,6 @@ import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
|
|||||||
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
|
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
|
||||||
import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
|
import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,9 +152,6 @@ public class KeyListFragment extends Fragment
|
|||||||
} catch (ApiLevelTooLowException e) {
|
} catch (ApiLevelTooLowException e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this view is made visible if no data is available
|
|
||||||
mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only
|
* ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only
|
||||||
* available for Android >= 3.0
|
* available for Android >= 3.0
|
||||||
@ -193,30 +185,15 @@ public class KeyListFragment extends Fragment
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case R.id.menu_key_list_multi_delete: {
|
case R.id.menu_key_list_multi_delete: {
|
||||||
ids = mStickyList.getWrappedList().getCheckedItemIds();
|
ids = mAdapter.getCurrentSelectedMasterKeyIds();
|
||||||
showDeleteKeyDialog(mode, ids);
|
showDeleteKeyDialog(mode, ids);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case R.id.menu_key_list_multi_export: {
|
case R.id.menu_key_list_multi_export: {
|
||||||
ids = mStickyList.getWrappedList().getCheckedItemIds();
|
ids = mAdapter.getCurrentSelectedMasterKeyIds();
|
||||||
long[] masterKeyIds = new long[2*ids.length];
|
|
||||||
/* TODO! redo
|
|
||||||
ArrayList<Long> allPubRowIds =
|
|
||||||
ProviderHelper.getPublicKeyRingsRowIds(getActivity());
|
|
||||||
for (int i = 0; i < ids.length; i++) {
|
|
||||||
if (allPubRowIds.contains(ids[i])) {
|
|
||||||
masterKeyIds[i] =
|
|
||||||
ProviderHelper.getPublicMasterKeyId(getActivity(), ids[i]);
|
|
||||||
} else {
|
|
||||||
masterKeyIds[i] =
|
|
||||||
ProviderHelper.getSecretMasterKeyId(getActivity(), ids[i]);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
|
ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
|
||||||
mExportHelper
|
mExportHelper.showExportKeysDialog(
|
||||||
.showExportKeysDialog(masterKeyIds, Id.type.public_key,
|
ids, Constants.Path.APP_DIR_FILE_PUB, mAdapter.isAnySecretSelected());
|
||||||
Constants.Path.APP_DIR_FILE_PUB,
|
|
||||||
getString(R.string.also_export_secret_keys));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case R.id.menu_key_list_multi_select_all: {
|
case R.id.menu_key_list_multi_select_all: {
|
||||||
@ -270,11 +247,11 @@ public class KeyListFragment extends Fragment
|
|||||||
|
|
||||||
// These are the rows that we will retrieve.
|
// These are the rows that we will retrieve.
|
||||||
static final String[] PROJECTION = new String[]{
|
static final String[] PROJECTION = new String[]{
|
||||||
KeychainContract.KeyRings._ID,
|
KeyRings._ID,
|
||||||
KeychainContract.Keys.MASTER_KEY_ID,
|
KeyRings.MASTER_KEY_ID,
|
||||||
KeychainContract.UserIds.USER_ID,
|
KeyRings.USER_ID,
|
||||||
KeychainContract.Keys.IS_REVOKED,
|
KeyRings.IS_REVOKED,
|
||||||
KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID
|
KeyRings.HAS_SECRET
|
||||||
};
|
};
|
||||||
|
|
||||||
static final int INDEX_MASTER_KEY_ID = 1;
|
static final int INDEX_MASTER_KEY_ID = 1;
|
||||||
@ -282,12 +259,6 @@ public class KeyListFragment extends Fragment
|
|||||||
static final int INDEX_IS_REVOKED = 3;
|
static final int INDEX_IS_REVOKED = 3;
|
||||||
static final int INDEX_HAS_SECRET = 4;
|
static final int INDEX_HAS_SECRET = 4;
|
||||||
|
|
||||||
static final String SORT_ORDER =
|
|
||||||
// show secret before public key
|
|
||||||
KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID + " IS NULL ASC, " +
|
|
||||||
// sort by user id otherwise
|
|
||||||
UserIds.USER_ID + " ASC";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||||
// This is called when a new Loader needs to be created. This
|
// This is called when a new Loader needs to be created. This
|
||||||
@ -296,12 +267,12 @@ public class KeyListFragment extends Fragment
|
|||||||
String where = null;
|
String where = null;
|
||||||
String whereArgs[] = null;
|
String whereArgs[] = null;
|
||||||
if (mCurQuery != null) {
|
if (mCurQuery != null) {
|
||||||
where = KeychainContract.UserIds.USER_ID + " LIKE ?";
|
where = KeyRings.USER_ID + " LIKE ?";
|
||||||
whereArgs = new String[]{"%" + mCurQuery + "%"};
|
whereArgs = new String[]{"%" + mCurQuery + "%"};
|
||||||
}
|
}
|
||||||
// Now create and return a CursorLoader that will take care of
|
// Now create and return a CursorLoader that will take care of
|
||||||
// creating a Cursor for the data being displayed.
|
// creating a Cursor for the data being displayed.
|
||||||
return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, SORT_ORDER);
|
return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -313,6 +284,9 @@ public class KeyListFragment extends Fragment
|
|||||||
|
|
||||||
mStickyList.setAdapter(mAdapter);
|
mStickyList.setAdapter(mAdapter);
|
||||||
|
|
||||||
|
// this view is made visible if no data is available
|
||||||
|
mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty));
|
||||||
|
|
||||||
// NOTE: Not supported by StickyListHeader, but reimplemented here
|
// NOTE: Not supported by StickyListHeader, but reimplemented here
|
||||||
// The list should now be shown.
|
// The list should now be shown.
|
||||||
if (isResumed()) {
|
if (isResumed()) {
|
||||||
@ -342,17 +316,15 @@ public class KeyListFragment extends Fragment
|
|||||||
viewIntent = new Intent(getActivity(), ViewKeyActivityJB.class);
|
viewIntent = new Intent(getActivity(), ViewKeyActivityJB.class);
|
||||||
}
|
}
|
||||||
viewIntent.setData(
|
viewIntent.setData(
|
||||||
KeychainContract
|
KeyRings.buildGenericKeyRingUri(Long.toString(mAdapter.getMasterKeyId(position))));
|
||||||
.KeyRings.buildPublicKeyRingUri(
|
|
||||||
Long.toString(mAdapter.getMasterKeyId(position))));
|
|
||||||
startActivity(viewIntent);
|
startActivity(viewIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(11)
|
@TargetApi(11)
|
||||||
protected void encrypt(ActionMode mode, long[] keyRingMasterKeyIds) {
|
protected void encrypt(ActionMode mode, long[] masterKeyIds) {
|
||||||
Intent intent = new Intent(getActivity(), EncryptActivity.class);
|
Intent intent = new Intent(getActivity(), EncryptActivity.class);
|
||||||
intent.setAction(EncryptActivity.ACTION_ENCRYPT);
|
intent.setAction(EncryptActivity.ACTION_ENCRYPT);
|
||||||
intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, keyRingMasterKeyIds);
|
intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, masterKeyIds);
|
||||||
// used instead of startActivity set actionbar based on callingPackage
|
// used instead of startActivity set actionbar based on callingPackage
|
||||||
startActivityForResult(intent, 0);
|
startActivityForResult(intent, 0);
|
||||||
|
|
||||||
@ -362,11 +334,11 @@ public class KeyListFragment extends Fragment
|
|||||||
/**
|
/**
|
||||||
* Show dialog to delete key
|
* Show dialog to delete key
|
||||||
*
|
*
|
||||||
* @param keyRingRowIds
|
* @param masterKeyIds
|
||||||
*/
|
*/
|
||||||
@TargetApi(11)
|
@TargetApi(11)
|
||||||
// TODO: this method needs an overhaul to handle both public and secret keys gracefully!
|
// TODO: this method needs an overhaul to handle both public and secret keys gracefully!
|
||||||
public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
|
public void showDeleteKeyDialog(final ActionMode mode, long[] masterKeyIds) {
|
||||||
// Message is received after key is deleted
|
// Message is received after key is deleted
|
||||||
Handler returnHandler = new Handler() {
|
Handler returnHandler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
@ -381,7 +353,7 @@ public class KeyListFragment extends Fragment
|
|||||||
Messenger messenger = new Messenger(returnHandler);
|
Messenger messenger = new Messenger(returnHandler);
|
||||||
|
|
||||||
DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
|
DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
|
||||||
keyRingRowIds);
|
masterKeyIds);
|
||||||
|
|
||||||
deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog");
|
deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog");
|
||||||
}
|
}
|
||||||
@ -520,7 +492,7 @@ public class KeyListFragment extends Fragment
|
|||||||
Button button = (Button) view.findViewById(R.id.edit);
|
Button button = (Button) view.findViewById(R.id.edit);
|
||||||
TextView revoked = (TextView) view.findViewById(R.id.revoked);
|
TextView revoked = (TextView) view.findViewById(R.id.revoked);
|
||||||
|
|
||||||
if (!cursor.isNull(KeyListFragment.INDEX_HAS_SECRET)) {
|
if (cursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
|
||||||
// this is a secret key - show the edit button
|
// this is a secret key - show the edit button
|
||||||
statusDivider.setVisibility(View.VISIBLE);
|
statusDivider.setVisibility(View.VISIBLE);
|
||||||
statusLayout.setVisibility(View.VISIBLE);
|
statusLayout.setVisibility(View.VISIBLE);
|
||||||
@ -531,9 +503,7 @@ public class KeyListFragment extends Fragment
|
|||||||
button.setOnClickListener(new OnClickListener() {
|
button.setOnClickListener(new OnClickListener() {
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
|
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
|
||||||
editIntent.setData(
|
editIntent.setData(KeyRingData.buildSecretKeyRingUri(Long.toString(id)));
|
||||||
KeychainContract.KeyRings
|
|
||||||
.buildSecretKeyRingUri(Long.toString(id)));
|
|
||||||
editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
|
editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
|
||||||
startActivityForResult(editIntent, 0);
|
startActivityForResult(editIntent, 0);
|
||||||
}
|
}
|
||||||
@ -551,6 +521,13 @@ public class KeyListFragment extends Fragment
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSecretAvailable(int id) {
|
||||||
|
if (!mCursor.moveToPosition(id)) {
|
||||||
|
throw new IllegalStateException("couldn't move cursor to position " + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mCursor.getInt(INDEX_HAS_SECRET) != 0;
|
||||||
|
}
|
||||||
public long getMasterKeyId(int id) {
|
public long getMasterKeyId(int id) {
|
||||||
if (!mCursor.moveToPosition(id)) {
|
if (!mCursor.moveToPosition(id)) {
|
||||||
throw new IllegalStateException("couldn't move cursor to position " + id);
|
throw new IllegalStateException("couldn't move cursor to position " + id);
|
||||||
@ -594,7 +571,7 @@ public class KeyListFragment extends Fragment
|
|||||||
throw new IllegalStateException("couldn't move cursor to position " + position);
|
throw new IllegalStateException("couldn't move cursor to position " + position);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mCursor.isNull(KeyListFragment.INDEX_HAS_SECRET)) {
|
if (mCursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
|
||||||
{ // set contact count
|
{ // set contact count
|
||||||
int num = mCursor.getCount();
|
int num = mCursor.getCount();
|
||||||
String contactsTotal = getResources().getQuantityString(R.plurals.n_contacts, num, num);
|
String contactsTotal = getResources().getQuantityString(R.plurals.n_contacts, num, num);
|
||||||
@ -634,7 +611,7 @@ public class KeyListFragment extends Fragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
// early breakout: all secret keys are assigned id 0
|
// early breakout: all secret keys are assigned id 0
|
||||||
if (!mCursor.isNull(KeyListFragment.INDEX_HAS_SECRET)) {
|
if (mCursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
|
||||||
return 1L;
|
return 1L;
|
||||||
}
|
}
|
||||||
// otherwise, return the first character of the name as ID
|
// otherwise, return the first character of the name as ID
|
||||||
@ -659,6 +636,14 @@ public class KeyListFragment extends Fragment
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAnySecretSelected() {
|
||||||
|
for (int pos : mSelection.keySet()) {
|
||||||
|
if(mAdapter.isSecretAvailable(pos))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public long[] getCurrentSelectedMasterKeyIds() {
|
public long[] getCurrentSelectedMasterKeyIds() {
|
||||||
long[] ids = new long[mSelection.size()];
|
long[] ids = new long[mSelection.size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -29,6 +29,7 @@ import android.support.v7.app.ActionBar;
|
|||||||
import android.support.v7.app.ActionBarActivity;
|
import android.support.v7.app.ActionBarActivity;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.view.Window;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.Id;
|
import org.sufficientlysecure.keychain.Id;
|
||||||
@ -41,7 +42,6 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
|||||||
import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@ -60,6 +60,7 @@ public class ViewKeyActivity extends ActionBarActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
mExportHelper = new ExportHelper(this);
|
mExportHelper = new ExportHelper(this);
|
||||||
@ -118,10 +119,12 @@ public class ViewKeyActivity extends ActionBarActivity {
|
|||||||
uploadToKeyserver(mDataUri);
|
uploadToKeyserver(mDataUri);
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_key_view_export_file:
|
case R.id.menu_key_view_export_file:
|
||||||
long masterKeyId = Long.valueOf(mDataUri.getLastPathSegment());
|
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
|
||||||
long[] ids = new long[]{masterKeyId};
|
mExportHelper.showExportKeysDialog(
|
||||||
mExportHelper.showExportKeysDialog(ids, Id.type.public_key,
|
new long[] { masterKeyId } , Constants.Path.APP_DIR_FILE_PUB,
|
||||||
Constants.Path.APP_DIR_FILE_PUB, null);
|
// TODO this doesn't work?
|
||||||
|
((ViewKeyMainFragment) mTabsAdapter.getItem(0)).isSecretAvailable()
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_key_view_share_default_fingerprint:
|
case R.id.menu_key_view_share_default_fingerprint:
|
||||||
shareKey(mDataUri, true);
|
shareKey(mDataUri, true);
|
||||||
@ -156,8 +159,10 @@ public class ViewKeyActivity extends ActionBarActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateFromKeyserver(Uri dataUri) {
|
private void updateFromKeyserver(Uri dataUri) {
|
||||||
byte[] fingerprintBlob = ProviderHelper.getFingerprint(this, dataUri);
|
byte[] blob = (byte[]) ProviderHelper.getGenericData(
|
||||||
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
|
this, KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
|
||||||
|
KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
|
||||||
|
String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob);
|
||||||
|
|
||||||
Intent queryIntent = new Intent(this, ImportKeysActivity.class);
|
Intent queryIntent = new Intent(this, ImportKeysActivity.class);
|
||||||
queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN);
|
queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN);
|
||||||
@ -169,15 +174,22 @@ public class ViewKeyActivity extends ActionBarActivity {
|
|||||||
private void shareKey(Uri dataUri, boolean fingerprintOnly) {
|
private void shareKey(Uri dataUri, boolean fingerprintOnly) {
|
||||||
String content;
|
String content;
|
||||||
if (fingerprintOnly) {
|
if (fingerprintOnly) {
|
||||||
byte[] fingerprintBlob = ProviderHelper.getFingerprint(this, dataUri);
|
byte[] data = (byte[]) ProviderHelper.getGenericData(
|
||||||
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
|
this, KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
|
||||||
|
KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
|
||||||
|
if(data != null) {
|
||||||
|
String fingerprint = PgpKeyHelper.convertFingerprintToHex(data);
|
||||||
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
|
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getApplicationContext(), "Bad key selected!",
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// get public keyring as ascii armored string
|
// get public keyring as ascii armored string
|
||||||
long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
|
long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
|
||||||
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this,
|
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
|
||||||
dataUri, new long[]{masterKeyId});
|
this, new long[]{ masterKeyId });
|
||||||
|
|
||||||
content = keyringArmored.get(0);
|
content = keyringArmored.get(0);
|
||||||
|
|
||||||
@ -207,8 +219,8 @@ public class ViewKeyActivity extends ActionBarActivity {
|
|||||||
private void copyToClipboard(Uri dataUri) {
|
private void copyToClipboard(Uri dataUri) {
|
||||||
// get public keyring as ascii armored string
|
// get public keyring as ascii armored string
|
||||||
long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
|
long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
|
||||||
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri,
|
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
|
||||||
new long[]{masterKeyId});
|
this, new long[]{ masterKeyId });
|
||||||
|
|
||||||
ClipboardReflection.copyToClipboard(this, keyringArmored.get(0));
|
ClipboardReflection.copyToClipboard(this, keyringArmored.get(0));
|
||||||
Toast.makeText(getApplicationContext(), R.string.key_copied_to_clipboard, Toast.LENGTH_LONG)
|
Toast.makeText(getApplicationContext(), R.string.key_copied_to_clipboard, Toast.LENGTH_LONG)
|
||||||
|
@ -34,6 +34,9 @@ import android.widget.Toast;
|
|||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||||
public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMessageCallback,
|
public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMessageCallback,
|
||||||
@ -47,26 +50,18 @@ public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMess
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
initNfc(mDataUri);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NFC: Initialize NFC sharing if OS and device supports it
|
* NFC: Initialize NFC sharing if OS and device supports it
|
||||||
*/
|
*/
|
||||||
private void initNfc(Uri dataUri) {
|
private void initNfc() {
|
||||||
// check if NFC Beam is supported (>= Android 4.1)
|
// check if NFC Beam is supported (>= Android 4.1)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
// Check for available NFC Adapter
|
// Check for available NFC Adapter
|
||||||
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
|
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
|
||||||
if (mNfcAdapter != null) {
|
if (mNfcAdapter != null) {
|
||||||
// init nfc
|
// init nfc
|
||||||
|
|
||||||
// get public keyring as byte array
|
|
||||||
long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
|
|
||||||
mSharedKeyringBytes = ProviderHelper.getKeyRingsAsByteArray(this, dataUri,
|
|
||||||
new long[]{masterKeyId});
|
|
||||||
|
|
||||||
// Register callback to set NDEF message
|
// Register callback to set NDEF message
|
||||||
mNfcAdapter.setNdefPushMessageCallback(this, this);
|
mNfcAdapter.setNdefPushMessageCallback(this, this);
|
||||||
// Register callback to listen for message-sent success
|
// Register callback to listen for message-sent success
|
||||||
@ -86,9 +81,19 @@ public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMess
|
|||||||
* guarantee that this activity starts when receiving a beamed message. For now, this code
|
* guarantee that this activity starts when receiving a beamed message. For now, this code
|
||||||
* uses the tag dispatch system.
|
* uses the tag dispatch system.
|
||||||
*/
|
*/
|
||||||
|
// get public keyring as byte array
|
||||||
|
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
|
||||||
|
try {
|
||||||
|
mSharedKeyringBytes = ProviderHelper.getPGPPublicKeyRing(this, masterKeyId).getEncoded();
|
||||||
|
|
||||||
NdefMessage msg = new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME,
|
NdefMessage msg = new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME,
|
||||||
mSharedKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME));
|
mSharedKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME));
|
||||||
return msg;
|
return msg;
|
||||||
|
} catch(IOException e) {
|
||||||
|
// not much trouble, but leave a note
|
||||||
|
Log.e(Constants.TAG, "Error parsing keyring: ", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +30,7 @@ import android.text.format.DateFormat;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
@ -38,7 +39,9 @@ import com.beardedhen.androidbootstrap.BootstrapButton;
|
|||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter;
|
||||||
@ -52,6 +55,7 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
|
|
||||||
public static final String ARG_DATA_URI = "uri";
|
public static final String ARG_DATA_URI = "uri";
|
||||||
|
|
||||||
|
private LinearLayout mContainer;
|
||||||
private TextView mName;
|
private TextView mName;
|
||||||
private TextView mEmail;
|
private TextView mEmail;
|
||||||
private TextView mComment;
|
private TextView mComment;
|
||||||
@ -68,6 +72,7 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
private ListView mUserIds;
|
private ListView mUserIds;
|
||||||
private ListView mKeys;
|
private ListView mKeys;
|
||||||
|
|
||||||
|
private static final int LOADER_ID_UNIFIED = 0;
|
||||||
private static final int LOADER_ID_USER_IDS = 1;
|
private static final int LOADER_ID_USER_IDS = 1;
|
||||||
private static final int LOADER_ID_KEYS = 2;
|
private static final int LOADER_ID_KEYS = 2;
|
||||||
|
|
||||||
@ -76,10 +81,14 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
|
|
||||||
private Uri mDataUri;
|
private Uri mDataUri;
|
||||||
|
|
||||||
|
// for activity
|
||||||
|
private boolean mSecretAvailable = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.view_key_main_fragment, container, false);
|
View view = inflater.inflate(R.layout.view_key_main_fragment, container, false);
|
||||||
|
|
||||||
|
mContainer = (LinearLayout) view.findViewById(R.id.container);
|
||||||
mName = (TextView) view.findViewById(R.id.name);
|
mName = (TextView) view.findViewById(R.id.name);
|
||||||
mEmail = (TextView) view.findViewById(R.id.email);
|
mEmail = (TextView) view.findViewById(R.id.email);
|
||||||
mComment = (TextView) view.findViewById(R.id.comment);
|
mComment = (TextView) view.findViewById(R.id.comment);
|
||||||
@ -118,64 +127,24 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getActivity().setProgressBarIndeterminateVisibility(Boolean.TRUE);
|
||||||
|
mContainer.setVisibility(View.GONE);
|
||||||
|
|
||||||
mDataUri = dataUri;
|
mDataUri = dataUri;
|
||||||
|
|
||||||
Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
|
Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
|
||||||
|
|
||||||
{ // label whether secret key is available, and edit button if it is
|
|
||||||
final long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), mDataUri);
|
|
||||||
if (ProviderHelper.hasSecretKeyByMasterKeyId(getActivity(), masterKeyId)) {
|
|
||||||
// set this attribute. this is a LITTLE unclean, but we have the info available
|
|
||||||
// right here, so why not.
|
|
||||||
mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
|
|
||||||
mSecretKey.setText(R.string.secret_key_yes);
|
|
||||||
|
|
||||||
// certify button
|
|
||||||
// TODO this button MIGHT be useful if the user wants to
|
|
||||||
// certify a private key with another...
|
|
||||||
// mActionCertify.setVisibility(View.GONE);
|
|
||||||
|
|
||||||
// edit button
|
|
||||||
mActionEdit.setVisibility(View.VISIBLE);
|
|
||||||
mActionEdit.setOnClickListener(new View.OnClickListener() {
|
|
||||||
public void onClick(View view) {
|
|
||||||
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
|
|
||||||
editIntent.setData(
|
|
||||||
KeychainContract
|
|
||||||
.KeyRings.buildSecretKeyRingUri(
|
|
||||||
Long.toString(masterKeyId)));
|
|
||||||
editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
|
|
||||||
startActivityForResult(editIntent, 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
mSecretKey.setTextColor(Color.BLACK);
|
|
||||||
mSecretKey.setText(getResources().getString(R.string.secret_key_no));
|
|
||||||
|
|
||||||
// certify button
|
|
||||||
mActionCertify.setVisibility(View.VISIBLE);
|
|
||||||
// edit button
|
|
||||||
mActionEdit.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO see todo note above, doing this here for now
|
|
||||||
mActionCertify.setOnClickListener(new View.OnClickListener() {
|
|
||||||
public void onClick(View view) {
|
|
||||||
certifyKey(KeychainContract.KeyRings.buildGenericKeyRingUri(
|
|
||||||
Long.toString(masterKeyId)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
mActionEncrypt.setOnClickListener(new View.OnClickListener() {
|
mActionEncrypt.setOnClickListener(new View.OnClickListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
encryptToContact(mDataUri);
|
encryptToContact(mDataUri);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
mActionCertify.setOnClickListener(new View.OnClickListener() {
|
||||||
|
public void onClick(View view) {
|
||||||
|
certifyKey(mDataUri);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
mUserIdsAdapter = new ViewKeyUserIdsAdapter(getActivity(), null, 0);
|
mUserIdsAdapter = new ViewKeyUserIdsAdapter(getActivity(), null, 0);
|
||||||
mUserIds.setAdapter(mUserIdsAdapter);
|
mUserIds.setAdapter(mUserIdsAdapter);
|
||||||
@ -185,56 +154,51 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
|
|
||||||
// Prepare the loaders. Either re-connect with an existing ones,
|
// Prepare the loaders. Either re-connect with an existing ones,
|
||||||
// or start new ones.
|
// or start new ones.
|
||||||
|
getActivity().getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
|
||||||
getActivity().getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
|
getActivity().getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
|
||||||
getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this);
|
getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final String[] USER_IDS_PROJECTION =
|
static final String[] UNIFIED_PROJECTION = new String[] {
|
||||||
new String[]{
|
KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_SECRET,
|
||||||
KeychainContract.UserIds._ID,
|
KeyRings.USER_ID, KeyRings.FINGERPRINT,
|
||||||
KeychainContract.UserIds.USER_ID,
|
KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY,
|
||||||
KeychainContract.UserIds.RANK,
|
|
||||||
};
|
|
||||||
static final int INDEX_UID_UID = 1;
|
|
||||||
static final String USER_IDS_SORT_ORDER =
|
|
||||||
KeychainContract.UserIds.RANK + " COLLATE LOCALIZED ASC";
|
|
||||||
|
|
||||||
static final String[] KEYS_PROJECTION =
|
};
|
||||||
new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID,
|
static final int INDEX_UNIFIED_MKI = 1;
|
||||||
KeychainContract.Keys.ALGORITHM, KeychainContract.Keys.RANK,
|
static final int INDEX_UNIFIED_HAS_SECRET = 2;
|
||||||
KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY,
|
static final int INDEX_UNIFIED_UID = 3;
|
||||||
KeychainContract.Keys.CAN_SIGN, KeychainContract.Keys.CAN_ENCRYPT,
|
static final int INDEX_UNIFIED_FINGERPRINT = 4;
|
||||||
KeychainContract.Keys.IS_REVOKED, KeychainContract.Keys.CREATION,
|
static final int INDEX_UNIFIED_ALGORITHM = 5;
|
||||||
KeychainContract.Keys.EXPIRY, KeychainContract.Keys.FINGERPRINT};
|
static final int INDEX_UNIFIED_KEY_SIZE = 6;
|
||||||
static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC";
|
static final int INDEX_UNIFIED_CREATION = 7;
|
||||||
static final int KEYS_INDEX_KEY_ID = 1;
|
static final int INDEX_UNIFIED_EXPIRY = 8;
|
||||||
static final int KEYS_INDEX_ALGORITHM = 2;
|
|
||||||
static final int KEYS_INDEX_RANK = 3;
|
static final String[] USER_IDS_PROJECTION = new String[] {
|
||||||
static final int KEYS_INDEX_KEY_SIZE = 4;
|
UserIds._ID, UserIds.USER_ID, UserIds.RANK,
|
||||||
static final int KEYS_INDEX_CAN_CERTIFY = 5;
|
};
|
||||||
static final int KEYS_INDEX_CAN_SIGN = 6;
|
|
||||||
static final int KEYS_INDEX_CAN_ENCRYPT = 7;
|
static final String[] KEYS_PROJECTION = new String[] {
|
||||||
static final int KEYS_INDEX_IS_REVOKED = 8;
|
Keys._ID,
|
||||||
static final int KEYS_INDEX_CREATION = 9;
|
Keys.KEY_ID, Keys.RANK, Keys.ALGORITHM, Keys.KEY_SIZE,
|
||||||
static final int KEYS_INDEX_EXPIRY = 10;
|
Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT, Keys.CAN_SIGN, Keys.IS_REVOKED,
|
||||||
static final int KEYS_INDEX_FINGERPRINT = 11;
|
Keys.CREATION, Keys.EXPIRY, Keys.FINGERPRINT
|
||||||
|
};
|
||||||
|
static final int KEYS_INDEX_CAN_ENCRYPT = 6;
|
||||||
|
|
||||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
|
case LOADER_ID_UNIFIED: {
|
||||||
|
Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
|
||||||
|
return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null);
|
||||||
|
}
|
||||||
case LOADER_ID_USER_IDS: {
|
case LOADER_ID_USER_IDS: {
|
||||||
Uri baseUri = KeychainContract.UserIds.buildUserIdsUri(mDataUri);
|
Uri baseUri = UserIds.buildUserIdsUri(mDataUri);
|
||||||
|
return new CursorLoader(getActivity(), baseUri, USER_IDS_PROJECTION, null, null, null);
|
||||||
// Now create and return a CursorLoader that will take care of
|
|
||||||
// creating a Cursor for the data being displayed.
|
|
||||||
return new CursorLoader(getActivity(), baseUri, USER_IDS_PROJECTION, null, null,
|
|
||||||
USER_IDS_SORT_ORDER);
|
|
||||||
}
|
}
|
||||||
case LOADER_ID_KEYS: {
|
case LOADER_ID_KEYS: {
|
||||||
Uri baseUri = KeychainContract.Keys.buildKeysUri(mDataUri);
|
Uri baseUri = Keys.buildKeysUri(mDataUri);
|
||||||
|
return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, null);
|
||||||
// Now create and return a CursorLoader that will take care of
|
|
||||||
// creating a Cursor for the data being displayed.
|
|
||||||
return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, KEYS_SORT_ORDER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -243,14 +207,19 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||||
|
/* TODO better error handling? May cause problems when a key is deleted,
|
||||||
|
* because the notification triggers faster than the activity closes.
|
||||||
|
*/
|
||||||
|
// Avoid NullPointerExceptions...
|
||||||
|
if(data.getCount() == 0)
|
||||||
|
return;
|
||||||
// Swap the new cursor in. (The framework will take care of closing the
|
// Swap the new cursor in. (The framework will take care of closing the
|
||||||
// old cursor once we return.)
|
// old cursor once we return.)
|
||||||
switch (loader.getId()) {
|
switch (loader.getId()) {
|
||||||
case LOADER_ID_USER_IDS:
|
case LOADER_ID_UNIFIED: {
|
||||||
if (data.moveToFirst()) {
|
if (data.moveToFirst()) {
|
||||||
// get name, email, and comment from USER_ID
|
// get name, email, and comment from USER_ID
|
||||||
String[] mainUserId = PgpKeyHelper.splitUserId(data
|
String[] mainUserId = PgpKeyHelper.splitUserId(data.getString(INDEX_UNIFIED_UID));
|
||||||
.getString(INDEX_UID_UID));
|
|
||||||
if (mainUserId[0] != null) {
|
if (mainUserId[0] != null) {
|
||||||
getActivity().setTitle(mainUserId[0]);
|
getActivity().setTitle(mainUserId[0]);
|
||||||
mName.setText(mainUserId[0]);
|
mName.setText(mainUserId[0]);
|
||||||
@ -260,22 +229,45 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
}
|
}
|
||||||
mEmail.setText(mainUserId[1]);
|
mEmail.setText(mainUserId[1]);
|
||||||
mComment.setText(mainUserId[2]);
|
mComment.setText(mainUserId[2]);
|
||||||
|
|
||||||
|
if (data.getInt(INDEX_UNIFIED_HAS_SECRET) != 0) {
|
||||||
|
mSecretAvailable = true;
|
||||||
|
|
||||||
|
mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
|
||||||
|
mSecretKey.setText(R.string.secret_key_yes);
|
||||||
|
|
||||||
|
// edit button
|
||||||
|
mActionEdit.setVisibility(View.VISIBLE);
|
||||||
|
mActionEdit.setOnClickListener(new View.OnClickListener() {
|
||||||
|
public void onClick(View view) {
|
||||||
|
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
|
||||||
|
editIntent.setData(mDataUri);
|
||||||
|
editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
|
||||||
|
startActivityForResult(editIntent, 0);
|
||||||
}
|
}
|
||||||
mUserIdsAdapter.swapCursor(data);
|
});
|
||||||
break;
|
} else {
|
||||||
case LOADER_ID_KEYS:
|
mSecretAvailable = false;
|
||||||
// the first key here is our master key
|
|
||||||
if (data.moveToFirst()) {
|
mSecretKey.setTextColor(Color.BLACK);
|
||||||
|
mSecretKey.setText(getResources().getString(R.string.secret_key_no));
|
||||||
|
|
||||||
|
// certify button
|
||||||
|
mActionCertify.setVisibility(View.VISIBLE);
|
||||||
|
// edit button
|
||||||
|
mActionEdit.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
// get key id from MASTER_KEY_ID
|
// get key id from MASTER_KEY_ID
|
||||||
long keyId = data.getLong(KEYS_INDEX_KEY_ID);
|
long masterKeyId = data.getLong(INDEX_UNIFIED_MKI);
|
||||||
String keyIdStr = PgpKeyHelper.convertKeyIdToHex(keyId);
|
String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId);
|
||||||
mKeyId.setText(keyIdStr);
|
mKeyId.setText(keyIdStr);
|
||||||
|
|
||||||
// get creation date from CREATION
|
// get creation date from CREATION
|
||||||
if (data.isNull(KEYS_INDEX_CREATION)) {
|
if (data.isNull(INDEX_UNIFIED_CREATION)) {
|
||||||
mCreation.setText(R.string.none);
|
mCreation.setText(R.string.none);
|
||||||
} else {
|
} else {
|
||||||
Date creationDate = new Date(data.getLong(KEYS_INDEX_CREATION) * 1000);
|
Date creationDate = new Date(data.getLong(INDEX_UNIFIED_CREATION) * 1000);
|
||||||
|
|
||||||
mCreation.setText(
|
mCreation.setText(
|
||||||
DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
|
DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
|
||||||
@ -283,10 +275,10 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get expiry date from EXPIRY
|
// get expiry date from EXPIRY
|
||||||
if (data.isNull(KEYS_INDEX_EXPIRY)) {
|
if (data.isNull(INDEX_UNIFIED_EXPIRY)) {
|
||||||
mExpiry.setText(R.string.none);
|
mExpiry.setText(R.string.none);
|
||||||
} else {
|
} else {
|
||||||
Date expiryDate = new Date(data.getLong(KEYS_INDEX_EXPIRY) * 1000);
|
Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000);
|
||||||
|
|
||||||
mExpiry.setText(
|
mExpiry.setText(
|
||||||
DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
|
DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
|
||||||
@ -294,19 +286,22 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
|
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
|
||||||
data.getInt(KEYS_INDEX_ALGORITHM), data.getInt(KEYS_INDEX_KEY_SIZE));
|
data.getInt(INDEX_UNIFIED_ALGORITHM), data.getInt(INDEX_UNIFIED_KEY_SIZE));
|
||||||
mAlgorithm.setText(algorithmStr);
|
mAlgorithm.setText(algorithmStr);
|
||||||
|
|
||||||
byte[] fingerprintBlob = data.getBlob(KEYS_INDEX_FINGERPRINT);
|
byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT);
|
||||||
if (fingerprintBlob == null) {
|
|
||||||
// FALLBACK for old database entries
|
|
||||||
fingerprintBlob = ProviderHelper.getFingerprint(getActivity(), mDataUri);
|
|
||||||
}
|
|
||||||
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
|
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
|
||||||
|
|
||||||
mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
|
mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case LOADER_ID_USER_IDS:
|
||||||
|
mUserIdsAdapter.swapCursor(data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LOADER_ID_KEYS:
|
||||||
// hide encrypt button if no encryption key is available
|
// hide encrypt button if no encryption key is available
|
||||||
boolean canEncrypt = false;
|
boolean canEncrypt = false;
|
||||||
data.moveToFirst();
|
data.moveToFirst();
|
||||||
@ -322,10 +317,9 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
|
|
||||||
mKeysAdapter.swapCursor(data);
|
mKeysAdapter.swapCursor(data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
getActivity().setProgressBarIndeterminateVisibility(Boolean.FALSE);
|
||||||
|
mContainer.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -340,14 +334,17 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
case LOADER_ID_KEYS:
|
case LOADER_ID_KEYS:
|
||||||
mKeysAdapter.swapCursor(null);
|
mKeysAdapter.swapCursor(null);
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns true if the key current displayed is known to have a secret key. */
|
||||||
|
public boolean isSecretAvailable() {
|
||||||
|
return mSecretAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
private void encryptToContact(Uri dataUri) {
|
private void encryptToContact(Uri dataUri) {
|
||||||
// TODO preselect from uri? should be feasible without trivial query
|
// TODO preselect from uri? should be feasible without trivial query
|
||||||
long keyId = Long.parseLong(dataUri.getPathSegments().get(1));
|
long keyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri);
|
||||||
|
|
||||||
long[] encryptionKeyIds = new long[]{ keyId };
|
long[] encryptionKeyIds = new long[]{ keyId };
|
||||||
Intent intent = new Intent(getActivity(), EncryptActivity.class);
|
Intent intent = new Intent(getActivity(), EncryptActivity.class);
|
||||||
|
@ -20,8 +20,6 @@ package org.sufficientlysecure.keychain.ui.dialog;
|
|||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Messenger;
|
import android.os.Messenger;
|
||||||
@ -35,18 +33,18 @@ import android.widget.LinearLayout;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.Id;
|
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class DeleteKeyDialogFragment extends DialogFragment {
|
public class DeleteKeyDialogFragment extends DialogFragment {
|
||||||
private static final String ARG_MESSENGER = "messenger";
|
private static final String ARG_MESSENGER = "messenger";
|
||||||
private static final String ARG_DELETE_KEY_RING_ROW_IDS = "delete_key_ring_row_ids";
|
private static final String ARG_DELETE_MASTER_KEY_IDS = "delete_master_key_ids";
|
||||||
|
|
||||||
public static final int MESSAGE_OKAY = 1;
|
public static final int MESSAGE_OKAY = 1;
|
||||||
public static final int MESSAGE_ERROR = 0;
|
public static final int MESSAGE_ERROR = 0;
|
||||||
@ -63,13 +61,13 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
|||||||
/**
|
/**
|
||||||
* Creates new instance of this delete file dialog fragment
|
* Creates new instance of this delete file dialog fragment
|
||||||
*/
|
*/
|
||||||
public static DeleteKeyDialogFragment newInstance(Messenger messenger, long[] keyRingRowIds
|
public static DeleteKeyDialogFragment newInstance(Messenger messenger,
|
||||||
) {
|
long[] masterKeyIds) {
|
||||||
DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment();
|
DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment();
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
|
|
||||||
args.putParcelable(ARG_MESSENGER, messenger);
|
args.putParcelable(ARG_MESSENGER, messenger);
|
||||||
args.putLongArray(ARG_DELETE_KEY_RING_ROW_IDS, keyRingRowIds);
|
args.putLongArray(ARG_DELETE_MASTER_KEY_IDS, masterKeyIds);
|
||||||
//We don't need the key type
|
//We don't need the key type
|
||||||
|
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
@ -77,14 +75,13 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
|||||||
return frag;
|
return frag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
|
||||||
final FragmentActivity activity = getActivity();
|
final FragmentActivity activity = getActivity();
|
||||||
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
|
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
|
||||||
|
|
||||||
final long[] keyRingRowIds = getArguments().getLongArray(ARG_DELETE_KEY_RING_ROW_IDS);
|
final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS);
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
|
|
||||||
@ -98,112 +95,50 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
|||||||
mCheckDeleteSecret = (CheckBox) mInflateView.findViewById(R.id.checkDeleteSecret);
|
mCheckDeleteSecret = (CheckBox) mInflateView.findViewById(R.id.checkDeleteSecret);
|
||||||
|
|
||||||
builder.setTitle(R.string.warning);
|
builder.setTitle(R.string.warning);
|
||||||
/* TODO! redo
|
|
||||||
|
|
||||||
// If only a single key has been selected
|
// If only a single key has been selected
|
||||||
if (keyRingRowIds.length == 1) {
|
if (masterKeyIds.length == 1) {
|
||||||
Uri dataUri;
|
|
||||||
ArrayList<Long> publicKeyRings; //Any one will do
|
|
||||||
mIsSingleSelection = true;
|
mIsSingleSelection = true;
|
||||||
|
|
||||||
long selectedRow = keyRingRowIds[0];
|
long masterKeyId = masterKeyIds[0];
|
||||||
long keyType;
|
|
||||||
publicKeyRings = ProviderHelper.getPublicKeyRingsRowIds(activity);
|
|
||||||
|
|
||||||
if (publicKeyRings.contains(selectedRow)) {
|
HashMap<String, Object> data = ProviderHelper.getUnifiedData(activity, masterKeyId, new String[]{
|
||||||
//TODO Should be a better method to do this other than getting all the KeyRings
|
KeyRings.USER_ID,
|
||||||
dataUri = KeychainContract.KeyRings.buildPublicKeyRingsUri(String.valueOf(selectedRow));
|
KeyRings.HAS_SECRET
|
||||||
keyType = Id.type.public_key;
|
}, new int[] { ProviderHelper.FIELD_TYPE_STRING, ProviderHelper.FIELD_TYPE_INTEGER });
|
||||||
} else {
|
String userId = (String) data.get(KeyRings.USER_ID);
|
||||||
dataUri = KeychainContract.KeyRings.buildSecretKeyRingsUri(String.valueOf(selectedRow));
|
boolean hasSecret = ((Long) data.get(KeyRings.HAS_SECRET)) == 1;
|
||||||
keyType = Id.type.secret_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
String userId = ProviderHelper.getUserId(activity, dataUri);
|
// Hide the Checkbox and TextView since this is a single selection,user will be notified through message
|
||||||
// Hide the Checkbox and TextView since this is a single selection,
|
|
||||||
// user will be notified thru message
|
|
||||||
mDeleteSecretKeyView.setVisibility(View.GONE);
|
mDeleteSecretKeyView.setVisibility(View.GONE);
|
||||||
// Set message depending on which key it is.
|
// Set message depending on which key it is.
|
||||||
mMainMessage.setText(getString(keyType == Id.type.secret_key ?
|
mMainMessage.setText(getString(
|
||||||
R.string.secret_key_deletion_confirmation :
|
hasSecret ? R.string.secret_key_deletion_confirmation
|
||||||
R.string.public_key_deletetion_confirmation, userId));
|
: R.string.public_key_deletetion_confirmation,
|
||||||
|
userId));
|
||||||
} else {
|
} else {
|
||||||
mDeleteSecretKeyView.setVisibility(View.VISIBLE);
|
mDeleteSecretKeyView.setVisibility(View.VISIBLE);
|
||||||
mMainMessage.setText(R.string.key_deletion_confirmation_multi);
|
mMainMessage.setText(R.string.key_deletion_confirmation_multi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
builder.setIcon(R.drawable.ic_dialog_alert_holo_light);
|
builder.setIcon(R.drawable.ic_dialog_alert_holo_light);
|
||||||
builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() {
|
builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
Uri queryUri = KeychainContract.KeyRings.buildUnifiedKeyRingsUri();
|
|
||||||
String[] projection = new String[]{
|
|
||||||
KeychainContract.KeyRings.MASTER_KEY_ID, // 0
|
|
||||||
KeychainContract.KeyRings.TYPE// 1
|
|
||||||
};
|
|
||||||
|
|
||||||
// make selection with all entries where _ID is one of the given row ids
|
boolean success = false;
|
||||||
String selection = KeychainDatabase.Tables.KEY_RINGS + "." +
|
for(long masterKeyId : masterKeyIds) {
|
||||||
KeychainContract.KeyRings._ID + " IN(";
|
int count = activity.getContentResolver().delete(
|
||||||
String selectionIDs = "";
|
KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null
|
||||||
for (int i = 0; i < keyRingRowIds.length; i++) {
|
);
|
||||||
selectionIDs += "'" + String.valueOf(keyRingRowIds[i]) + "'";
|
success = count > 0;
|
||||||
if (i + 1 < keyRingRowIds.length) {
|
|
||||||
selectionIDs += ",";
|
|
||||||
}
|
}
|
||||||
}
|
if (success) {
|
||||||
selection += selectionIDs + ")";
|
|
||||||
|
|
||||||
Cursor cursor = activity.getContentResolver().query(queryUri, projection,
|
|
||||||
selection, null, null);
|
|
||||||
|
|
||||||
|
|
||||||
long masterKeyId;
|
|
||||||
long keyType;
|
|
||||||
boolean isSuccessfullyDeleted;
|
|
||||||
try {
|
|
||||||
isSuccessfullyDeleted = false;
|
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
|
||||||
masterKeyId = cursor.getLong(0);
|
|
||||||
keyType = cursor.getLong(1);
|
|
||||||
|
|
||||||
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId +
|
|
||||||
", keyType:" +
|
|
||||||
(keyType == KeychainContract.KeyTypes.PUBLIC ?
|
|
||||||
"Public" : "Private"));
|
|
||||||
|
|
||||||
if (keyType == KeychainContract.KeyTypes.SECRET) {
|
|
||||||
if (mCheckDeleteSecret.isChecked() || mIsSingleSelection) {
|
|
||||||
ProviderHelper.deleteUnifiedKeyRing(activity,
|
|
||||||
String.valueOf(masterKeyId), true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ProviderHelper.deleteUnifiedKeyRing(activity,
|
|
||||||
String.valueOf(masterKeyId), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if the selected rows have actually been deleted
|
|
||||||
cursor = activity.getContentResolver().query(
|
|
||||||
queryUri, projection, selection, null, null);
|
|
||||||
if (cursor == null || cursor.getCount() == 0 ||
|
|
||||||
!mCheckDeleteSecret.isChecked()) {
|
|
||||||
isSuccessfullyDeleted = true;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dismiss();
|
|
||||||
|
|
||||||
if (isSuccessfullyDeleted) {
|
|
||||||
sendMessageToHandler(MESSAGE_OKAY, null);
|
sendMessageToHandler(MESSAGE_OKAY, null);
|
||||||
} else {
|
} else {
|
||||||
sendMessageToHandler(MESSAGE_ERROR, null);
|
sendMessageToHandler(MESSAGE_ERROR, null);
|
||||||
}
|
}
|
||||||
|
dismiss();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||||
@ -213,7 +148,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
|||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
return builder.create();
|
return builder.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
|
|||||||
secretKey = null;
|
secretKey = null;
|
||||||
alert.setMessage(R.string.passphrase_for_symmetric_encryption);
|
alert.setMessage(R.string.passphrase_for_symmetric_encryption);
|
||||||
} else {
|
} else {
|
||||||
secretKey = ProviderHelper.getPGPSecretKeyByKeyId(activity, secretKeyId);
|
secretKey = ProviderHelper.getPGPSecretKeyRing(activity, secretKeyId).getSecretKey();
|
||||||
|
|
||||||
if (secretKey == null) {
|
if (secretKey == null) {
|
||||||
alert.setTitle(R.string.title_key_not_found);
|
alert.setTitle(R.string.title_key_not_found);
|
||||||
|
@ -31,6 +31,7 @@ import android.widget.TextView;
|
|||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.util.QrCodeUtils;
|
import org.sufficientlysecure.keychain.util.QrCodeUtils;
|
||||||
|
|
||||||
@ -89,22 +90,26 @@ public class ShareQrCodeDialogFragment extends DialogFragment {
|
|||||||
if (mFingerprintOnly) {
|
if (mFingerprintOnly) {
|
||||||
alert.setPositiveButton(R.string.btn_okay, null);
|
alert.setPositiveButton(R.string.btn_okay, null);
|
||||||
|
|
||||||
byte[] fingerprintBlob = ProviderHelper.getFingerprint(getActivity(), dataUri);
|
byte[] blob = (byte[]) ProviderHelper.getGenericData(
|
||||||
String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
|
getActivity(), KeyRings.buildUnifiedKeyRingUri(dataUri),
|
||||||
|
KeyRings.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
|
||||||
|
if(blob == null) {
|
||||||
|
// TODO error handling?!
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob);
|
||||||
mText.setText(getString(R.string.share_qr_code_dialog_fingerprint_text) + " " + fingerprint);
|
mText.setText(getString(R.string.share_qr_code_dialog_fingerprint_text) + " " + fingerprint);
|
||||||
|
|
||||||
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
|
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
|
||||||
setQrCode(content);
|
setQrCode(content);
|
||||||
} else {
|
} else {
|
||||||
mText.setText(R.string.share_qr_code_dialog_start);
|
mText.setText(R.string.share_qr_code_dialog_start);
|
||||||
|
|
||||||
// TODO
|
// TODO works, but
|
||||||
long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri);
|
long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri);
|
||||||
|
|
||||||
// get public keyring as ascii armored string
|
// get public keyring as ascii armored string
|
||||||
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
|
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
|
||||||
getActivity(), dataUri, new long[]{masterKeyId});
|
getActivity(), new long[] { masterKeyId });
|
||||||
|
|
||||||
// TODO: binary?
|
// TODO: binary?
|
||||||
|
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
android:descendantFocusability="beforeDescendants"
|
android:descendantFocusability="beforeDescendants"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:paddingRight="16dp">
|
android:paddingRight="16dp"
|
||||||
|
android:id="@+id/container">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
style="@style/SectionHeader"
|
style="@style/SectionHeader"
|
||||||
|
@ -38,17 +38,6 @@
|
|||||||
app:showAsAction="ifRoom|withText"
|
app:showAsAction="ifRoom|withText"
|
||||||
android:icon="@drawable/ic_action_import_export"
|
android:icon="@drawable/ic_action_import_export"
|
||||||
android:title="@string/menu_export_keys">
|
android:title="@string/menu_export_keys">
|
||||||
<menu>
|
|
||||||
<item
|
|
||||||
android:id="@+id/menu_key_list_export_public"
|
|
||||||
app:showAsAction="never"
|
|
||||||
android:title="@string/menu_export_public_keys" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/menu_key_list_secret_export"
|
|
||||||
app:showAsAction="never"
|
|
||||||
android:title="@string/menu_export_secret_keys" />
|
|
||||||
</menu>
|
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
Loading…
Reference in New Issue
Block a user