Bug 1350088: Recover when we hit "server was flushed", r?kmag
This is another edge case that seems to be linked to the server-side
data loss bug in Kinto. It seems like you can get into a "server was
flushed" case if one device hadn't seen the most recent keyring before
another client caused the server to be wiped. We don't expect this to
happen in the future, but it affects some number of our users who were
already using storage.sync, so build a recovery pathway for them.
MozReview-Commit-ID: K0BJNQgN6Z4
--- a/toolkit/components/extensions/ExtensionStorageSync.jsm
+++ b/toolkit/components/extensions/ExtensionStorageSync.jsm
@@ -1064,17 +1064,20 @@ class ExtensionStorageSync {
// Server version is now correct. Return that result.
return result;
}
}
// No conflicts, or conflict was just someone else adding keys.
return result;
} catch (e) {
if (KeyRingEncryptionRemoteTransformer.isOutdatedKB(e) ||
- e instanceof ServerKeyringDeleted) {
+ e instanceof ServerKeyringDeleted ||
+ // This is another way that ServerKeyringDeleted can
+ // manifest; see bug 1350088 for more details.
+ e.message == "Server has been flushed.") {
// Check if our token is still valid, or if we got locked out
// between starting the sync and talking to Kinto.
const isSessionValid = await this._fxaService.sessionStatus();
if (isSessionValid) {
log.error("Couldn't decipher old keyring; deleting the default bucket and resetting sync status");
await this._deleteBucket();
await this.cryptoCollection.resetSyncStatus();
--- a/toolkit/components/extensions/test/xpcshell/test_ext_storage_sync.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_storage_sync.js
@@ -791,16 +791,59 @@ add_task(async function ensureCanSync_ha
let afterWipeBody = await assertPostedEncryptedKeys(fxaService, afterWipePost);
deepEqual(afterWipeBody.keys.collections[extensionId], extensionKey.keyPairB64,
`decrypted new post should have preserved the key for ${extensionId}`);
});
});
});
+add_task(async function ensureCanSync_handles_flushes() {
+ // One of the ways that bug 1359879 presents is as bug 1350088. This
+ // seems to be the symptom that results when the user had two
+ // devices, one of which was not syncing at the time the keyring was
+ // lost. Ensure we can recover for these users as well.
+ const extensionId = uuid();
+ const extensionId2 = uuid();
+ await withContextAndServer(async function(context, server) {
+ server.installCollection("storage-sync-crypto");
+ server.installDeleteBucket();
+ await withSignedInUser(loggedInUser, async function(extensionStorageSync, fxaService) {
+ server.etag = 700;
+ // Generate keys that we can check for later.
+ let collectionKeys = await extensionStorageSync.ensureCanSync([extensionId]);
+ const extensionKey = collectionKeys.keyForCollection(extensionId);
+ server.clearPosts();
+
+ // last_modified is new, but there is no data.
+ server.etag = 800;
+
+ // Try to add a new extension to trigger a sync of the keyring.
+ let collectionKeys2 = await extensionStorageSync.ensureCanSync([extensionId2]);
+
+ assertKeyRingKey(collectionKeys2, extensionId, extensionKey,
+ `syncing keyring should keep our local key for ${extensionId}`);
+
+ deepEqual(server.getDeletedBuckets(), ["default"],
+ "Kinto server should have been wiped when keyring was thrown away");
+
+ let posts = server.getPosts();
+ equal(posts.length, 1,
+ "syncing keyring should have tried to post a keyring once");
+
+ const post = posts[0];
+ assertPostedNewRecord(post);
+ let postBody = await assertPostedEncryptedKeys(fxaService, post);
+
+ deepEqual(postBody.keys.collections[extensionId], extensionKey.keyPairB64,
+ `decrypted new post should have preserved the key for ${extensionId}`);
+ });
+ });
+});
+
add_task(async function checkSyncKeyRing_reuploads_keys() {
// Verify that when keys are present, they are reuploaded with the
// new kB when we call touchKeys().
const extensionId = uuid();
let extensionKey, extensionSalt;
await withContextAndServer(async function(context, server) {
await withSignedInUser(loggedInUser, async function(extensionStorageSync, fxaService) {
server.installCollection("storage-sync-crypto");