kishikawakatsumi / KeychainAccess

Simple Swift wrapper for Keychain that works on iOS, watchOS, tvOS and macOS.
MIT License
7.95k stars 789 forks source link

Migrating existing keychain to using accessGroup #499

Open damirstuhec opened 4 years ago

damirstuhec commented 4 years ago

Up until now, I've been initializing Keychain with default options, like this: Keychain().

Recently, I added a new extension and enabled keychain sharing on both targets. The initialization now looks like this: Keychain(service: "com.app", accessGroup: "PREFIX.SharedGroup").

The problem is that the new Keychain using accessGroup is empty, ie. does not include existing items that were stored using the old Keychain().

Is there a built-in way to migrate the old keychain items to the new one? Or do we have to do it manually?

tomazravljen commented 3 years ago

We have faced a similar issue this month. We've been using Keychain without accessGroup: parameter so far and now that we have implemented NotificationService we needed to share some of the items within those existing Keychains to the app group.

Since we did not find any built-in way to do it, we decided to manually migrate items from old keychain to the new shared one. When creating a new keychain for sharing between apps within a group, we used the same service name as before, but this time we passed the accessGroup parameter.

This caused some very interesting and at the same time confusing results. First attempt was to simply iterate between all keys in the old keychain and store them to the new one like so:

for key in oldKeychain.allKeys() {
    newKeychain[key] = oldKeychain[key]
}

The newKeychain looked fine after execution of this block, new values were added to it, great. But the result was unexpected for the oldKeychain, which now contained all old items AND all new items, so there were duplicate keys. 😮

For example, oldKeychain contains item with key testKey and after this block of code is executed, so does the newKeychain. But now oldKeychain contains 2 items with testKey as key.

Now, before we knew this, we tried to clean up the old keychain with try oldKeychain.removeAll(). This resulted in all items being removed, the old ones in oldKeychain which is expected and the copied/migrated items in the newKeychain which was completely unexpected. So it appears that somehow the two keychains with the same name are tied together, even though one has accessGroup and the other does not. I would assume this is the same keychain, but with different permissions of sorts. But it does seem odd that the items migrated to newKeychain do not override the old ones, but creates duplicates.

We solved this duplicate issue internally by clearing old keychain before storing new into the new shared keychain. To me the question still remains, is this intentional behaviour or possibly a bug? And if so, is there another way we could have resolved this migration process without creating duplicates or clearing old ones before adding new ones?

euroboy commented 2 years ago

Still no fix on this issue?