Index: sync/engine/nigori_util.cc |
diff --git a/chrome/browser/sync/engine/nigori_util.cc b/sync/engine/nigori_util.cc |
similarity index 53% |
rename from chrome/browser/sync/engine/nigori_util.cc |
rename to sync/engine/nigori_util.cc |
index b9791aba609a48418e97a5cc9dfb929b2f11fabe..1b6d42a803288ef5c64cd6c2781b55ab8011f827 100644 |
--- a/chrome/browser/sync/engine/nigori_util.cc |
+++ b/sync/engine/nigori_util.cc |
@@ -2,16 +2,16 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "chrome/browser/sync/engine/nigori_util.h" |
+#include "sync/engine/nigori_util.h" |
#include <queue> |
#include <string> |
#include <vector> |
-#include "chrome/browser/sync/engine/syncer_util.h" |
-#include "chrome/browser/sync/internal_api/write_node.h" |
-#include "chrome/browser/sync/syncable/syncable.h" |
-#include "chrome/browser/sync/util/cryptographer.h" |
+#include "base/json/json_writer.h" |
+#include "sync/engine/syncer_util.h" |
+#include "sync/syncable/syncable.h" |
+#include "sync/util/cryptographer.h" |
namespace syncable { |
@@ -36,9 +36,7 @@ bool ProcessUnsyncedChangesForEncryption( |
specifics)) { |
continue; |
} |
- if (!sync_api::WriteNode::UpdateEntryWithEncryption(cryptographer, |
- specifics, |
- &entry)) { |
+ if (!UpdateEntryWithEncryption(cryptographer, specifics, &entry)) { |
NOTREACHED(); |
return false; |
} |
@@ -154,4 +152,93 @@ bool VerifyDataTypeEncryptionForTest( |
return true; |
} |
+bool UpdateEntryWithEncryption( |
+ browser_sync::Cryptographer* cryptographer, |
+ const sync_pb::EntitySpecifics& new_specifics, |
+ syncable::MutableEntry* entry) { |
+ syncable::ModelType type = syncable::GetModelTypeFromSpecifics(new_specifics); |
+ DCHECK_GE(type, syncable::FIRST_REAL_MODEL_TYPE); |
+ const sync_pb::EntitySpecifics& old_specifics = entry->Get(SPECIFICS); |
+ const syncable::ModelTypeSet encrypted_types = |
+ cryptographer->GetEncryptedTypes(); |
+ // It's possible the nigori lost the set of encrypted types. If the current |
+ // specifics are already encrypted, we want to ensure we continue encrypting. |
+ bool was_encrypted = old_specifics.has_encrypted(); |
+ sync_pb::EntitySpecifics generated_specifics; |
+ if (new_specifics.has_encrypted()) { |
+ NOTREACHED() << "New specifics already has an encrypted blob."; |
+ return false; |
+ } |
+ if ((!SpecificsNeedsEncryption(encrypted_types, new_specifics) && |
+ !was_encrypted) || |
+ !cryptographer->is_initialized()) { |
+ // No encryption required or we are unable to encrypt. |
+ generated_specifics.CopyFrom(new_specifics); |
+ } else { |
+ // Encrypt new_specifics into generated_specifics. |
+ if (VLOG_IS_ON(2)) { |
+ scoped_ptr<DictionaryValue> value(entry->ToValue()); |
+ std::string info; |
+ base::JSONWriter::Write(value.get(), true, &info); |
+ DVLOG(2) << "Encrypting specifics of type " |
+ << syncable::ModelTypeToString(type) |
+ << " with content: " |
+ << info; |
+ } |
+ // Only copy over the old specifics if it is of the right type and already |
+ // encrypted. The first time we encrypt a node we start from scratch, hence |
+ // removing all the unencrypted data, but from then on we only want to |
+ // update the node if the data changes or the encryption key changes. |
+ if (syncable::GetModelTypeFromSpecifics(old_specifics) == type && |
+ was_encrypted) { |
+ generated_specifics.CopyFrom(old_specifics); |
+ } else { |
+ syncable::AddDefaultFieldValue(type, &generated_specifics); |
+ } |
+ // Does not change anything if underlying encrypted blob was already up |
+ // to date and encrypted with the default key. |
+ if (!cryptographer->Encrypt(new_specifics, |
+ generated_specifics.mutable_encrypted())) { |
+ NOTREACHED() << "Could not encrypt data for node of type " |
+ << syncable::ModelTypeToString(type); |
+ return false; |
+ } |
+ } |
+ |
+ // It's possible this entry was encrypted but didn't properly overwrite the |
+ // non_unique_name (see crbug.com/96314). |
+ bool encrypted_without_overwriting_name = (was_encrypted && |
+ entry->Get(syncable::NON_UNIQUE_NAME) != kEncryptedString); |
+ |
+ // If we're encrypted but the name wasn't overwritten properly we still want |
+ // to rewrite the entry, irrespective of whether the specifics match. |
+ if (!encrypted_without_overwriting_name && |
+ old_specifics.SerializeAsString() == |
+ generated_specifics.SerializeAsString()) { |
+ DVLOG(2) << "Specifics of type " << syncable::ModelTypeToString(type) |
+ << " already match, dropping change."; |
+ return true; |
+ } |
+ |
+ if (generated_specifics.has_encrypted()) { |
+ // Overwrite the possibly sensitive non-specifics data. |
+ entry->Put(syncable::NON_UNIQUE_NAME, kEncryptedString); |
+ // For bookmarks we actually put bogus data into the unencrypted specifics, |
+ // else the server will try to do it for us. |
+ if (type == syncable::BOOKMARKS) { |
+ sync_pb::BookmarkSpecifics* bookmark_specifics = |
+ generated_specifics.mutable_bookmark(); |
+ if (!entry->Get(syncable::IS_DIR)) |
+ bookmark_specifics->set_url(kEncryptedString); |
+ bookmark_specifics->set_title(kEncryptedString); |
+ } |
+ } |
+ entry->Put(syncable::SPECIFICS, generated_specifics); |
+ DVLOG(1) << "Overwriting specifics of type " |
+ << syncable::ModelTypeToString(type) |
+ << " and marking for syncing."; |
+ syncable::MarkForSyncing(entry); |
+ return true; |
+} |
+ |
} // namespace syncable |