OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync/engine/syncer_util.h" | 5 #include "chrome/browser/sync/engine/syncer_util.h" |
6 | 6 |
7 #include <algorithm> | |
8 #include <set> | 7 #include <set> |
9 #include <string> | 8 #include <string> |
10 #include <vector> | 9 #include <vector> |
11 | 10 |
12 #include "chrome/browser/sync/engine/conflict_resolver.h" | 11 #include "chrome/browser/sync/engine/conflict_resolver.h" |
13 #include "chrome/browser/sync/engine/syncer_proto_util.h" | 12 #include "chrome/browser/sync/engine/syncer_proto_util.h" |
14 #include "chrome/browser/sync/engine/syncer_types.h" | 13 #include "chrome/browser/sync/engine/syncer_types.h" |
15 #include "chrome/browser/sync/engine/syncproto.h" | 14 #include "chrome/browser/sync/engine/syncproto.h" |
16 #include "chrome/browser/sync/protocol/bookmark_specifics.pb.h" | 15 #include "chrome/browser/sync/protocol/bookmark_specifics.pb.h" |
17 #include "chrome/browser/sync/protocol/nigori_specifics.pb.h" | 16 #include "chrome/browser/sync/protocol/nigori_specifics.pb.h" |
18 #include "chrome/browser/sync/protocol/sync.pb.h" | 17 #include "chrome/browser/sync/protocol/sync.pb.h" |
19 #include "chrome/browser/sync/syncable/directory_manager.h" | 18 #include "chrome/browser/sync/syncable/directory_manager.h" |
20 #include "chrome/browser/sync/syncable/model_type.h" | 19 #include "chrome/browser/sync/syncable/model_type.h" |
21 #include "chrome/browser/sync/syncable/nigori_util.h" | |
22 #include "chrome/browser/sync/syncable/syncable.h" | 20 #include "chrome/browser/sync/syncable/syncable.h" |
23 #include "chrome/browser/sync/syncable/syncable_changes_version.h" | 21 #include "chrome/browser/sync/syncable/syncable_changes_version.h" |
24 | 22 |
25 using syncable::BASE_VERSION; | 23 using syncable::BASE_VERSION; |
26 using syncable::Blob; | 24 using syncable::Blob; |
27 using syncable::CHANGES_VERSION; | 25 using syncable::CHANGES_VERSION; |
28 using syncable::CREATE; | 26 using syncable::CREATE; |
29 using syncable::CREATE_NEW_UPDATE_ITEM; | 27 using syncable::CREATE_NEW_UPDATE_ITEM; |
30 using syncable::CTIME; | 28 using syncable::CTIME; |
31 using syncable::ComparePathNames; | 29 using syncable::ComparePathNames; |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 syncable::Id client_item_id = syncable::Id::CreateFromClientString( | 212 syncable::Id client_item_id = syncable::Id::CreateFromClientString( |
215 update.originator_client_item_id()); | 213 update.originator_client_item_id()); |
216 DCHECK(!client_item_id.ServerKnows()); | 214 DCHECK(!client_item_id.ServerKnows()); |
217 syncable::Entry local_entry(trans, GET_BY_ID, client_item_id); | 215 syncable::Entry local_entry(trans, GET_BY_ID, client_item_id); |
218 | 216 |
219 // If it exists, then our local client lost a commit response. Use | 217 // If it exists, then our local client lost a commit response. Use |
220 // the local entry. | 218 // the local entry. |
221 if (local_entry.good() && !local_entry.Get(IS_DEL)) { | 219 if (local_entry.good() && !local_entry.Get(IS_DEL)) { |
222 int64 old_version = local_entry.Get(BASE_VERSION); | 220 int64 old_version = local_entry.Get(BASE_VERSION); |
223 int64 new_version = update.version(); | 221 int64 new_version = update.version(); |
224 DCHECK_LE(old_version, 0); | 222 DCHECK(old_version <= 0); |
225 DCHECK_GT(new_version, 0); | 223 DCHECK(new_version > 0); |
226 // Otherwise setting the base version could cause a consistency failure. | 224 // Otherwise setting the base version could cause a consistency failure. |
227 // An entry should never be version 0 and SYNCED. | 225 // An entry should never be version 0 and SYNCED. |
228 DCHECK(local_entry.Get(IS_UNSYNCED)); | 226 DCHECK(local_entry.Get(IS_UNSYNCED)); |
229 | 227 |
230 // Just a quick sanity check. | 228 // Just a quick sanity check. |
231 DCHECK(!local_entry.Get(ID).ServerKnows()); | 229 DCHECK(!local_entry.Get(ID).ServerKnows()); |
232 | 230 |
233 VLOG(1) << "Reuniting lost commit response IDs. server id: " | 231 VLOG(1) << "Reuniting lost commit response IDs. server id: " |
234 << update.id() << " local id: " << local_entry.Get(ID) | 232 << update.id() << " local id: " << local_entry.Get(ID) |
235 << " new version: " << new_version; | 233 << " new version: " << new_version; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 Directory::ChildHandles handles; | 279 Directory::ChildHandles handles; |
282 trans->directory()->GetChildHandles(trans, id, &handles); | 280 trans->directory()->GetChildHandles(trans, id, &handles); |
283 if (!handles.empty()) { | 281 if (!handles.empty()) { |
284 // If we have still-existing children, then we need to deal with | 282 // If we have still-existing children, then we need to deal with |
285 // them before we can process this change. | 283 // them before we can process this change. |
286 VLOG(1) << "Not deleting directory; it's not empty " << *entry; | 284 VLOG(1) << "Not deleting directory; it's not empty " << *entry; |
287 return CONFLICT; | 285 return CONFLICT; |
288 } | 286 } |
289 } | 287 } |
290 | 288 |
291 // We intercept updates to the Nigori node, update the Cryptographer and | 289 // We intercept updates to the Nigori node and update the Cryptographer here |
292 // encrypt any unsynced changes here because there is no Nigori | 290 // because there is no Nigori ChangeProcessor. |
293 // ChangeProcessor. | |
294 const sync_pb::EntitySpecifics& specifics = entry->Get(SERVER_SPECIFICS); | 291 const sync_pb::EntitySpecifics& specifics = entry->Get(SERVER_SPECIFICS); |
295 if (specifics.HasExtension(sync_pb::nigori)) { | 292 if (specifics.HasExtension(sync_pb::nigori)) { |
296 const sync_pb::NigoriSpecifics& nigori = | 293 const sync_pb::NigoriSpecifics& nigori = |
297 specifics.GetExtension(sync_pb::nigori); | 294 specifics.GetExtension(sync_pb::nigori); |
298 if (!nigori.encrypted().blob().empty()) { | 295 if (!nigori.encrypted().blob().empty()) { |
299 if (cryptographer->CanDecrypt(nigori.encrypted())) { | 296 if (cryptographer->CanDecrypt(nigori.encrypted())) { |
300 cryptographer->SetKeys(nigori.encrypted()); | 297 cryptographer->SetKeys(nigori.encrypted()); |
301 } else { | 298 } else { |
302 cryptographer->SetPendingKeys(nigori.encrypted()); | 299 cryptographer->SetPendingKeys(nigori.encrypted()); |
303 } | 300 } |
304 } | 301 } |
305 | |
306 // Make sure any unsynced changes are properly encrypted as necessary. | |
307 syncable::ModelTypeSet encrypted_types = | |
308 syncable::GetEncryptedDataTypesFromNigori(nigori); | |
309 if (!VerifyUnsyncedChangesAreEncrypted(trans, encrypted_types) && | |
310 (!cryptographer->is_ready() || | |
311 !syncable::ProcessUnsyncedChangesForEncryption(trans, encrypted_types, | |
312 cryptographer))) { | |
313 // We were unable to encrypt the changes, possibly due to a missing | |
314 // passphrase. We return conflict, even though the conflict is with the | |
315 // unsynced change and not the nigori node. We ensure foward progress | |
316 // because the cryptographer already has the pending keys set, so once | |
317 // the new passphrase is entered we should be able to encrypt properly. | |
318 // And, because this update will not be applied yet, next time around | |
319 // we will properly encrypt all appropriate unsynced data. | |
320 VLOG(1) << "Marking nigori node update as conflicting due to being unable" | |
321 << " to encrypt all necessary unsynced changes."; | |
322 return CONFLICT; | |
323 } | |
324 | |
325 // Note that we don't bother to encrypt any synced data that now requires | |
326 // encryption. The machine that turned on encryption should encrypt | |
327 // everything itself. It's possible it could get interrupted during this | |
328 // process, but we currently reencrypt everything at startup as well, | |
329 // so as soon as a client is restarted with this datatype encrypted, all the | |
330 // data should be updated as necessary. | |
331 } | 302 } |
332 | 303 |
333 // Only apply updates that we can decrypt. Updates that can't be decrypted yet | 304 // Only apply updates that we can decrypt. Updates that can't be decrypted yet |
334 // will stay in conflict until the user provides a passphrase that lets the | 305 // will stay in conflict until the user provides a passphrase that lets the |
335 // Cryptographer decrypt them. | 306 // Cryptographer decrypt them. |
336 if (!entry->Get(SERVER_IS_DIR)) { | 307 if (!entry->Get(SERVER_IS_DIR) && specifics.HasExtension(sync_pb::password)) { |
337 if (specifics.has_encrypted() && | 308 const sync_pb::PasswordSpecifics& password = |
338 !cryptographer->CanDecrypt(specifics.encrypted())) { | 309 specifics.GetExtension(sync_pb::password); |
| 310 if (!cryptographer->CanDecrypt(password.encrypted())) { |
339 // We can't decrypt this node yet. | 311 // We can't decrypt this node yet. |
340 return CONFLICT; | 312 return CONFLICT; |
341 } else if (specifics.HasExtension(sync_pb::password)) { | |
342 // Passwords use their own legacy encryption scheme. | |
343 const sync_pb::PasswordSpecifics& password = | |
344 specifics.GetExtension(sync_pb::password); | |
345 if (!cryptographer->CanDecrypt(password.encrypted())) { | |
346 return CONFLICT; | |
347 } | |
348 } | 313 } |
349 } | 314 } |
350 | 315 |
351 SyncerUtil::UpdateLocalDataFromServerData(trans, entry); | 316 SyncerUtil::UpdateLocalDataFromServerData(trans, entry); |
352 | 317 |
353 return SUCCESS; | 318 return SUCCESS; |
354 } | 319 } |
355 | 320 |
356 namespace { | 321 namespace { |
357 // Helper to synthesize a new-style sync_pb::EntitySpecifics for use locally, | 322 // Helper to synthesize a new-style sync_pb::EntitySpecifics for use locally, |
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
897 | 862 |
898 // |update_entry| is considered to be somewhere after |candidate|, so store | 863 // |update_entry| is considered to be somewhere after |candidate|, so store |
899 // it as the upper bound. | 864 // it as the upper bound. |
900 closest_sibling = candidate.Get(ID); | 865 closest_sibling = candidate.Get(ID); |
901 } | 866 } |
902 | 867 |
903 return closest_sibling; | 868 return closest_sibling; |
904 } | 869 } |
905 | 870 |
906 } // namespace browser_sync | 871 } // namespace browser_sync |
OLD | NEW |