Index: sync/syncable/nigori_util.cc |
diff --git a/sync/syncable/nigori_util.cc b/sync/syncable/nigori_util.cc |
deleted file mode 100644 |
index 2016a7ac9896401620d3471128cd9e43aae91eb0..0000000000000000000000000000000000000000 |
--- a/sync/syncable/nigori_util.cc |
+++ /dev/null |
@@ -1,332 +0,0 @@ |
-// Copyright 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "sync/syncable/nigori_util.h" |
- |
-#include <stddef.h> |
-#include <stdint.h> |
- |
-#include <queue> |
-#include <string> |
-#include <vector> |
- |
-#include "base/json/json_writer.h" |
-#include "sync/syncable/directory.h" |
-#include "sync/syncable/entry.h" |
-#include "sync/syncable/mutable_entry.h" |
-#include "sync/syncable/nigori_handler.h" |
-#include "sync/syncable/syncable_util.h" |
-#include "sync/syncable/syncable_write_transaction.h" |
-#include "sync/util/cryptographer.h" |
- |
-namespace syncer { |
-namespace syncable { |
- |
-bool ProcessUnsyncedChangesForEncryption( |
- WriteTransaction* const trans) { |
- NigoriHandler* nigori_handler = trans->directory()->GetNigoriHandler(); |
- ModelTypeSet encrypted_types = nigori_handler->GetEncryptedTypes(trans); |
- Cryptographer* cryptographer = trans->directory()->GetCryptographer(trans); |
- DCHECK(cryptographer->is_ready()); |
- |
- // Get list of all datatypes with unsynced changes. It's possible that our |
- // local changes need to be encrypted if encryption for that datatype was |
- // just turned on (and vice versa). |
- // Note: we do not attempt to re-encrypt data with a new key here as key |
- // changes in this code path are likely due to consistency issues (we have |
- // to be updated to a key we already have, e.g. an old key). |
- std::vector<int64_t> handles; |
- GetUnsyncedEntries(trans, &handles); |
- for (size_t i = 0; i < handles.size(); ++i) { |
- MutableEntry entry(trans, GET_BY_HANDLE, handles[i]); |
- const sync_pb::EntitySpecifics& specifics = entry.GetSpecifics(); |
- // Ignore types that don't need encryption or entries that are already |
- // encrypted. |
- if (!SpecificsNeedsEncryption(encrypted_types, specifics)) |
- continue; |
- if (!UpdateEntryWithEncryption(trans, specifics, &entry)) |
- return false; |
- } |
- return true; |
-} |
- |
-bool VerifyUnsyncedChangesAreEncrypted( |
- BaseTransaction* const trans, |
- ModelTypeSet encrypted_types) { |
- std::vector<int64_t> handles; |
- GetUnsyncedEntries(trans, &handles); |
- for (size_t i = 0; i < handles.size(); ++i) { |
- Entry entry(trans, GET_BY_HANDLE, handles[i]); |
- if (!entry.good()) { |
- NOTREACHED(); |
- return false; |
- } |
- if (EntryNeedsEncryption(encrypted_types, entry)) |
- return false; |
- } |
- return true; |
-} |
- |
-bool EntryNeedsEncryption(ModelTypeSet encrypted_types, |
- const Entry& entry) { |
- if (!entry.GetUniqueServerTag().empty()) |
- return false; // We don't encrypt unique server nodes. |
- ModelType type = entry.GetModelType(); |
- if (type == PASSWORDS || IsControlType(type)) |
- return false; |
- // Checking NON_UNIQUE_NAME is not necessary for the correctness of encrypting |
- // the data, nor for determining if data is encrypted. We simply ensure it has |
- // been overwritten to avoid any possible leaks of sensitive data. |
- return SpecificsNeedsEncryption(encrypted_types, entry.GetSpecifics()) || |
- (encrypted_types.Has(type) && |
- entry.GetNonUniqueName() != kEncryptedString); |
-} |
- |
-bool SpecificsNeedsEncryption(ModelTypeSet encrypted_types, |
- const sync_pb::EntitySpecifics& specifics) { |
- const ModelType type = GetModelTypeFromSpecifics(specifics); |
- if (type == PASSWORDS || IsControlType(type)) |
- return false; // These types have their own encryption schemes. |
- if (!encrypted_types.Has(type)) |
- return false; // This type does not require encryption |
- return !specifics.has_encrypted(); |
-} |
- |
-// Mainly for testing. |
-bool VerifyDataTypeEncryptionForTest( |
- BaseTransaction* const trans, |
- ModelType type, |
- bool is_encrypted) { |
- Cryptographer* cryptographer = trans->directory()->GetCryptographer(trans); |
- if (type == PASSWORDS || IsControlType(type)) { |
- NOTREACHED(); |
- return true; |
- } |
- Entry type_root(trans, GET_TYPE_ROOT, type); |
- if (!type_root.good()) { |
- NOTREACHED(); |
- return false; |
- } |
- |
- std::queue<Id> to_visit; |
- Id id_string = type_root.GetFirstChildId(); |
- to_visit.push(id_string); |
- while (!to_visit.empty()) { |
- id_string = to_visit.front(); |
- to_visit.pop(); |
- if (id_string.IsNull()) |
- continue; |
- |
- Entry child(trans, GET_BY_ID, id_string); |
- if (!child.good()) { |
- NOTREACHED(); |
- return false; |
- } |
- if (child.GetIsDir()) { |
- Id child_id_string = child.GetFirstChildId(); |
- // Traverse the children. |
- to_visit.push(child_id_string); |
- } |
- const sync_pb::EntitySpecifics& specifics = child.GetSpecifics(); |
- DCHECK_EQ(type, child.GetModelType()); |
- DCHECK_EQ(type, GetModelTypeFromSpecifics(specifics)); |
- // We don't encrypt the server's permanent items. |
- if (child.GetUniqueServerTag().empty()) { |
- if (specifics.has_encrypted() != is_encrypted) |
- return false; |
- if (specifics.has_encrypted()) { |
- if (child.GetNonUniqueName() != kEncryptedString) |
- return false; |
- if (!cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted())) |
- return false; |
- } |
- } |
- // Push the successor. |
- to_visit.push(child.GetSuccessorId()); |
- } |
- return true; |
-} |
- |
-bool UpdateEntryWithEncryption( |
- BaseTransaction* const trans, |
- const sync_pb::EntitySpecifics& new_specifics, |
- syncable::MutableEntry* entry) { |
- NigoriHandler* nigori_handler = trans->directory()->GetNigoriHandler(); |
- Cryptographer* cryptographer = trans->directory()->GetCryptographer(trans); |
- ModelType type = GetModelTypeFromSpecifics(new_specifics); |
- DCHECK_GE(type, FIRST_REAL_MODEL_TYPE); |
- const sync_pb::EntitySpecifics& old_specifics = entry->GetSpecifics(); |
- const ModelTypeSet encrypted_types = |
- nigori_handler? |
- nigori_handler->GetEncryptedTypes(trans) : ModelTypeSet(); |
- // 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 || !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)) { |
- std::unique_ptr<base::DictionaryValue> value(entry->ToValue(NULL)); |
- std::string info; |
- base::JSONWriter::WriteWithOptions( |
- *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &info); |
- DVLOG(2) << "Encrypting specifics of type " |
- << 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 (GetModelTypeFromSpecifics(old_specifics) == type && |
- was_encrypted) { |
- generated_specifics.CopyFrom(old_specifics); |
- } else { |
- 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 " |
- << 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->GetNonUniqueName() != 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 " << ModelTypeToString(type) |
- << " already match, dropping change."; |
- return true; |
- } |
- |
- if (generated_specifics.has_encrypted()) { |
- // Overwrite the possibly sensitive non-specifics data. |
- entry->PutNonUniqueName(kEncryptedString); |
- // For bookmarks we actually put bogus data into the unencrypted specifics, |
- // else the server will try to do it for us. |
- if (type == BOOKMARKS) { |
- sync_pb::BookmarkSpecifics* bookmark_specifics = |
- generated_specifics.mutable_bookmark(); |
- if (!entry->GetIsDir()) |
- bookmark_specifics->set_url(kEncryptedString); |
- bookmark_specifics->set_title(kEncryptedString); |
- } |
- } |
- entry->PutSpecifics(generated_specifics); |
- DVLOG(1) << "Overwriting specifics of type " |
- << ModelTypeToString(type) |
- << " and marking for syncing."; |
- syncable::MarkForSyncing(entry); |
- return true; |
-} |
- |
-void UpdateNigoriFromEncryptedTypes(ModelTypeSet encrypted_types, |
- bool encrypt_everything, |
- sync_pb::NigoriSpecifics* nigori) { |
- nigori->set_encrypt_everything(encrypt_everything); |
- static_assert(37 == MODEL_TYPE_COUNT, "update encrypted types"); |
- nigori->set_encrypt_bookmarks( |
- encrypted_types.Has(BOOKMARKS)); |
- nigori->set_encrypt_preferences( |
- encrypted_types.Has(PREFERENCES)); |
- nigori->set_encrypt_autofill_profile( |
- encrypted_types.Has(AUTOFILL_PROFILE)); |
- nigori->set_encrypt_autofill(encrypted_types.Has(AUTOFILL)); |
- nigori->set_encrypt_autofill_wallet_metadata( |
- encrypted_types.Has(AUTOFILL_WALLET_METADATA)); |
- nigori->set_encrypt_themes(encrypted_types.Has(THEMES)); |
- nigori->set_encrypt_typed_urls( |
- encrypted_types.Has(TYPED_URLS)); |
- nigori->set_encrypt_extension_settings( |
- encrypted_types.Has(EXTENSION_SETTINGS)); |
- nigori->set_encrypt_extensions( |
- encrypted_types.Has(EXTENSIONS)); |
- nigori->set_encrypt_search_engines( |
- encrypted_types.Has(SEARCH_ENGINES)); |
- nigori->set_encrypt_sessions(encrypted_types.Has(SESSIONS)); |
- nigori->set_encrypt_app_settings( |
- encrypted_types.Has(APP_SETTINGS)); |
- nigori->set_encrypt_apps(encrypted_types.Has(APPS)); |
- nigori->set_encrypt_app_notifications( |
- encrypted_types.Has(APP_NOTIFICATIONS)); |
- nigori->set_encrypt_dictionary(encrypted_types.Has(DICTIONARY)); |
- nigori->set_encrypt_favicon_images(encrypted_types.Has(FAVICON_IMAGES)); |
- nigori->set_encrypt_favicon_tracking(encrypted_types.Has(FAVICON_TRACKING)); |
- nigori->set_encrypt_articles(encrypted_types.Has(ARTICLES)); |
- nigori->set_encrypt_app_list(encrypted_types.Has(APP_LIST)); |
- nigori->set_encrypt_arc_package(encrypted_types.Has(ARC_PACKAGE)); |
-} |
- |
-ModelTypeSet GetEncryptedTypesFromNigori( |
- const sync_pb::NigoriSpecifics& nigori) { |
- if (nigori.encrypt_everything()) |
- return ModelTypeSet::All(); |
- |
- ModelTypeSet encrypted_types; |
- static_assert(37 == MODEL_TYPE_COUNT, "update encrypted types"); |
- if (nigori.encrypt_bookmarks()) |
- encrypted_types.Put(BOOKMARKS); |
- if (nigori.encrypt_preferences()) |
- encrypted_types.Put(PREFERENCES); |
- if (nigori.encrypt_autofill_profile()) |
- encrypted_types.Put(AUTOFILL_PROFILE); |
- if (nigori.encrypt_autofill()) |
- encrypted_types.Put(AUTOFILL); |
- if (nigori.encrypt_autofill_wallet_metadata()) |
- encrypted_types.Put(AUTOFILL_WALLET_METADATA); |
- if (nigori.encrypt_themes()) |
- encrypted_types.Put(THEMES); |
- if (nigori.encrypt_typed_urls()) |
- encrypted_types.Put(TYPED_URLS); |
- if (nigori.encrypt_extension_settings()) |
- encrypted_types.Put(EXTENSION_SETTINGS); |
- if (nigori.encrypt_extensions()) |
- encrypted_types.Put(EXTENSIONS); |
- if (nigori.encrypt_search_engines()) |
- encrypted_types.Put(SEARCH_ENGINES); |
- if (nigori.encrypt_sessions()) |
- encrypted_types.Put(SESSIONS); |
- if (nigori.encrypt_app_settings()) |
- encrypted_types.Put(APP_SETTINGS); |
- if (nigori.encrypt_apps()) |
- encrypted_types.Put(APPS); |
- if (nigori.encrypt_app_notifications()) |
- encrypted_types.Put(APP_NOTIFICATIONS); |
- if (nigori.encrypt_dictionary()) |
- encrypted_types.Put(DICTIONARY); |
- if (nigori.encrypt_favicon_images()) |
- encrypted_types.Put(FAVICON_IMAGES); |
- if (nigori.encrypt_favicon_tracking()) |
- encrypted_types.Put(FAVICON_TRACKING); |
- if (nigori.encrypt_articles()) |
- encrypted_types.Put(ARTICLES); |
- if (nigori.encrypt_app_list()) |
- encrypted_types.Put(APP_LIST); |
- if (nigori.encrypt_arc_package()) |
- encrypted_types.Put(ARC_PACKAGE); |
- return encrypted_types; |
-} |
- |
-} // namespace syncable |
-} // namespace syncer |