mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-27 11:12:15 -05:00
Merge pull request #576 from Valodim/stripped-secretkeys
Support stripped secretkeys
This commit is contained in:
commit
b0c65729a9
@ -42,6 +42,7 @@ public class KeychainContract {
|
|||||||
String CAN_ENCRYPT = "can_encrypt";
|
String CAN_ENCRYPT = "can_encrypt";
|
||||||
String CAN_CERTIFY = "can_certify";
|
String CAN_CERTIFY = "can_certify";
|
||||||
String IS_REVOKED = "is_revoked";
|
String IS_REVOKED = "is_revoked";
|
||||||
|
String HAS_SECRET = "has_secret";
|
||||||
|
|
||||||
String CREATION = "creation";
|
String CREATION = "creation";
|
||||||
String EXPIRY = "expiry";
|
String EXPIRY = "expiry";
|
||||||
@ -106,7 +107,7 @@ public class KeychainContract {
|
|||||||
public static final String MASTER_KEY_ID = KeysColumns.MASTER_KEY_ID;
|
public static final String MASTER_KEY_ID = KeysColumns.MASTER_KEY_ID;
|
||||||
public static final String IS_REVOKED = KeysColumns.IS_REVOKED;
|
public static final String IS_REVOKED = KeysColumns.IS_REVOKED;
|
||||||
public static final String VERIFIED = CertsColumns.VERIFIED;
|
public static final String VERIFIED = CertsColumns.VERIFIED;
|
||||||
public static final String HAS_SECRET = "has_secret";
|
public static final String HAS_ANY_SECRET = "has_any_secret";
|
||||||
public static final String HAS_ENCRYPT = "has_encrypt";
|
public static final String HAS_ENCRYPT = "has_encrypt";
|
||||||
public static final String HAS_SIGN = "has_encrypt";
|
public static final String HAS_SIGN = "has_encrypt";
|
||||||
|
|
||||||
|
@ -84,6 +84,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
|||||||
+ KeysColumns.CAN_SIGN + " BOOLEAN, "
|
+ KeysColumns.CAN_SIGN + " BOOLEAN, "
|
||||||
+ KeysColumns.CAN_ENCRYPT + " BOOLEAN, "
|
+ KeysColumns.CAN_ENCRYPT + " BOOLEAN, "
|
||||||
+ KeysColumns.IS_REVOKED + " BOOLEAN, "
|
+ KeysColumns.IS_REVOKED + " BOOLEAN, "
|
||||||
|
+ KeysColumns.HAS_SECRET + " BOOLEAN, "
|
||||||
|
|
||||||
+ KeysColumns.CREATION + " INTEGER, "
|
+ KeysColumns.CREATION + " INTEGER, "
|
||||||
+ KeysColumns.EXPIRY + " INTEGER, "
|
+ KeysColumns.EXPIRY + " INTEGER, "
|
||||||
@ -187,6 +188,11 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
|||||||
if (!db.isReadOnly()) {
|
if (!db.isReadOnly()) {
|
||||||
// Enable foreign key constraints
|
// Enable foreign key constraints
|
||||||
db.execSQL("PRAGMA foreign_keys=ON;");
|
db.execSQL("PRAGMA foreign_keys=ON;");
|
||||||
|
// TODO this is a dev hack, remove for release!
|
||||||
|
try {
|
||||||
|
db.execSQL("ALTER TABLE keys ADD COLUMN has_secret BOOLEAN");
|
||||||
|
} catch(Exception e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,16 +254,18 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT);
|
projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT);
|
||||||
projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID);
|
projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID);
|
||||||
projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED);
|
projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED);
|
||||||
projectionMap.put(KeyRings.HAS_SECRET,
|
projectionMap.put(KeyRings.HAS_SECRET, KeyRings.HAS_SECRET);
|
||||||
|
projectionMap.put(KeyRings.HAS_ANY_SECRET,
|
||||||
"(EXISTS (SELECT * FROM " + Tables.KEY_RINGS_SECRET
|
"(EXISTS (SELECT * FROM " + Tables.KEY_RINGS_SECRET
|
||||||
+ " WHERE " + Tables.KEY_RINGS_SECRET + "." + KeyRingData.MASTER_KEY_ID
|
+ " WHERE " + Tables.KEY_RINGS_SECRET + "." + KeyRingData.MASTER_KEY_ID
|
||||||
+ " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
+ " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||||
+ ")) AS " + KeyRings.HAS_SECRET);
|
+ ")) AS " + KeyRings.HAS_ANY_SECRET);
|
||||||
projectionMap.put(KeyRings.HAS_ENCRYPT,
|
projectionMap.put(KeyRings.HAS_ENCRYPT,
|
||||||
"(EXISTS (SELECT COUNT(*) FROM " + Tables.KEYS + " AS k"
|
"(EXISTS (SELECT COUNT(*) FROM " + Tables.KEYS + " AS k"
|
||||||
+" WHERE k." + Keys.MASTER_KEY_ID
|
+" WHERE k." + Keys.MASTER_KEY_ID
|
||||||
+ " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
+ " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||||
+ " AND k." + Keys.IS_REVOKED + " = 0"
|
+ " AND k." + Keys.IS_REVOKED + " = 0"
|
||||||
|
+ " AND k." + Keys.HAS_SECRET + " = 1"
|
||||||
+ " AND k." + Keys.CAN_ENCRYPT + " = 1"
|
+ " AND k." + Keys.CAN_ENCRYPT + " = 1"
|
||||||
+ " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY
|
+ " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY
|
||||||
+ " >= '" + new Date().getTime() / 1000 + "' )"
|
+ " >= '" + new Date().getTime() / 1000 + "' )"
|
||||||
@ -273,6 +275,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
+" WHERE k." + Keys.MASTER_KEY_ID
|
+" WHERE k." + Keys.MASTER_KEY_ID
|
||||||
+ " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
+ " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||||
+ " AND k." + Keys.IS_REVOKED + " = 0"
|
+ " AND k." + Keys.IS_REVOKED + " = 0"
|
||||||
|
+ " AND k." + Keys.HAS_SECRET + " = 1"
|
||||||
+ " AND k." + Keys.CAN_SIGN + " = 1"
|
+ " AND k." + Keys.CAN_SIGN + " = 1"
|
||||||
+ " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY
|
+ " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY
|
||||||
+ " >= '" + new Date().getTime() / 1000 + "' )"
|
+ " >= '" + new Date().getTime() / 1000 + "' )"
|
||||||
@ -373,6 +376,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
projectionMap.put(Keys.CAN_CERTIFY, Keys.CAN_CERTIFY);
|
projectionMap.put(Keys.CAN_CERTIFY, Keys.CAN_CERTIFY);
|
||||||
projectionMap.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
|
projectionMap.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
|
||||||
projectionMap.put(Keys.CAN_SIGN, Keys.CAN_SIGN);
|
projectionMap.put(Keys.CAN_SIGN, Keys.CAN_SIGN);
|
||||||
|
projectionMap.put(Keys.HAS_SECRET, Keys.HAS_SECRET);
|
||||||
projectionMap.put(Keys.CREATION, Keys.CREATION);
|
projectionMap.put(Keys.CREATION, Keys.CREATION);
|
||||||
projectionMap.put(Keys.EXPIRY, Keys.EXPIRY);
|
projectionMap.put(Keys.EXPIRY, Keys.EXPIRY);
|
||||||
projectionMap.put(Keys.ALGORITHM, Keys.ALGORITHM);
|
projectionMap.put(Keys.ALGORITHM, Keys.ALGORITHM);
|
||||||
@ -699,6 +703,20 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
try {
|
try {
|
||||||
final int match = mUriMatcher.match(uri);
|
final int match = mUriMatcher.match(uri);
|
||||||
switch (match) {
|
switch (match) {
|
||||||
|
case KEY_RING_KEYS: {
|
||||||
|
if (values.size() != 1 || !values.containsKey(Keys.HAS_SECRET)) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Only has_secret column may be updated!");
|
||||||
|
}
|
||||||
|
// make sure we get a long value here
|
||||||
|
Long mkid = Long.parseLong(uri.getPathSegments().get(1));
|
||||||
|
String actualSelection = Keys.MASTER_KEY_ID + " = " + Long.toString(mkid);
|
||||||
|
if (!TextUtils.isEmpty(selection)) {
|
||||||
|
actualSelection += " AND (" + selection + ")";
|
||||||
|
}
|
||||||
|
count = db.update(Tables.KEYS, values, actualSelection, selectionArgs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case API_APPS_BY_PACKAGE_NAME:
|
case API_APPS_BY_PACKAGE_NAME:
|
||||||
count = db.update(Tables.API_APPS, values,
|
count = db.update(Tables.API_APPS, values,
|
||||||
buildDefaultApiAppsSelection(uri, selection), selectionArgs);
|
buildDefaultApiAppsSelection(uri, selection), selectionArgs);
|
||||||
@ -715,7 +733,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
getContext().getContentResolver().notifyChange(uri, null);
|
getContext().getContentResolver().notifyChange(uri, null);
|
||||||
|
|
||||||
} catch (SQLiteConstraintException e) {
|
} catch (SQLiteConstraintException e) {
|
||||||
Log.e(Constants.TAG, "Constraint exception on update! Entry already existing?");
|
Log.e(Constants.TAG, "Constraint exception on update! Entry already existing?", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
@ -28,12 +28,15 @@ import android.net.Uri;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
|
|
||||||
import org.spongycastle.bcpg.ArmoredOutputStream;
|
import org.spongycastle.bcpg.ArmoredOutputStream;
|
||||||
|
import org.spongycastle.bcpg.S2K;
|
||||||
import org.spongycastle.openpgp.PGPException;
|
import org.spongycastle.openpgp.PGPException;
|
||||||
import org.spongycastle.openpgp.PGPKeyRing;
|
import org.spongycastle.openpgp.PGPKeyRing;
|
||||||
import org.spongycastle.openpgp.PGPPublicKey;
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.spongycastle.openpgp.PGPSecretKey;
|
||||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.spongycastle.openpgp.PGPSignature;
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
|
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
|
||||||
@ -387,13 +390,38 @@ public class ProviderHelper {
|
|||||||
public void saveKeyRing(PGPSecretKeyRing keyRing) throws IOException {
|
public void saveKeyRing(PGPSecretKeyRing keyRing) throws IOException {
|
||||||
long masterKeyId = keyRing.getPublicKey().getKeyID();
|
long masterKeyId = keyRing.getPublicKey().getKeyID();
|
||||||
|
|
||||||
|
{
|
||||||
|
Uri uri = Keys.buildKeysUri(Long.toString(masterKeyId));
|
||||||
|
|
||||||
|
// first, mark all keys as not available
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(Keys.HAS_SECRET, 0);
|
||||||
|
mContentResolver.update(uri, values, null, null);
|
||||||
|
|
||||||
|
values.put(Keys.HAS_SECRET, 1);
|
||||||
|
// then, mark exactly the keys we have available
|
||||||
|
for (PGPSecretKey sub : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
|
||||||
|
// Set to 1, except if the encryption type is GNU_DUMMY_S2K
|
||||||
|
if(sub.getS2K().getType() != S2K.GNU_DUMMY_S2K) {
|
||||||
|
mContentResolver.update(uri, values, Keys.KEY_ID + " = ?", new String[]{
|
||||||
|
Long.toString(sub.getKeyID())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// this implicitly leaves all keys which were not in the secret key ring
|
||||||
|
// with has_secret = 0
|
||||||
|
}
|
||||||
|
|
||||||
// save secret keyring
|
// save secret keyring
|
||||||
ContentValues values = new ContentValues();
|
{
|
||||||
values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
|
ContentValues values = new ContentValues();
|
||||||
values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded());
|
values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
|
||||||
// insert new version of this keyRing
|
values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded());
|
||||||
Uri uri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
|
// insert new version of this keyRing
|
||||||
mContentResolver.insert(uri, values);
|
Uri uri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
|
||||||
|
mContentResolver.insert(uri, values);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -685,7 +685,7 @@ public class KeychainIntentService extends IntentService
|
|||||||
}
|
}
|
||||||
|
|
||||||
Cursor cursor = getContentResolver().query(KeyRings.buildUnifiedKeyRingsUri(),
|
Cursor cursor = getContentResolver().query(KeyRings.buildUnifiedKeyRingsUri(),
|
||||||
new String[]{KeyRings.MASTER_KEY_ID, KeyRings.HAS_SECRET},
|
new String[]{KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET},
|
||||||
selection, null, null);
|
selection, null, null);
|
||||||
try {
|
try {
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
|
@ -256,7 +256,7 @@ public class KeyListFragment extends Fragment
|
|||||||
KeyRings.IS_REVOKED,
|
KeyRings.IS_REVOKED,
|
||||||
KeyRings.EXPIRY,
|
KeyRings.EXPIRY,
|
||||||
KeyRings.VERIFIED,
|
KeyRings.VERIFIED,
|
||||||
KeyRings.HAS_SECRET
|
KeyRings.HAS_ANY_SECRET
|
||||||
};
|
};
|
||||||
|
|
||||||
static final int INDEX_MASTER_KEY_ID = 1;
|
static final int INDEX_MASTER_KEY_ID = 1;
|
||||||
@ -264,10 +264,10 @@ public class KeyListFragment extends Fragment
|
|||||||
static final int INDEX_IS_REVOKED = 3;
|
static final int INDEX_IS_REVOKED = 3;
|
||||||
static final int INDEX_EXPIRY = 4;
|
static final int INDEX_EXPIRY = 4;
|
||||||
static final int INDEX_VERIFIED = 5;
|
static final int INDEX_VERIFIED = 5;
|
||||||
static final int INDEX_HAS_SECRET = 6;
|
static final int INDEX_HAS_ANY_SECRET = 6;
|
||||||
|
|
||||||
static final String ORDER = // IN THE COURT
|
static final String ORDER = // IN THE COURT
|
||||||
KeyRings.HAS_SECRET + " DESC, " + KeyRings.USER_ID + " ASC";
|
KeyRings.HAS_ANY_SECRET + " DESC, " + KeyRings.USER_ID + " ASC";
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -518,7 +518,7 @@ public class KeyListFragment extends Fragment
|
|||||||
|
|
||||||
{ // set edit button and revoked info, specific by key type
|
{ // set edit button and revoked info, specific by key type
|
||||||
|
|
||||||
if (cursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
|
if (cursor.getInt(KeyListFragment.INDEX_HAS_ANY_SECRET) != 0) {
|
||||||
// this is a secret key - show the edit mButton
|
// this is a secret key - show the edit mButton
|
||||||
h.mStatusDivider.setVisibility(View.VISIBLE);
|
h.mStatusDivider.setVisibility(View.VISIBLE);
|
||||||
h.mStatusLayout.setVisibility(View.VISIBLE);
|
h.mStatusLayout.setVisibility(View.VISIBLE);
|
||||||
@ -564,7 +564,7 @@ public class KeyListFragment extends Fragment
|
|||||||
throw new IllegalStateException("couldn't move cursor to position " + id);
|
throw new IllegalStateException("couldn't move cursor to position " + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mCursor.getInt(INDEX_HAS_SECRET) != 0;
|
return mCursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
|
||||||
}
|
}
|
||||||
public long getMasterKeyId(int id) {
|
public long getMasterKeyId(int id) {
|
||||||
if (!mCursor.moveToPosition(id)) {
|
if (!mCursor.moveToPosition(id)) {
|
||||||
@ -604,7 +604,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.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
|
if (mCursor.getInt(KeyListFragment.INDEX_HAS_ANY_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);
|
||||||
@ -643,7 +643,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.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
|
if (mCursor.getInt(KeyListFragment.INDEX_HAS_ANY_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
|
||||||
|
@ -117,10 +117,11 @@ public class SelectSecretKeyFragment extends ListFragment implements
|
|||||||
KeyRings.IS_REVOKED,
|
KeyRings.IS_REVOKED,
|
||||||
KeyRings.CAN_CERTIFY,
|
KeyRings.CAN_CERTIFY,
|
||||||
KeyRings.HAS_SIGN,
|
KeyRings.HAS_SIGN,
|
||||||
KeyRings.HAS_SECRET
|
KeyRings.HAS_SECRET,
|
||||||
|
KeyRings.HAS_ANY_SECRET
|
||||||
};
|
};
|
||||||
|
|
||||||
String where = KeyRings.HAS_SECRET + " = 1";
|
String where = KeyRings.HAS_ANY_SECRET + " = 1";
|
||||||
|
|
||||||
// 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.
|
||||||
@ -151,7 +152,7 @@ public class SelectSecretKeyFragment extends ListFragment implements
|
|||||||
|
|
||||||
private class SelectSecretKeyCursorAdapter extends SelectKeyCursorAdapter {
|
private class SelectSecretKeyCursorAdapter extends SelectKeyCursorAdapter {
|
||||||
|
|
||||||
private int mIndexHasSign, mIndexCanCertify;
|
private int mIndexHasSecret, mIndexHasSign, mIndexCanCertify;
|
||||||
|
|
||||||
public SelectSecretKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) {
|
public SelectSecretKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) {
|
||||||
super(context, c, flags, listView);
|
super(context, c, flags, listView);
|
||||||
@ -161,6 +162,7 @@ public class SelectSecretKeyFragment extends ListFragment implements
|
|||||||
protected void initIndex(Cursor cursor) {
|
protected void initIndex(Cursor cursor) {
|
||||||
super.initIndex(cursor);
|
super.initIndex(cursor);
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
|
mIndexHasSecret = cursor.getColumnIndexOrThrow(KeyRings.HAS_SECRET);
|
||||||
mIndexCanCertify = cursor.getColumnIndexOrThrow(KeyRings.CAN_CERTIFY);
|
mIndexCanCertify = cursor.getColumnIndexOrThrow(KeyRings.CAN_CERTIFY);
|
||||||
mIndexHasSign = cursor.getColumnIndexOrThrow(KeyRings.HAS_SIGN);
|
mIndexHasSign = cursor.getColumnIndexOrThrow(KeyRings.HAS_SIGN);
|
||||||
}
|
}
|
||||||
@ -177,8 +179,10 @@ public class SelectSecretKeyFragment extends ListFragment implements
|
|||||||
// Special from superclass: Te
|
// Special from superclass: Te
|
||||||
boolean enabled = false;
|
boolean enabled = false;
|
||||||
if((Boolean) h.status.getTag()) {
|
if((Boolean) h.status.getTag()) {
|
||||||
|
if (cursor.getInt(mIndexHasSecret) == 0) {
|
||||||
|
h.status.setText(R.string.no_subkey);
|
||||||
// Check if key is viable for our purposes (certify or sign)
|
// Check if key is viable for our purposes (certify or sign)
|
||||||
if(mFilterCertify) {
|
} else if(mFilterCertify) {
|
||||||
if (cursor.getInt(mIndexCanCertify) == 0) {
|
if (cursor.getInt(mIndexCanCertify) == 0) {
|
||||||
h.status.setText(R.string.can_certify_not);
|
h.status.setText(R.string.can_certify_not);
|
||||||
} else {
|
} else {
|
||||||
|
@ -158,13 +158,13 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
static final String[] UNIFIED_PROJECTION = new String[] {
|
static final String[] UNIFIED_PROJECTION = new String[] {
|
||||||
KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_SECRET,
|
KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET,
|
||||||
KeyRings.USER_ID, KeyRings.FINGERPRINT,
|
KeyRings.USER_ID, KeyRings.FINGERPRINT,
|
||||||
KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY,
|
KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY,
|
||||||
|
|
||||||
};
|
};
|
||||||
static final int INDEX_UNIFIED_MKI = 1;
|
static final int INDEX_UNIFIED_MKI = 1;
|
||||||
static final int INDEX_UNIFIED_HAS_SECRET = 2;
|
static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2;
|
||||||
static final int INDEX_UNIFIED_UID = 3;
|
static final int INDEX_UNIFIED_UID = 3;
|
||||||
static final int INDEX_UNIFIED_FINGERPRINT = 4;
|
static final int INDEX_UNIFIED_FINGERPRINT = 4;
|
||||||
static final int INDEX_UNIFIED_ALGORITHM = 5;
|
static final int INDEX_UNIFIED_ALGORITHM = 5;
|
||||||
@ -174,11 +174,11 @@ public class ViewKeyMainFragment extends Fragment implements
|
|||||||
|
|
||||||
static final String[] KEYS_PROJECTION = new String[] {
|
static final String[] KEYS_PROJECTION = new String[] {
|
||||||
Keys._ID,
|
Keys._ID,
|
||||||
Keys.KEY_ID, Keys.RANK, Keys.ALGORITHM, Keys.KEY_SIZE,
|
Keys.KEY_ID, Keys.RANK, Keys.ALGORITHM, Keys.KEY_SIZE, Keys.HAS_SECRET,
|
||||||
Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT, Keys.CAN_SIGN, Keys.IS_REVOKED,
|
Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT, Keys.CAN_SIGN, Keys.IS_REVOKED,
|
||||||
Keys.CREATION, Keys.EXPIRY, Keys.FINGERPRINT
|
Keys.CREATION, Keys.EXPIRY, Keys.FINGERPRINT
|
||||||
};
|
};
|
||||||
static final int KEYS_INDEX_CAN_ENCRYPT = 6;
|
static final int KEYS_INDEX_CAN_ENCRYPT = 7;
|
||||||
|
|
||||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
@ -225,7 +225,7 @@ 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) {
|
if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) {
|
||||||
mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
|
mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
|
||||||
mSecretKey.setText(R.string.secret_key_yes);
|
mSecretKey.setText(R.string.secret_key_yes);
|
||||||
|
|
||||||
|
@ -45,9 +45,12 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
|
|||||||
private int mIndexCanCertify;
|
private int mIndexCanCertify;
|
||||||
private int mIndexCanEncrypt;
|
private int mIndexCanEncrypt;
|
||||||
private int mIndexCanSign;
|
private int mIndexCanSign;
|
||||||
|
private int mIndexHasSecret;
|
||||||
private int mIndexRevokedKey;
|
private int mIndexRevokedKey;
|
||||||
private int mIndexExpiry;
|
private int mIndexExpiry;
|
||||||
|
|
||||||
|
private boolean hasAnySecret;
|
||||||
|
|
||||||
private ColorStateList mDefaultTextColor;
|
private ColorStateList mDefaultTextColor;
|
||||||
|
|
||||||
public ViewKeyKeysAdapter(Context context, Cursor c, int flags) {
|
public ViewKeyKeysAdapter(Context context, Cursor c, int flags) {
|
||||||
@ -62,6 +65,17 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
|
|||||||
public Cursor swapCursor(Cursor newCursor) {
|
public Cursor swapCursor(Cursor newCursor) {
|
||||||
initIndex(newCursor);
|
initIndex(newCursor);
|
||||||
|
|
||||||
|
hasAnySecret = false;
|
||||||
|
if (newCursor != null) {
|
||||||
|
newCursor.moveToFirst();
|
||||||
|
do {
|
||||||
|
if (newCursor.getInt(mIndexHasSecret) != 0) {
|
||||||
|
hasAnySecret = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(newCursor.moveToNext());
|
||||||
|
}
|
||||||
|
|
||||||
return super.swapCursor(newCursor);
|
return super.swapCursor(newCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +94,7 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
|
|||||||
mIndexCanCertify = cursor.getColumnIndexOrThrow(Keys.CAN_CERTIFY);
|
mIndexCanCertify = cursor.getColumnIndexOrThrow(Keys.CAN_CERTIFY);
|
||||||
mIndexCanEncrypt = cursor.getColumnIndexOrThrow(Keys.CAN_ENCRYPT);
|
mIndexCanEncrypt = cursor.getColumnIndexOrThrow(Keys.CAN_ENCRYPT);
|
||||||
mIndexCanSign = cursor.getColumnIndexOrThrow(Keys.CAN_SIGN);
|
mIndexCanSign = cursor.getColumnIndexOrThrow(Keys.CAN_SIGN);
|
||||||
|
mIndexHasSecret = cursor.getColumnIndexOrThrow(Keys.HAS_SECRET);
|
||||||
mIndexRevokedKey = cursor.getColumnIndexOrThrow(Keys.IS_REVOKED);
|
mIndexRevokedKey = cursor.getColumnIndexOrThrow(Keys.IS_REVOKED);
|
||||||
mIndexExpiry = cursor.getColumnIndexOrThrow(Keys.EXPIRY);
|
mIndexExpiry = cursor.getColumnIndexOrThrow(Keys.EXPIRY);
|
||||||
}
|
}
|
||||||
@ -101,7 +116,13 @@ public class ViewKeyKeysAdapter extends CursorAdapter {
|
|||||||
cursor.getInt(mIndexKeySize));
|
cursor.getInt(mIndexKeySize));
|
||||||
|
|
||||||
keyId.setText(keyIdStr);
|
keyId.setText(keyIdStr);
|
||||||
keyDetails.setText("(" + algorithmStr + ")");
|
// may be set with additional "stripped" later on
|
||||||
|
if (hasAnySecret && cursor.getInt(mIndexHasSecret) == 0) {
|
||||||
|
keyDetails.setText("(" + algorithmStr + ", " +
|
||||||
|
context.getString(R.string.key_stripped) + ")");
|
||||||
|
} else {
|
||||||
|
keyDetails.setText("(" + algorithmStr + ")");
|
||||||
|
}
|
||||||
|
|
||||||
if (cursor.getInt(mIndexRank) == 0) {
|
if (cursor.getInt(mIndexRank) == 0) {
|
||||||
masterKeyIcon.setVisibility(View.INVISIBLE);
|
masterKeyIcon.setVisibility(View.INVISIBLE);
|
||||||
|
@ -91,10 +91,10 @@ public class DeleteKeyDialogFragment extends DialogFragment {
|
|||||||
|
|
||||||
HashMap<String, Object> data = new ProviderHelper(activity).getUnifiedData(masterKeyId, new String[]{
|
HashMap<String, Object> data = new ProviderHelper(activity).getUnifiedData(masterKeyId, new String[]{
|
||||||
KeyRings.USER_ID,
|
KeyRings.USER_ID,
|
||||||
KeyRings.HAS_SECRET
|
KeyRings.HAS_ANY_SECRET
|
||||||
}, new int[]{ProviderHelper.FIELD_TYPE_STRING, ProviderHelper.FIELD_TYPE_INTEGER});
|
}, new int[]{ProviderHelper.FIELD_TYPE_STRING, ProviderHelper.FIELD_TYPE_INTEGER});
|
||||||
String userId = (String) data.get(KeyRings.USER_ID);
|
String userId = (String) data.get(KeyRings.USER_ID);
|
||||||
boolean hasSecret = ((Long) data.get(KeyRings.HAS_SECRET)) == 1;
|
boolean hasSecret = ((Long) data.get(KeyRings.HAS_ANY_SECRET)) == 1;
|
||||||
|
|
||||||
// Set message depending on which key it is.
|
// Set message depending on which key it is.
|
||||||
mMainMessage.setText(getString(
|
mMainMessage.setText(getString(
|
||||||
|
@ -535,5 +535,7 @@
|
|||||||
<string name="can_certify_not">cannot certify</string>
|
<string name="can_certify_not">cannot certify</string>
|
||||||
<string name="error_key_not_found">Key not found!</string>
|
<string name="error_key_not_found">Key not found!</string>
|
||||||
<string name="error_key_processing">Error processing key!</string>
|
<string name="error_key_processing">Error processing key!</string>
|
||||||
|
<string name="no_subkey">subkey unavailable</string>
|
||||||
|
<string name="key_stripped">stripped</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -279,6 +279,15 @@ public class PGPSecretKey
|
|||||||
return pub.getUserIDs();
|
return pub.getUserIDs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the S2K object used to encrypt this secret key.
|
||||||
|
*
|
||||||
|
* @return this secret key's s2k object'
|
||||||
|
*/
|
||||||
|
public S2K getS2K() {
|
||||||
|
return secret.getS2K();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return any user attribute vectors associated with the key.
|
* Return any user attribute vectors associated with the key.
|
||||||
*
|
*
|
||||||
|
@ -432,6 +432,15 @@ public class PGPSecretKey
|
|||||||
return pub.getUserIDs();
|
return pub.getUserIDs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the S2K this secret key is encrypted with.
|
||||||
|
*
|
||||||
|
* @return the S2K for this key.
|
||||||
|
*/
|
||||||
|
public S2K getS2K() {
|
||||||
|
return secret.getS2K();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return any user attribute vectors associated with the key.
|
* Return any user attribute vectors associated with the key.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user