CloudServices/Sync/ExtensionStorage Design Doc: Difference between revisions

Jump to navigation Jump to search
update this document to match new version of patch
(explain a bunch of edge cases)
(update this document to match new version of patch)
Line 26: Line 26:


We detect kB changing by storing the current kB (as a hash) in the keyring record itself. We "update" this keyring record with the current kB hash on every call to sync(). kinto.js tries to track the status of the keyring in a field called <code>_status</code> -- it should be <code>"synced"</code> when it is the same as the version that we expect on the server, and it should be <code>"updated"</code> if we've changed it and haven't pushed it to the server. So after possibly updating the kB hash (or just replacing it with what it already is), we check if the keyring is "updated" and if so, try to upload it to the server. Because encryption happens "just-in-time", this causes the keyring to be reuploaded but encrypted by the new kB.
We detect kB changing by storing the current kB (as a hash) in the keyring record itself. We "update" this keyring record with the current kB hash on every call to sync(). kinto.js tries to track the status of the keyring in a field called <code>_status</code> -- it should be <code>"synced"</code> when it is the same as the version that we expect on the server, and it should be <code>"updated"</code> if we've changed it and haven't pushed it to the server. So after possibly updating the kB hash (or just replacing it with what it already is), we check if the keyring is "updated" and if so, try to upload it to the server. Because encryption happens "just-in-time", this causes the keyring to be reuploaded but encrypted by the new kB.
=== Losing access to the keyring ===
All of the above allows the keyring to be preserved across password resets, but it's possible that a user no longer has access to the device that had the old keyring. If this happens, the old keyring and any data encrypted using it is completely lost -- that's the point of encrypting it with kB, after all -- and we need a way to recover. When we try to sync our keyring, if we find that we can't decrypt the server version, we check if it was encrypted using a different kB. If it was, then we no longer have access to the keyring, so we delete the entire Kinto collection corresponding to our data and generate a new keyring.
We identify the kB used to encrypt a keyring by storing a hash of that kB on the keyring itself.
It's possible that another device still had access to the old keyring when it was thrown away. It got thrown away due to a password reset, so when it gets the new password (and the new kB), it will try to resync its keyring. When it does, it will see that the keyring was newly generated. From this it will know that the Kinto server was wiped, and it will reset its sync status for all data, and thereby try to reupload everything.
We detect the "generation" of a keyring by storing a <code>uuid</code> field on the keyring. This is preserved across all keyring operations, but generating a new keyring generates a new uuid. Thus, if you sync your keyring and discover that the new version you got has a new uuid, you know you need to reset your sync status.


=== Edge Cases ===
=== Edge Cases ===


* '''Can keys in the keyring ever change?''' No, at the time of this writing, keys are generated once and stay forever. When a user resets their password, the keyring is reuploaded, but the keys in the keyring aren't changed.
* '''Can keys in the keyring ever change?''' Yes, during a password reset, the keyring can be thrown away, with all its keys replaced. However, in normal operation, keys are permanent.


* '''What happens if I uninstall and reinstall an add-on?''' Keys are preserved in the keyring forever, so the old data will still be available to that extension, encrypted in the same way on the server.
* '''What happens if I uninstall and reinstall an add-on?''' Keys are not discarded on uninstalling an add-on, so the old data will still be available to that extension, encrypted in the same way on the server.


* '''What happens if a user simultaneously installs an add-on (and uses it) in two Firefoxes?''' Until one Firefox syncs the data for that add-on, no data is encrypted, so there can be no conflict in the keyring. Each Firefox will try to update its keyring to have a new key for this collection. One will "win"; the other will get a conflict, and pull down the new keyring (because syncing is done using "server_wins"). No Firefox will try to upload data for any add-on for which it doesn't have a key in a synced keyring, and two keyring syncs can't be interleaved, so it's impossible for data to be encrypted on the server with two keys.
* '''What happens if a user simultaneously installs an add-on (and uses it) in two Firefoxes?''' Until one Firefox syncs the data for that add-on, no data is encrypted, so there can be no conflict in the keyring. Each Firefox will try to update its keyring to have a new key for this collection. One will "win"; the other will get a conflict, and pull down the new keyring (because syncing is done using "server_wins"). No Firefox will try to upload data for any add-on for which it doesn't have a key in a synced keyring, and two keyring syncs can't be interleaved, so it's impossible for data to be encrypted on the server with two keys.


