| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/sync/engine/nigori_util.h" | |
| 6 | |
| 7 #include <queue> | |
| 8 #include <string> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "chrome/browser/sync/engine/syncer_util.h" | |
| 12 #include "chrome/browser/sync/internal_api/write_node.h" | |
| 13 #include "chrome/browser/sync/syncable/syncable.h" | |
| 14 #include "chrome/browser/sync/util/cryptographer.h" | |
| 15 | |
| 16 namespace syncable { | |
| 17 | |
| 18 bool ProcessUnsyncedChangesForEncryption( | |
| 19 WriteTransaction* const trans, | |
| 20 browser_sync::Cryptographer* cryptographer) { | |
| 21 DCHECK(cryptographer->is_ready()); | |
| 22 syncable::ModelTypeSet encrypted_types = cryptographer->GetEncryptedTypes(); | |
| 23 | |
| 24 // Get list of all datatypes with unsynced changes. It's possible that our | |
| 25 // local changes need to be encrypted if encryption for that datatype was | |
| 26 // just turned on (and vice versa). This should never affect passwords. | |
| 27 std::vector<int64> handles; | |
| 28 browser_sync::SyncerUtil::GetUnsyncedEntries(trans, &handles); | |
| 29 for (size_t i = 0; i < handles.size(); ++i) { | |
| 30 MutableEntry entry(trans, GET_BY_HANDLE, handles[i]); | |
| 31 if (!sync_api::WriteNode::UpdateEntryWithEncryption(cryptographer, | |
| 32 entry.Get(SPECIFICS), | |
| 33 &entry)) { | |
| 34 NOTREACHED(); | |
| 35 return false; | |
| 36 } | |
| 37 } | |
| 38 return true; | |
| 39 } | |
| 40 | |
| 41 bool VerifyUnsyncedChangesAreEncrypted( | |
| 42 BaseTransaction* const trans, | |
| 43 const ModelTypeSet& encrypted_types) { | |
| 44 std::vector<int64> handles; | |
| 45 browser_sync::SyncerUtil::GetUnsyncedEntries(trans, &handles); | |
| 46 for (size_t i = 0; i < handles.size(); ++i) { | |
| 47 Entry entry(trans, GET_BY_HANDLE, handles[i]); | |
| 48 if (!entry.good()) { | |
| 49 NOTREACHED(); | |
| 50 return false; | |
| 51 } | |
| 52 if (EntryNeedsEncryption(encrypted_types, entry)) | |
| 53 return false; | |
| 54 } | |
| 55 return true; | |
| 56 } | |
| 57 | |
| 58 bool EntryNeedsEncryption(const ModelTypeSet& encrypted_types, | |
| 59 const Entry& entry) { | |
| 60 if (!entry.Get(UNIQUE_SERVER_TAG).empty()) | |
| 61 return false; // We don't encrypt unique server nodes. | |
| 62 syncable::ModelType type = entry.GetModelType(); | |
| 63 if (type == PASSWORDS || type == NIGORI) | |
| 64 return false; | |
| 65 // Checking NON_UNIQUE_NAME is not necessary for the correctness of encrypting | |
| 66 // the data, nor for determining if data is encrypted. We simply ensure it has | |
| 67 // been overwritten to avoid any possible leaks of sensitive data. | |
| 68 return SpecificsNeedsEncryption(encrypted_types, entry.Get(SPECIFICS)) || | |
| 69 (encrypted_types.count(type) > 0 && | |
| 70 entry.Get(NON_UNIQUE_NAME) != kEncryptedString); | |
| 71 } | |
| 72 | |
| 73 bool SpecificsNeedsEncryption(const ModelTypeSet& encrypted_types, | |
| 74 const sync_pb::EntitySpecifics& specifics) { | |
| 75 ModelType type = GetModelTypeFromSpecifics(specifics); | |
| 76 if (type == PASSWORDS || type == NIGORI) | |
| 77 return false; // These types have their own encryption schemes. | |
| 78 if (encrypted_types.count(type) == 0) | |
| 79 return false; // This type does not require encryption | |
| 80 return !specifics.has_encrypted(); | |
| 81 } | |
| 82 | |
| 83 // Mainly for testing. | |
| 84 bool VerifyDataTypeEncryptionForTest( | |
| 85 BaseTransaction* const trans, | |
| 86 browser_sync::Cryptographer* cryptographer, | |
| 87 ModelType type, | |
| 88 bool is_encrypted) { | |
| 89 if (type == PASSWORDS || type == NIGORI) { | |
| 90 NOTREACHED(); | |
| 91 return true; | |
| 92 } | |
| 93 std::string type_tag = ModelTypeToRootTag(type); | |
| 94 Entry type_root(trans, GET_BY_SERVER_TAG, type_tag); | |
| 95 if (!type_root.good()) { | |
| 96 NOTREACHED(); | |
| 97 return false; | |
| 98 } | |
| 99 | |
| 100 std::queue<Id> to_visit; | |
| 101 Id id_string; | |
| 102 if (!trans->directory()->GetFirstChildId( | |
| 103 trans, type_root.Get(ID), &id_string)) { | |
| 104 NOTREACHED(); | |
| 105 return false; | |
| 106 } | |
| 107 to_visit.push(id_string); | |
| 108 while (!to_visit.empty()) { | |
| 109 id_string = to_visit.front(); | |
| 110 to_visit.pop(); | |
| 111 if (id_string.IsRoot()) | |
| 112 continue; | |
| 113 | |
| 114 Entry child(trans, GET_BY_ID, id_string); | |
| 115 if (!child.good()) { | |
| 116 NOTREACHED(); | |
| 117 return false; | |
| 118 } | |
| 119 if (child.Get(IS_DIR)) { | |
| 120 Id child_id_string; | |
| 121 if (!trans->directory()->GetFirstChildId( | |
| 122 trans, child.Get(ID), &child_id_string)) { | |
| 123 NOTREACHED(); | |
| 124 return false; | |
| 125 } | |
| 126 // Traverse the children. | |
| 127 to_visit.push(child_id_string); | |
| 128 } | |
| 129 const sync_pb::EntitySpecifics& specifics = child.Get(SPECIFICS); | |
| 130 DCHECK_EQ(type, child.GetModelType()); | |
| 131 DCHECK_EQ(type, GetModelTypeFromSpecifics(specifics)); | |
| 132 // We don't encrypt the server's permanent items. | |
| 133 if (child.Get(UNIQUE_SERVER_TAG).empty()) { | |
| 134 if (specifics.has_encrypted() != is_encrypted) | |
| 135 return false; | |
| 136 if (specifics.has_encrypted()) { | |
| 137 if (child.Get(NON_UNIQUE_NAME) != kEncryptedString) | |
| 138 return false; | |
| 139 if (!cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted())) | |
| 140 return false; | |
| 141 } | |
| 142 } | |
| 143 // Push the successor. | |
| 144 to_visit.push(child.Get(NEXT_ID)); | |
| 145 } | |
| 146 return true; | |
| 147 } | |
| 148 | |
| 149 } // namespace syncable | |
| OLD | NEW |