OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 // Get list of all datatypes with unsynced changes. It's possible that our | |
23 // local changes need to be encrypted if encryption for that datatype was | |
24 // just turned on (and vice versa). | |
25 // Note: we do not attempt to re-encrypt data with a new key here as key | |
26 // changes in this code path are likely due to consistency issues (we have | |
27 // to be updated to a key we already have, e.g. an old key). | |
28 std::vector<int64> handles; | |
29 browser_sync::SyncerUtil::GetUnsyncedEntries(trans, &handles); | |
30 for (size_t i = 0; i < handles.size(); ++i) { | |
31 MutableEntry entry(trans, GET_BY_HANDLE, handles[i]); | |
32 const sync_pb::EntitySpecifics& specifics = entry.Get(SPECIFICS); | |
33 // Ignore types that don't need encryption or entries that are already | |
34 // encrypted. | |
35 if (!SpecificsNeedsEncryption(cryptographer->GetEncryptedTypes(), | |
36 specifics)) { | |
37 continue; | |
38 } | |
39 if (!sync_api::WriteNode::UpdateEntryWithEncryption(cryptographer, | |
40 specifics, | |
41 &entry)) { | |
42 NOTREACHED(); | |
43 return false; | |
44 } | |
45 } | |
46 return true; | |
47 } | |
48 | |
49 bool VerifyUnsyncedChangesAreEncrypted( | |
50 BaseTransaction* const trans, | |
51 ModelTypeSet encrypted_types) { | |
52 std::vector<int64> handles; | |
53 browser_sync::SyncerUtil::GetUnsyncedEntries(trans, &handles); | |
54 for (size_t i = 0; i < handles.size(); ++i) { | |
55 Entry entry(trans, GET_BY_HANDLE, handles[i]); | |
56 if (!entry.good()) { | |
57 NOTREACHED(); | |
58 return false; | |
59 } | |
60 if (EntryNeedsEncryption(encrypted_types, entry)) | |
61 return false; | |
62 } | |
63 return true; | |
64 } | |
65 | |
66 bool EntryNeedsEncryption(ModelTypeSet encrypted_types, | |
67 const Entry& entry) { | |
68 if (!entry.Get(UNIQUE_SERVER_TAG).empty()) | |
69 return false; // We don't encrypt unique server nodes. | |
70 syncable::ModelType type = entry.GetModelType(); | |
71 if (type == PASSWORDS || type == NIGORI) | |
72 return false; | |
73 // Checking NON_UNIQUE_NAME is not necessary for the correctness of encrypting | |
74 // the data, nor for determining if data is encrypted. We simply ensure it has | |
75 // been overwritten to avoid any possible leaks of sensitive data. | |
76 return SpecificsNeedsEncryption(encrypted_types, entry.Get(SPECIFICS)) || | |
77 (encrypted_types.Has(type) && | |
78 entry.Get(NON_UNIQUE_NAME) != kEncryptedString); | |
79 } | |
80 | |
81 bool SpecificsNeedsEncryption(ModelTypeSet encrypted_types, | |
82 const sync_pb::EntitySpecifics& specifics) { | |
83 const ModelType type = GetModelTypeFromSpecifics(specifics); | |
84 if (type == PASSWORDS || type == NIGORI) | |
85 return false; // These types have their own encryption schemes. | |
86 if (!encrypted_types.Has(type)) | |
87 return false; // This type does not require encryption | |
88 return !specifics.has_encrypted(); | |
89 } | |
90 | |
91 // Mainly for testing. | |
92 bool VerifyDataTypeEncryptionForTest( | |
93 BaseTransaction* const trans, | |
94 browser_sync::Cryptographer* cryptographer, | |
95 ModelType type, | |
96 bool is_encrypted) { | |
97 if (type == PASSWORDS || type == NIGORI) { | |
98 NOTREACHED(); | |
99 return true; | |
100 } | |
101 std::string type_tag = ModelTypeToRootTag(type); | |
102 Entry type_root(trans, GET_BY_SERVER_TAG, type_tag); | |
103 if (!type_root.good()) { | |
104 NOTREACHED(); | |
105 return false; | |
106 } | |
107 | |
108 std::queue<Id> to_visit; | |
109 Id id_string; | |
110 if (!trans->directory()->GetFirstChildId( | |
111 trans, type_root.Get(ID), &id_string)) { | |
112 NOTREACHED(); | |
113 return false; | |
114 } | |
115 to_visit.push(id_string); | |
116 while (!to_visit.empty()) { | |
117 id_string = to_visit.front(); | |
118 to_visit.pop(); | |
119 if (id_string.IsRoot()) | |
120 continue; | |
121 | |
122 Entry child(trans, GET_BY_ID, id_string); | |
123 if (!child.good()) { | |
124 NOTREACHED(); | |
125 return false; | |
126 } | |
127 if (child.Get(IS_DIR)) { | |
128 Id child_id_string; | |
129 if (!trans->directory()->GetFirstChildId( | |
130 trans, child.Get(ID), &child_id_string)) { | |
131 NOTREACHED(); | |
132 return false; | |
133 } | |
134 // Traverse the children. | |
135 to_visit.push(child_id_string); | |
136 } | |
137 const sync_pb::EntitySpecifics& specifics = child.Get(SPECIFICS); | |
138 DCHECK_EQ(type, child.GetModelType()); | |
139 DCHECK_EQ(type, GetModelTypeFromSpecifics(specifics)); | |
140 // We don't encrypt the server's permanent items. | |
141 if (child.Get(UNIQUE_SERVER_TAG).empty()) { | |
142 if (specifics.has_encrypted() != is_encrypted) | |
143 return false; | |
144 if (specifics.has_encrypted()) { | |
145 if (child.Get(NON_UNIQUE_NAME) != kEncryptedString) | |
146 return false; | |
147 if (!cryptographer->CanDecryptUsingDefaultKey(specifics.encrypted())) | |
148 return false; | |
149 } | |
150 } | |
151 // Push the successor. | |
152 to_visit.push(child.Get(NEXT_ID)); | |
153 } | |
154 return true; | |
155 } | |
156 | |
157 } // namespace syncable | |
OLD | NEW |