* '''What happens if a user resets their password on one device in the middle of an upload?''' We only consider a user's password state at the beginning of a sync. If we get as far as uploading extension data, then the keys for those extensions exist on the server, encrypted with the old kB. This is fine because next sync, we will discover that the keyring was encrypted with the old kB, update the kB on that keyring, and reupload it.
* '''What happens if a user uploads some data on one device and then resets the password on another?''' Assuming the second device had the old keyring, it will re-encrypt the keyring with the new kB and sync it. Because the other device didn't upload a new version of the keyring, the sync will succeed and no data will have to be reuploaded. The first device won't be able to sync until it gets the new password (and the new kB), but once it does, it will try to resync the keyring and accept whatever keyring is on the server.


* '''What happens if a user resets their password on one device when another is uploading?''' Since the keys for each extension don't change, syncing of this data will continue to work. The only concern is whether syncing the keyrings will work. If one device replaces the keyring with the newly encrypted one, the other device will fail to sync that keyring because it can't successfully decode it. Alternately, if one device updated the keyring with a new key while the other device gets its password reset, the second device will fail to reupload its keyring because it can't decrypt the new version on the server (which was encrypted with the old kB).
* '''What happens if a user adds a new extension and syncs some data on one device and then resets the password on another?''' Because the first device uploaded a new keyring, the second device will try to sync the keyring and fail. Because the kB is different on the two keyrings, it will assume that the old keyring is lost and wipe the Kinto server. When the first device reconnects, it will find that the keyring got replaced and reupload all its data.


Right now, the code is conservative, so it won't try to work without a successfully synced keyring, because this could lead to keys getting lost or data being uploaded with a key that doesn't exist on the server. Ideally, the other devices will also have their passwords reset to the new kB. If a device last updated the keyring with the old kB, it will be the only one that can successfully sync the keyring, and it will do so using the new kB. Each other device that gets the new kB will be able to use the new keyring, once it is uploaded.
* '''What happens if a user resets their password on one device in the middle of an upload?''' We only consider a user's password state at the beginning of a sync. If we get as far as uploading extension data, then the keys for those extensions exist on the server, encrypted with the old kB. This is fine because next sync, we will discover that the keyring was encrypted with the old kB, update the kB on that keyring, and reupload it.


* '''What's the worst thing that could happen?''' A user could reset their password on one device and then throw that device in a river and forget the password. If other devices don't get the new kB, they will refuse to sync because they are afraid of erasing an unreadable keyring on the server which has keys that were used to encrypt some extension's data. *I'm not sure what the right fix here is.* One obvious fix is to start ignoring/discarding any record that you can't read for more than some span of time. Since it's impossible for two devices to be syncing with different kBs (one would be logged out), eventually all devices would converge on a set of data that was uploaded with a kB that everyone who was logged in could read. However, this set of data would discard data that extensions already stored, and could be surprising to extension authors.
* '''What happens if a user resets their password on one device when another is uploading?''' If the device that gets reset had access to the old keyring, it will reupload it. In this case, the keys for each extension don't change, so syncing of extension data will continue to work. If the device that gets reset didn't have access to the old keyring, it will wipe the entire server and start uploading from zero. However, it seems like it might be possible for the wipe to happen while the other device is in the middle of reuploading, in which case the other device could upload data encrypted with a key that just got deleted. In this case, the "new" device might try to sync this data and fail to decrypt it and throw forever. *I'm not sure how to handle this case.*
30

edits

Navigation menu