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> |
7 #include <set> | 8 #include <set> |
8 #include <string> | 9 #include <string> |
9 #include <vector> | 10 #include <vector> |
10 | 11 |
11 #include "chrome/browser/sync/engine/conflict_resolver.h" | 12 #include "chrome/browser/sync/engine/conflict_resolver.h" |
12 #include "chrome/browser/sync/engine/syncer_proto_util.h" | 13 #include "chrome/browser/sync/engine/syncer_proto_util.h" |
13 #include "chrome/browser/sync/engine/syncer_types.h" | 14 #include "chrome/browser/sync/engine/syncer_types.h" |
14 #include "chrome/browser/sync/engine/syncproto.h" | 15 #include "chrome/browser/sync/engine/syncproto.h" |
15 #include "chrome/browser/sync/protocol/bookmark_specifics.pb.h" | 16 #include "chrome/browser/sync/protocol/bookmark_specifics.pb.h" |
16 #include "chrome/browser/sync/protocol/nigori_specifics.pb.h" | 17 #include "chrome/browser/sync/protocol/nigori_specifics.pb.h" |
17 #include "chrome/browser/sync/protocol/sync.pb.h" | 18 #include "chrome/browser/sync/protocol/sync.pb.h" |
18 #include "chrome/browser/sync/syncable/directory_manager.h" | 19 #include "chrome/browser/sync/syncable/directory_manager.h" |
19 #include "chrome/browser/sync/syncable/model_type.h" | 20 #include "chrome/browser/sync/syncable/model_type.h" |
| 21 #include "chrome/browser/sync/syncable/nigori_util.h" |
20 #include "chrome/browser/sync/syncable/syncable.h" | 22 #include "chrome/browser/sync/syncable/syncable.h" |
21 #include "chrome/browser/sync/syncable/syncable_changes_version.h" | 23 #include "chrome/browser/sync/syncable/syncable_changes_version.h" |
22 | 24 |
23 using syncable::BASE_VERSION; | 25 using syncable::BASE_VERSION; |
24 using syncable::Blob; | 26 using syncable::Blob; |
25 using syncable::CHANGES_VERSION; | 27 using syncable::CHANGES_VERSION; |
26 using syncable::CREATE; | 28 using syncable::CREATE; |
27 using syncable::CREATE_NEW_UPDATE_ITEM; | 29 using syncable::CREATE_NEW_UPDATE_ITEM; |
28 using syncable::CTIME; | 30 using syncable::CTIME; |
29 using syncable::ComparePathNames; | 31 using syncable::ComparePathNames; |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 syncable::Id client_item_id = syncable::Id::CreateFromClientString( | 214 syncable::Id client_item_id = syncable::Id::CreateFromClientString( |
213 update.originator_client_item_id()); | 215 update.originator_client_item_id()); |
214 DCHECK(!client_item_id.ServerKnows()); | 216 DCHECK(!client_item_id.ServerKnows()); |
215 syncable::Entry local_entry(trans, GET_BY_ID, client_item_id); | 217 syncable::Entry local_entry(trans, GET_BY_ID, client_item_id); |
216 | 218 |
217 // If it exists, then our local client lost a commit response. Use | 219 // If it exists, then our local client lost a commit response. Use |
218 // the local entry. | 220 // the local entry. |
219 if (local_entry.good() && !local_entry.Get(IS_DEL)) { | 221 if (local_entry.good() && !local_entry.Get(IS_DEL)) { |
220 int64 old_version = local_entry.Get(BASE_VERSION); | 222 int64 old_version = local_entry.Get(BASE_VERSION); |
221 int64 new_version = update.version(); | 223 int64 new_version = update.version(); |
222 DCHECK(old_version <= 0); | 224 DCHECK_LE(old_version, 0); |
223 DCHECK(new_version > 0); | 225 DCHECK_GT(new_version, 0); |
224 // Otherwise setting the base version could cause a consistency failure. | 226 // Otherwise setting the base version could cause a consistency failure. |
225 // An entry should never be version 0 and SYNCED. | 227 // An entry should never be version 0 and SYNCED. |
226 DCHECK(local_entry.Get(IS_UNSYNCED)); | 228 DCHECK(local_entry.Get(IS_UNSYNCED)); |
227 | 229 |
228 // Just a quick sanity check. | 230 // Just a quick sanity check. |
229 DCHECK(!local_entry.Get(ID).ServerKnows()); | 231 DCHECK(!local_entry.Get(ID).ServerKnows()); |
230 | 232 |
231 VLOG(1) << "Reuniting lost commit response IDs. server id: " | 233 VLOG(1) << "Reuniting lost commit response IDs. server id: " |
232 << update.id() << " local id: " << local_entry.Get(ID) | 234 << update.id() << " local id: " << local_entry.Get(ID) |
233 << " new version: " << new_version; | 235 << " new version: " << new_version; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 Directory::ChildHandles handles; | 281 Directory::ChildHandles handles; |
280 trans->directory()->GetChildHandles(trans, id, &handles); | 282 trans->directory()->GetChildHandles(trans, id, &handles); |
281 if (!handles.empty()) { | 283 if (!handles.empty()) { |
282 // If we have still-existing children, then we need to deal with | 284 // If we have still-existing children, then we need to deal with |
283 // them before we can process this change. | 285 // them before we can process this change. |
284 VLOG(1) << "Not deleting directory; it's not empty " << *entry; | 286 VLOG(1) << "Not deleting directory; it's not empty " << *entry; |
285 return CONFLICT; | 287 return CONFLICT; |
286 } | 288 } |
287 } | 289 } |
288 | 290 |
289 // We intercept updates to the Nigori node and update the Cryptographer here | 291 // We intercept updates to the Nigori node, update the Cryptographer and |
290 // because there is no Nigori ChangeProcessor. | 292 // encrypt any unsynced changes here because there is no Nigori |
| 293 // ChangeProcessor. |
291 const sync_pb::EntitySpecifics& specifics = entry->Get(SERVER_SPECIFICS); | 294 const sync_pb::EntitySpecifics& specifics = entry->Get(SERVER_SPECIFICS); |
292 if (specifics.HasExtension(sync_pb::nigori)) { | 295 if (specifics.HasExtension(sync_pb::nigori)) { |
293 const sync_pb::NigoriSpecifics& nigori = | 296 const sync_pb::NigoriSpecifics& nigori = |
294 specifics.GetExtension(sync_pb::nigori); | 297 specifics.GetExtension(sync_pb::nigori); |
295 if (!nigori.encrypted().blob().empty()) { | 298 if (!nigori.encrypted().blob().empty()) { |
296 if (cryptographer->CanDecrypt(nigori.encrypted())) { | 299 if (cryptographer->CanDecrypt(nigori.encrypted())) { |
297 cryptographer->SetKeys(nigori.encrypted()); | 300 cryptographer->SetKeys(nigori.encrypted()); |
298 } else { | 301 } else { |
299 cryptographer->SetPendingKeys(nigori.encrypted()); | 302 cryptographer->SetPendingKeys(nigori.encrypted()); |
300 } | 303 } |
301 } | 304 } |
| 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. |
302 } | 331 } |
303 | 332 |
304 // Only apply updates that we can decrypt. Updates that can't be decrypted yet | 333 // Only apply updates that we can decrypt. Updates that can't be decrypted yet |
305 // will stay in conflict until the user provides a passphrase that lets the | 334 // will stay in conflict until the user provides a passphrase that lets the |
306 // Cryptographer decrypt them. | 335 // Cryptographer decrypt them. |
307 if (!entry->Get(SERVER_IS_DIR) && specifics.HasExtension(sync_pb::password)) { | 336 if (!entry->Get(SERVER_IS_DIR)) { |
308 const sync_pb::PasswordSpecifics& password = | 337 if (specifics.has_encrypted() && |
309 specifics.GetExtension(sync_pb::password); | 338 !cryptographer->CanDecrypt(specifics.encrypted())) { |
310 if (!cryptographer->CanDecrypt(password.encrypted())) { | |
311 // We can't decrypt this node yet. | 339 // We can't decrypt this node yet. |
312 return CONFLICT; | 340 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 } |
313 } | 348 } |
314 } | 349 } |
315 | 350 |
316 SyncerUtil::UpdateLocalDataFromServerData(trans, entry); | 351 SyncerUtil::UpdateLocalDataFromServerData(trans, entry); |
317 | 352 |
318 return SUCCESS; | 353 return SUCCESS; |
319 } | 354 } |
320 | 355 |
321 namespace { | 356 namespace { |
322 // Helper to synthesize a new-style sync_pb::EntitySpecifics for use locally, | 357 // 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... |
862 | 897 |
863 // |update_entry| is considered to be somewhere after |candidate|, so store | 898 // |update_entry| is considered to be somewhere after |candidate|, so store |
864 // it as the upper bound. | 899 // it as the upper bound. |
865 closest_sibling = candidate.Get(ID); | 900 closest_sibling = candidate.Get(ID); |
866 } | 901 } |
867 | 902 |
868 return closest_sibling; | 903 return closest_sibling; |
869 } | 904 } |
870 | 905 |
871 } // namespace browser_sync | 906 } // namespace browser_sync |
OLD | NEW |