diff options
Diffstat (limited to 'OpenKeychain/src')
| -rw-r--r-- | OpenKeychain/src/main/AndroidManifest.xml | 1 | ||||
| -rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java | 127 | 
2 files changed, 119 insertions, 9 deletions
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index 5d3a106de..0e7baf039 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -65,6 +65,7 @@      <uses-permission android:name="android.permission.READ_CONTACTS" />      <uses-permission android:name="android.permission.WRITE_CONTACTS" />      <uses-permission android:name="android.permission.READ_PROFILE" /> +    <uses-permission android:name="android.permission.WRITE_PROFILE" />      <!-- android:allowBackup="false": Don't allow backup over adb backup or other apps! -->      <application diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java index b3eb36157..1b52e4e6b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java @@ -363,7 +363,8 @@ public class ContactHelper {              KeychainContract.KeyRings.IS_EXPIRED,              KeychainContract.KeyRings.IS_REVOKED,              KeychainContract.KeyRings.VERIFIED, -            KeychainContract.KeyRings.HAS_SECRET}; +            KeychainContract.KeyRings.HAS_SECRET, +            KeychainContract.KeyRings.HAS_ANY_SECRET};      public static final int INDEX_MASTER_KEY_ID = 0;      public static final int INDEX_USER_ID = 1; @@ -371,6 +372,7 @@ public class ContactHelper {      public static final int INDEX_IS_REVOKED = 3;      public static final int INDEX_VERIFIED = 4;      public static final int INDEX_HAS_SECRET = 5; +    public static final int INDEX_HAS_ANY_SECRET = 6;      /**       * Write/Update the current OpenKeychain keys to the contact db @@ -379,6 +381,8 @@ public class ContactHelper {          ContentResolver resolver = context.getContentResolver();          Set<Long> deletedKeys = getRawContactMasterKeyIds(resolver); +        writeKeysToMainProfileContact(context); +          if (Constants.DEBUG_SYNC_REMOVE_CONTACTS) {              debugDeleteRawContacts(resolver);          } @@ -395,9 +399,13 @@ public class ContactHelper {  //            e.printStackTrace();  //        } -        // Load all Keys from OK -        Cursor cursor = resolver.query(KeychainContract.KeyRings.buildUnifiedKeyRingsUri(), KEYS_TO_CONTACT_PROJECTION, -                null, null, null); +        // Load all public Keys from OK +        // TODO: figure out why using selectionArgs does not work in this case +        Cursor cursor = resolver.query(KeychainContract.KeyRings.buildUnifiedKeyRingsUri(), +                KEYS_TO_CONTACT_PROJECTION, +                KeychainContract.KeyRings.HAS_ANY_SECRET + "=0", +                null, null); +          if (cursor != null) {              while (cursor.moveToNext()) {                  long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID); @@ -406,7 +414,6 @@ public class ContactHelper {                  boolean isExpired = cursor.getInt(INDEX_IS_EXPIRED) != 0;                  boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;                  boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0; -                boolean isSecret = cursor.getInt(INDEX_HAS_SECRET) != 0;                  Log.d(Constants.TAG, "masterKeyId: " + masterKeyId); @@ -418,8 +425,9 @@ public class ContactHelper {                  ArrayList<ContentProviderOperation> ops = new ArrayList<>(); -                // Do not store expired or revoked keys in contact db - and remove them if they already exist -                if (isExpired || isRevoked || !isVerified&&!isSecret) { +                // Do not store expired or revoked or unverified keys in contact db - and +                // remove them if they already exist. Secret keys do not reach this point +                if (isExpired || isRevoked || !isVerified) {                      Log.d(Constants.TAG, "Expired or revoked or unverified: Deleting rawContactId " + rawContactId);                      if (rawContactId != -1) {                          deleteRawContactById(resolver, rawContactId); @@ -455,6 +463,83 @@ public class ContactHelper {          }      } +    public static void writeKeysToMainProfileContact(Context context) { +        ContentResolver resolver = context.getContentResolver(); +        Set<Long> keysToDelete = getMainProfileMasterKeyIds(resolver); + +        // get all keys which have associated secret keys +        // TODO: figure out why using selectionArgs does not work in this case +        Cursor cursor = resolver.query(KeychainContract.KeyRings.buildUnifiedKeyRingsUri(), +                KEYS_TO_CONTACT_PROJECTION, +                KeychainContract.KeyRings.HAS_ANY_SECRET + "!=0", +                null, null); +        if (cursor != null) { +            while (cursor.moveToNext()) { +                long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID); + +                boolean existsInMainProfile = keysToDelete.remove(masterKeyId); +                if (!existsInMainProfile) { +                    long rawContactId = -1;//new raw contact + +                    String keyIdShort = KeyFormattingUtils.convertKeyIdToHexShort(masterKeyId); +                    Log.d(Constants.TAG, "masterKeyId with secret " + masterKeyId); + +                    ArrayList<ContentProviderOperation> ops = new ArrayList<>(); +                    insertMainProfileRawContact(ops, masterKeyId); +                    writeContactKey(ops, context, rawContactId, masterKeyId, keyIdShort); + +                    try { +                        resolver.applyBatch(ContactsContract.AUTHORITY, ops); +                    } catch (Exception e) { +                        Log.w(Constants.TAG, e); +                    } +                } +            } +        } + +        for (long masterKeyId : keysToDelete) { +            deleteMainProfileRawContactByMasterKeyId(resolver, masterKeyId); +            Log.d(Constants.TAG, "Delete main profile raw contact with masterKeyId " + masterKeyId); +        } +    } + +    /** +     * Inserts a raw contact into the table defined by ContactsContract.Profile +     * +     * @param ops +     * @param masterKeyId +     */ +    private static void insertMainProfileRawContact(ArrayList<ContentProviderOperation> ops, +                                                    long masterKeyId) { +        ops.add(ContentProviderOperation.newInsert(ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI) +                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, Constants.ACCOUNT_NAME) +                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, Constants.ACCOUNT_TYPE) +                .withValue(ContactsContract.RawContacts.SOURCE_ID, Long.toString(masterKeyId)) +                .build()); +    } + +    /** +     * deletes a raw contact from the profile table +     * +     * @param resolver +     * @param masterKeyId +     * @return +     */ +    private static int deleteMainProfileRawContactByMasterKeyId(ContentResolver resolver, +                                                                long masterKeyId) { +        //allows us to actually wipe the RawContact from the device, otherwise would be just flagged +        //for deletion +        Uri deleteUri = ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI.buildUpon(). +                appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build(); + +        return resolver.delete(deleteUri, +                ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + +                        ContactsContract.RawContacts.SOURCE_ID + "=?", +                new String[]{ +                        Constants.ACCOUNT_TYPE, Long.toString(masterKeyId) +                }); +    } +      /**       * Delete all raw contacts associated to OpenKeychain.       */ @@ -479,7 +564,8 @@ public class ContactHelper {                  appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();          return resolver.delete(deleteUri, -                ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + ContactsContract.RawContacts._ID + "=?", +                ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + +                        ContactsContract.RawContacts._ID + "=?",                  new String[]{                          Constants.ACCOUNT_TYPE, Long.toString(rawContactId)                  }); @@ -492,7 +578,8 @@ public class ContactHelper {                  appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();          return resolver.delete(deleteUri, -                ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + ContactsContract.RawContacts.SOURCE_ID + "=?", +                ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + +                        ContactsContract.RawContacts.SOURCE_ID + "=?",                  new String[]{                          Constants.ACCOUNT_TYPE, Long.toString(masterKeyId)                  }); @@ -521,6 +608,28 @@ public class ContactHelper {      }      /** +     * @return a set of all key master key ids currently present in the contact db +     */ +    private static Set<Long> getMainProfileMasterKeyIds(ContentResolver resolver) { +        HashSet<Long> result = new HashSet<>(); +        Cursor masterKeyIds = resolver.query(ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI, +                new String[]{ +                        ContactsContract.RawContacts.SOURCE_ID +                }, +                ContactsContract.RawContacts.ACCOUNT_TYPE + "=?", +                new String[]{ +                        Constants.ACCOUNT_TYPE +                }, null); +        if (masterKeyIds != null) { +            while (masterKeyIds.moveToNext()) { +                result.add(masterKeyIds.getLong(0)); +            } +            masterKeyIds.close(); +        } +        return result; +    } + +    /**       * This will search the contact db for a raw contact with a given master key id       *       * @return raw contact id or -1 if not found  | 
