Chromium Code Reviews| 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/syncapi.h" | 5 #include "chrome/browser/sync/engine/syncapi.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 7 #include <bitset> | 8 #include <bitset> |
| 8 #include <iomanip> | 9 #include <iomanip> |
| 9 #include <list> | 10 #include <list> |
| 11 #include <queue> | |
| 10 #include <string> | 12 #include <string> |
| 11 #include <vector> | 13 #include <vector> |
| 12 | 14 |
| 13 #include "base/base64.h" | 15 #include "base/base64.h" |
| 14 #include "base/logging.h" | 16 #include "base/logging.h" |
| 15 #include "base/message_loop.h" | 17 #include "base/message_loop.h" |
| 16 #include "base/scoped_ptr.h" | 18 #include "base/scoped_ptr.h" |
| 17 #include "base/sha1.h" | 19 #include "base/sha1.h" |
| 18 #include "base/string_util.h" | 20 #include "base/string_util.h" |
| 19 #include "base/synchronization/lock.h" | 21 #include "base/synchronization/lock.h" |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 38 #include "chrome/browser/sync/protocol/preference_specifics.pb.h" | 40 #include "chrome/browser/sync/protocol/preference_specifics.pb.h" |
| 39 #include "chrome/browser/sync/protocol/session_specifics.pb.h" | 41 #include "chrome/browser/sync/protocol/session_specifics.pb.h" |
| 40 #include "chrome/browser/sync/protocol/service_constants.h" | 42 #include "chrome/browser/sync/protocol/service_constants.h" |
| 41 #include "chrome/browser/sync/protocol/sync.pb.h" | 43 #include "chrome/browser/sync/protocol/sync.pb.h" |
| 42 #include "chrome/browser/sync/protocol/theme_specifics.pb.h" | 44 #include "chrome/browser/sync/protocol/theme_specifics.pb.h" |
| 43 #include "chrome/browser/sync/protocol/typed_url_specifics.pb.h" | 45 #include "chrome/browser/sync/protocol/typed_url_specifics.pb.h" |
| 44 #include "chrome/browser/sync/sessions/sync_session.h" | 46 #include "chrome/browser/sync/sessions/sync_session.h" |
| 45 #include "chrome/browser/sync/sessions/sync_session_context.h" | 47 #include "chrome/browser/sync/sessions/sync_session_context.h" |
| 46 #include "chrome/browser/sync/syncable/autofill_migration.h" | 48 #include "chrome/browser/sync/syncable/autofill_migration.h" |
| 47 #include "chrome/browser/sync/syncable/directory_manager.h" | 49 #include "chrome/browser/sync/syncable/directory_manager.h" |
| 50 #include "chrome/browser/sync/syncable/nigori_util.h" | |
| 48 #include "chrome/browser/sync/syncable/syncable.h" | 51 #include "chrome/browser/sync/syncable/syncable.h" |
| 49 #include "chrome/browser/sync/util/crypto_helpers.h" | 52 #include "chrome/browser/sync/util/crypto_helpers.h" |
| 50 #include "chrome/common/deprecated/event_sys.h" | 53 #include "chrome/common/deprecated/event_sys.h" |
| 51 #include "chrome/common/net/gaia/gaia_authenticator.h" | 54 #include "chrome/common/net/gaia/gaia_authenticator.h" |
| 52 #include "jingle/notifier/listener/mediator_thread_impl.h" | 55 #include "jingle/notifier/listener/mediator_thread_impl.h" |
| 53 #include "jingle/notifier/listener/notification_constants.h" | 56 #include "jingle/notifier/listener/notification_constants.h" |
| 54 #include "jingle/notifier/listener/talk_mediator.h" | 57 #include "jingle/notifier/listener/talk_mediator.h" |
| 55 #include "jingle/notifier/listener/talk_mediator_impl.h" | 58 #include "jingle/notifier/listener/talk_mediator_impl.h" |
| 56 #include "net/base/network_change_notifier.h" | 59 #include "net/base/network_change_notifier.h" |
| 57 | 60 |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 if (!crypto->Decrypt(encrypted, data.get())) | 195 if (!crypto->Decrypt(encrypted, data.get())) |
| 193 return NULL; | 196 return NULL; |
| 194 return data.release(); | 197 return data.release(); |
| 195 } | 198 } |
| 196 | 199 |
| 197 bool BaseNode::DecryptIfNecessary(Entry* entry) { | 200 bool BaseNode::DecryptIfNecessary(Entry* entry) { |
| 198 if (GetIsFolder()) return true; // Ignore the top-level password folder. | 201 if (GetIsFolder()) return true; // Ignore the top-level password folder. |
| 199 const sync_pb::EntitySpecifics& specifics = | 202 const sync_pb::EntitySpecifics& specifics = |
| 200 entry->Get(syncable::SPECIFICS); | 203 entry->Get(syncable::SPECIFICS); |
| 201 if (specifics.HasExtension(sync_pb::password)) { | 204 if (specifics.HasExtension(sync_pb::password)) { |
| 205 // Passwords have their own legacy encryption structure. | |
| 202 scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics( | 206 scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics( |
| 203 specifics, GetTransaction()->GetCryptographer())); | 207 specifics, GetTransaction()->GetCryptographer())); |
| 204 if (!data.get()) | 208 if (!data.get()) |
| 205 return false; | 209 return false; |
| 206 password_data_.swap(data); | 210 password_data_.swap(data); |
| 211 return true; | |
| 212 } | |
| 213 | |
| 214 // We assume any node with the encrypted field set has encrypted data. | |
| 215 if (!specifics.has_encrypted()) | |
| 216 return true; | |
| 217 | |
| 218 const sync_pb::EncryptedData& encrypted = | |
| 219 specifics.encrypted(); | |
| 220 std::string plaintext_data = GetTransaction()->GetCryptographer()-> | |
| 221 DecryptToString(encrypted); | |
| 222 if (plaintext_data.length() == 0) | |
| 223 return false; | |
| 224 if (!unencrypted_data_.ParseFromString(plaintext_data)) { | |
| 225 LOG(ERROR) << "Failed to decrypt encrypted node of type " << | |
| 226 syncable::ModelTypeToString(entry->GetModelType()) << "."; | |
| 227 return false; | |
| 207 } | 228 } |
| 208 return true; | 229 return true; |
| 209 } | 230 } |
| 210 | 231 |
| 232 const sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics( | |
| 233 const syncable::Entry* entry) const { | |
| 234 const sync_pb::EntitySpecifics& specifics = entry->Get(SPECIFICS); | |
| 235 if (specifics.has_encrypted()) { | |
| 236 DCHECK(syncable::GetModelTypeFromSpecifics(unencrypted_data_) != | |
| 237 syncable::UNSPECIFIED); | |
| 238 return unencrypted_data_; | |
| 239 } else { | |
| 240 DCHECK(syncable::GetModelTypeFromSpecifics(unencrypted_data_) == | |
| 241 syncable::UNSPECIFIED); | |
| 242 return specifics; | |
| 243 } | |
| 244 } | |
| 245 | |
| 211 int64 BaseNode::GetParentId() const { | 246 int64 BaseNode::GetParentId() const { |
| 212 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), | 247 return IdToMetahandle(GetTransaction()->GetWrappedTrans(), |
| 213 GetEntry()->Get(syncable::PARENT_ID)); | 248 GetEntry()->Get(syncable::PARENT_ID)); |
| 214 } | 249 } |
| 215 | 250 |
| 216 int64 BaseNode::GetId() const { | 251 int64 BaseNode::GetId() const { |
| 217 return GetEntry()->Get(syncable::META_HANDLE); | 252 return GetEntry()->Get(syncable::META_HANDLE); |
| 218 } | 253 } |
| 219 | 254 |
| 220 int64 BaseNode::GetModificationTime() const { | 255 int64 BaseNode::GetModificationTime() const { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 267 reinterpret_cast<const unsigned char*>(favicon.data() + | 302 reinterpret_cast<const unsigned char*>(favicon.data() + |
| 268 favicon.length())); | 303 favicon.length())); |
| 269 } | 304 } |
| 270 | 305 |
| 271 int64 BaseNode::GetExternalId() const { | 306 int64 BaseNode::GetExternalId() const { |
| 272 return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID); | 307 return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID); |
| 273 } | 308 } |
| 274 | 309 |
| 275 const sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const { | 310 const sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const { |
| 276 DCHECK(GetModelType() == syncable::APPS); | 311 DCHECK(GetModelType() == syncable::APPS); |
| 277 return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::app); | 312 const sync_pb::EntitySpecifics& unencrypted = |
| 313 GetUnencryptedSpecifics(GetEntry()); | |
| 314 return unencrypted.GetExtension(sync_pb::app); | |
| 278 } | 315 } |
| 279 | 316 |
| 280 const sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const { | 317 const sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const { |
| 281 DCHECK(GetModelType() == syncable::AUTOFILL); | 318 DCHECK(GetModelType() == syncable::AUTOFILL); |
| 282 return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::autofill); | 319 const sync_pb::EntitySpecifics& unencrypted = |
| 320 GetUnencryptedSpecifics(GetEntry()); | |
| 321 return unencrypted.GetExtension(sync_pb::autofill); | |
| 283 } | 322 } |
| 284 | 323 |
| 285 const AutofillProfileSpecifics& BaseNode::GetAutofillProfileSpecifics() const { | 324 const AutofillProfileSpecifics& BaseNode::GetAutofillProfileSpecifics() const { |
| 286 DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE); | 325 DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE); |
| 287 return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::autofill_profile); | 326 const sync_pb::EntitySpecifics& unencrypted = |
| 327 GetUnencryptedSpecifics(GetEntry()); | |
| 328 return unencrypted.GetExtension(sync_pb::autofill_profile); | |
| 288 } | 329 } |
| 289 | 330 |
| 290 const sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const { | 331 const sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const { |
| 291 DCHECK(GetModelType() == syncable::BOOKMARKS); | 332 DCHECK(GetModelType() == syncable::BOOKMARKS); |
| 292 return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::bookmark); | 333 const sync_pb::EntitySpecifics& unencrypted = |
| 334 GetUnencryptedSpecifics(GetEntry()); | |
| 335 return unencrypted.GetExtension(sync_pb::bookmark); | |
| 293 } | 336 } |
| 294 | 337 |
| 295 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const { | 338 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const { |
| 296 DCHECK(GetModelType() == syncable::NIGORI); | 339 DCHECK(GetModelType() == syncable::NIGORI); |
| 297 return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::nigori); | 340 const sync_pb::EntitySpecifics& unencrypted = |
| 341 GetUnencryptedSpecifics(GetEntry()); | |
| 342 return unencrypted.GetExtension(sync_pb::nigori); | |
| 298 } | 343 } |
| 299 | 344 |
| 300 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const { | 345 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const { |
| 301 DCHECK(GetModelType() == syncable::PASSWORDS); | 346 DCHECK(GetModelType() == syncable::PASSWORDS); |
| 302 DCHECK(password_data_.get()); | 347 DCHECK(password_data_.get()); |
| 303 return *password_data_; | 348 return *password_data_; |
| 304 } | 349 } |
| 305 | 350 |
| 306 const sync_pb::PreferenceSpecifics& BaseNode::GetPreferenceSpecifics() const { | 351 const sync_pb::PreferenceSpecifics& BaseNode::GetPreferenceSpecifics() const { |
| 307 DCHECK(GetModelType() == syncable::PREFERENCES); | 352 DCHECK(GetModelType() == syncable::PREFERENCES); |
| 308 return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::preference); | 353 const sync_pb::EntitySpecifics& unencrypted = |
| 354 GetUnencryptedSpecifics(GetEntry()); | |
| 355 return unencrypted.GetExtension(sync_pb::preference); | |
| 309 } | 356 } |
| 310 | 357 |
| 311 const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const { | 358 const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const { |
| 312 DCHECK(GetModelType() == syncable::THEMES); | 359 DCHECK(GetModelType() == syncable::THEMES); |
| 313 return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::theme); | 360 const sync_pb::EntitySpecifics& unencrypted = |
| 361 GetUnencryptedSpecifics(GetEntry()); | |
| 362 return unencrypted.GetExtension(sync_pb::theme); | |
| 314 } | 363 } |
| 315 | 364 |
| 316 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const { | 365 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const { |
| 317 DCHECK(GetModelType() == syncable::TYPED_URLS); | 366 DCHECK(GetModelType() == syncable::TYPED_URLS); |
| 318 return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::typed_url); | 367 const sync_pb::EntitySpecifics& unencrypted = |
| 368 GetUnencryptedSpecifics(GetEntry()); | |
| 369 return unencrypted.GetExtension(sync_pb::typed_url); | |
| 319 } | 370 } |
| 320 | 371 |
| 321 const sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const { | 372 const sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const { |
| 322 DCHECK(GetModelType() == syncable::EXTENSIONS); | 373 DCHECK(GetModelType() == syncable::EXTENSIONS); |
| 323 return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::extension); | 374 const sync_pb::EntitySpecifics& unencrypted = |
| 375 GetUnencryptedSpecifics(GetEntry()); | |
| 376 return unencrypted.GetExtension(sync_pb::extension); | |
| 324 } | 377 } |
| 325 | 378 |
| 326 const sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const { | 379 const sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const { |
| 327 DCHECK(GetModelType() == syncable::SESSIONS); | 380 DCHECK(GetModelType() == syncable::SESSIONS); |
| 328 return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::session); | 381 const sync_pb::EntitySpecifics& unencrypted = |
| 382 GetUnencryptedSpecifics(GetEntry()); | |
| 383 return unencrypted.GetExtension(sync_pb::session); | |
| 329 } | 384 } |
| 330 | 385 |
| 331 syncable::ModelType BaseNode::GetModelType() const { | 386 syncable::ModelType BaseNode::GetModelType() const { |
| 332 return GetEntry()->GetModelType(); | 387 return GetEntry()->GetModelType(); |
| 333 } | 388 } |
| 334 | 389 |
| 335 //////////////////////////////////// | 390 //////////////////////////////////// |
| 336 // WriteNode member definitions | 391 // WriteNode member definitions |
| 392 void WriteNode::EncryptIfNecessary(sync_pb::EntitySpecifics* unencrypted) { | |
| 393 syncable::ModelType type = syncable::GetModelTypeFromSpecifics(*unencrypted); | |
| 394 DCHECK(type != syncable::UNSPECIFIED); | |
|
tim (not reviewing)
2011/02/11 06:52:31
DCHECK_NE
Nicolas Zea
2011/02/14 21:18:41
Done.
| |
| 395 DCHECK(type != syncable::PASSWORDS); // Passwords use their own encryption. | |
| 396 DCHECK(type != syncable::NIGORI); // Nigori is encrypted separately. | |
| 397 | |
| 398 syncable::ModelTypeSet encrypted_types = GetTransaction()->GetWrappedTrans()-> | |
| 399 GetEncryptedDatatypes(); | |
| 400 if (encrypted_types.count(type) == 0) { | |
| 401 // This datatype does not require encryption. | |
| 402 return; | |
| 403 } | |
| 404 | |
| 405 if (unencrypted->has_encrypted()) { | |
| 406 // This specifics is already encrypted, our work is done. | |
| 407 LOG(WARNING) << "Attempted to encrypt an already encrypted entity" | |
| 408 << " specifics of type " << syncable::ModelTypeToString(type) | |
| 409 << ". Dropping."; | |
| 410 return; | |
| 411 } | |
| 412 sync_pb::EntitySpecifics encrypted; | |
| 413 syncable::AddDefaultExtensionValue(type, &encrypted); | |
| 414 VLOG(2) << "Encrypted specifics of type " << syncable::ModelTypeToString(type) | |
| 415 << " with content: " << unencrypted->SerializeAsString() << "\n"; | |
| 416 if (!GetTransaction()->GetCryptographer()->Encrypt( | |
| 417 *unencrypted, | |
| 418 encrypted.mutable_encrypted())) { | |
| 419 LOG(ERROR) << "Could not encrypt data for node of type " << | |
| 420 syncable::ModelTypeToString(type); | |
| 421 NOTREACHED(); | |
| 422 } | |
| 423 unencrypted->CopyFrom(encrypted); | |
| 424 } | |
| 425 | |
| 337 void WriteNode::SetIsFolder(bool folder) { | 426 void WriteNode::SetIsFolder(bool folder) { |
| 338 if (entry_->Get(syncable::IS_DIR) == folder) | 427 if (entry_->Get(syncable::IS_DIR) == folder) |
| 339 return; // Skip redundant changes. | 428 return; // Skip redundant changes. |
| 340 | 429 |
| 341 entry_->Put(syncable::IS_DIR, folder); | 430 entry_->Put(syncable::IS_DIR, folder); |
| 342 MarkForSyncing(); | 431 MarkForSyncing(); |
| 343 } | 432 } |
| 344 | 433 |
| 345 void WriteNode::SetTitle(const std::wstring& title) { | 434 void WriteNode::SetTitle(const std::wstring& title) { |
| 346 std::string server_legal_name; | 435 std::string server_legal_name; |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 370 void WriteNode::SetAutofillSpecifics( | 459 void WriteNode::SetAutofillSpecifics( |
| 371 const sync_pb::AutofillSpecifics& new_value) { | 460 const sync_pb::AutofillSpecifics& new_value) { |
| 372 DCHECK(GetModelType() == syncable::AUTOFILL); | 461 DCHECK(GetModelType() == syncable::AUTOFILL); |
| 373 PutAutofillSpecificsAndMarkForSyncing(new_value); | 462 PutAutofillSpecificsAndMarkForSyncing(new_value); |
| 374 } | 463 } |
| 375 | 464 |
| 376 void WriteNode::PutAutofillSpecificsAndMarkForSyncing( | 465 void WriteNode::PutAutofillSpecificsAndMarkForSyncing( |
| 377 const sync_pb::AutofillSpecifics& new_value) { | 466 const sync_pb::AutofillSpecifics& new_value) { |
| 378 sync_pb::EntitySpecifics entity_specifics; | 467 sync_pb::EntitySpecifics entity_specifics; |
| 379 entity_specifics.MutableExtension(sync_pb::autofill)->CopyFrom(new_value); | 468 entity_specifics.MutableExtension(sync_pb::autofill)->CopyFrom(new_value); |
| 469 EncryptIfNecessary(&entity_specifics); | |
| 380 PutSpecificsAndMarkForSyncing(entity_specifics); | 470 PutSpecificsAndMarkForSyncing(entity_specifics); |
| 381 } | 471 } |
| 382 | 472 |
| 383 void WriteNode::SetAutofillProfileSpecifics( | 473 void WriteNode::SetAutofillProfileSpecifics( |
| 384 const sync_pb::AutofillProfileSpecifics& new_value) { | 474 const sync_pb::AutofillProfileSpecifics& new_value) { |
| 385 DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE); | 475 DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE); |
| 386 PutAutofillProfileSpecificsAndMarkForSyncing(new_value); | 476 PutAutofillProfileSpecificsAndMarkForSyncing(new_value); |
| 387 } | 477 } |
| 388 | 478 |
| 389 void WriteNode::PutAutofillProfileSpecificsAndMarkForSyncing( | 479 void WriteNode::PutAutofillProfileSpecificsAndMarkForSyncing( |
| 390 const sync_pb::AutofillProfileSpecifics& new_value) { | 480 const sync_pb::AutofillProfileSpecifics& new_value) { |
| 391 sync_pb::EntitySpecifics entity_specifics; | 481 sync_pb::EntitySpecifics entity_specifics; |
| 392 entity_specifics.MutableExtension(sync_pb::autofill_profile)->CopyFrom( | 482 entity_specifics.MutableExtension(sync_pb::autofill_profile)->CopyFrom( |
| 393 new_value); | 483 new_value); |
| 484 EncryptIfNecessary(&entity_specifics); | |
| 394 PutSpecificsAndMarkForSyncing(entity_specifics); | 485 PutSpecificsAndMarkForSyncing(entity_specifics); |
| 395 } | 486 } |
| 396 | 487 |
| 397 void WriteNode::SetBookmarkSpecifics( | 488 void WriteNode::SetBookmarkSpecifics( |
| 398 const sync_pb::BookmarkSpecifics& new_value) { | 489 const sync_pb::BookmarkSpecifics& new_value) { |
| 399 DCHECK(GetModelType() == syncable::BOOKMARKS); | 490 DCHECK(GetModelType() == syncable::BOOKMARKS); |
| 400 PutBookmarkSpecificsAndMarkForSyncing(new_value); | 491 PutBookmarkSpecificsAndMarkForSyncing(new_value); |
| 401 } | 492 } |
| 402 | 493 |
| 403 void WriteNode::PutBookmarkSpecificsAndMarkForSyncing( | 494 void WriteNode::PutBookmarkSpecificsAndMarkForSyncing( |
| 404 const sync_pb::BookmarkSpecifics& new_value) { | 495 const sync_pb::BookmarkSpecifics& new_value) { |
| 405 sync_pb::EntitySpecifics entity_specifics; | 496 sync_pb::EntitySpecifics entity_specifics; |
| 406 entity_specifics.MutableExtension(sync_pb::bookmark)->CopyFrom(new_value); | 497 entity_specifics.MutableExtension(sync_pb::bookmark)->CopyFrom(new_value); |
| 498 EncryptIfNecessary(&entity_specifics); | |
| 407 PutSpecificsAndMarkForSyncing(entity_specifics); | 499 PutSpecificsAndMarkForSyncing(entity_specifics); |
| 408 } | 500 } |
| 409 | 501 |
| 410 void WriteNode::SetNigoriSpecifics( | 502 void WriteNode::SetNigoriSpecifics( |
| 411 const sync_pb::NigoriSpecifics& new_value) { | 503 const sync_pb::NigoriSpecifics& new_value) { |
| 412 DCHECK(GetModelType() == syncable::NIGORI); | 504 DCHECK(GetModelType() == syncable::NIGORI); |
| 413 PutNigoriSpecificsAndMarkForSyncing(new_value); | 505 PutNigoriSpecificsAndMarkForSyncing(new_value); |
| 414 } | 506 } |
| 415 | 507 |
| 416 void WriteNode::PutNigoriSpecificsAndMarkForSyncing( | 508 void WriteNode::PutNigoriSpecificsAndMarkForSyncing( |
| 417 const sync_pb::NigoriSpecifics& new_value) { | 509 const sync_pb::NigoriSpecifics& new_value) { |
| 418 sync_pb::EntitySpecifics entity_specifics; | 510 sync_pb::EntitySpecifics entity_specifics; |
| 419 entity_specifics.MutableExtension(sync_pb::nigori)->CopyFrom(new_value); | 511 entity_specifics.MutableExtension(sync_pb::nigori)->CopyFrom(new_value); |
| 420 PutSpecificsAndMarkForSyncing(entity_specifics); | 512 PutSpecificsAndMarkForSyncing(entity_specifics); |
| 421 } | 513 } |
| 422 | 514 |
| 423 void WriteNode::SetPasswordSpecifics( | 515 void WriteNode::SetPasswordSpecifics( |
| 424 const sync_pb::PasswordSpecificsData& data) { | 516 const sync_pb::PasswordSpecificsData& data) { |
| 425 DCHECK(GetModelType() == syncable::PASSWORDS); | 517 DCHECK(GetModelType() == syncable::PASSWORDS); |
| 426 | |
| 427 sync_pb::PasswordSpecifics new_value; | 518 sync_pb::PasswordSpecifics new_value; |
| 428 if (!GetTransaction()->GetCryptographer()->Encrypt( | 519 if (!GetTransaction()->GetCryptographer()->Encrypt( |
| 429 data, | 520 data, |
| 430 new_value.mutable_encrypted())) { | 521 new_value.mutable_encrypted())) { |
| 431 NOTREACHED(); | 522 NOTREACHED(); |
| 432 } | 523 } |
| 433 | |
| 434 PutPasswordSpecificsAndMarkForSyncing(new_value); | 524 PutPasswordSpecificsAndMarkForSyncing(new_value); |
| 435 } | 525 } |
| 436 | 526 |
| 437 void WriteNode::SetPreferenceSpecifics( | 527 void WriteNode::SetPreferenceSpecifics( |
| 438 const sync_pb::PreferenceSpecifics& new_value) { | 528 const sync_pb::PreferenceSpecifics& new_value) { |
| 439 DCHECK(GetModelType() == syncable::PREFERENCES); | 529 DCHECK(GetModelType() == syncable::PREFERENCES); |
| 440 PutPreferenceSpecificsAndMarkForSyncing(new_value); | 530 PutPreferenceSpecificsAndMarkForSyncing(new_value); |
| 441 } | 531 } |
| 442 | 532 |
| 443 void WriteNode::SetThemeSpecifics( | 533 void WriteNode::SetThemeSpecifics( |
| 444 const sync_pb::ThemeSpecifics& new_value) { | 534 const sync_pb::ThemeSpecifics& new_value) { |
| 445 DCHECK(GetModelType() == syncable::THEMES); | 535 DCHECK(GetModelType() == syncable::THEMES); |
| 446 PutThemeSpecificsAndMarkForSyncing(new_value); | 536 PutThemeSpecificsAndMarkForSyncing(new_value); |
| 447 } | 537 } |
| 448 | 538 |
| 449 void WriteNode::SetSessionSpecifics( | 539 void WriteNode::SetSessionSpecifics( |
| 450 const sync_pb::SessionSpecifics& new_value) { | 540 const sync_pb::SessionSpecifics& new_value) { |
| 451 DCHECK(GetModelType() == syncable::SESSIONS); | 541 DCHECK(GetModelType() == syncable::SESSIONS); |
| 452 PutSessionSpecificsAndMarkForSyncing(new_value); | 542 PutSessionSpecificsAndMarkForSyncing(new_value); |
| 453 } | 543 } |
| 454 | 544 |
| 545 void WriteNode::ResetFromSpecifics() { | |
| 546 sync_pb::EntitySpecifics new_data; | |
| 547 new_data.CopyFrom(GetUnencryptedSpecifics(GetEntry())); | |
| 548 EncryptIfNecessary(&new_data); | |
| 549 PutSpecificsAndMarkForSyncing(new_data); | |
| 550 } | |
| 455 | 551 |
| 456 void WriteNode::PutPasswordSpecificsAndMarkForSyncing( | 552 void WriteNode::PutPasswordSpecificsAndMarkForSyncing( |
| 457 const sync_pb::PasswordSpecifics& new_value) { | 553 const sync_pb::PasswordSpecifics& new_value) { |
| 458 sync_pb::EntitySpecifics entity_specifics; | 554 sync_pb::EntitySpecifics entity_specifics; |
| 459 entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value); | 555 entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value); |
| 460 PutSpecificsAndMarkForSyncing(entity_specifics); | 556 PutSpecificsAndMarkForSyncing(entity_specifics); |
| 461 } | 557 } |
| 462 | 558 |
| 463 void WriteNode::PutPreferenceSpecificsAndMarkForSyncing( | 559 void WriteNode::PutPreferenceSpecificsAndMarkForSyncing( |
| 464 const sync_pb::PreferenceSpecifics& new_value) { | 560 const sync_pb::PreferenceSpecifics& new_value) { |
| 465 sync_pb::EntitySpecifics entity_specifics; | 561 sync_pb::EntitySpecifics entity_specifics; |
| 466 entity_specifics.MutableExtension(sync_pb::preference)->CopyFrom(new_value); | 562 entity_specifics.MutableExtension(sync_pb::preference)->CopyFrom(new_value); |
| 563 EncryptIfNecessary(&entity_specifics); | |
| 467 PutSpecificsAndMarkForSyncing(entity_specifics); | 564 PutSpecificsAndMarkForSyncing(entity_specifics); |
| 468 } | 565 } |
| 469 | 566 |
| 470 void WriteNode::SetTypedUrlSpecifics( | 567 void WriteNode::SetTypedUrlSpecifics( |
| 471 const sync_pb::TypedUrlSpecifics& new_value) { | 568 const sync_pb::TypedUrlSpecifics& new_value) { |
| 472 DCHECK(GetModelType() == syncable::TYPED_URLS); | 569 DCHECK(GetModelType() == syncable::TYPED_URLS); |
| 473 PutTypedUrlSpecificsAndMarkForSyncing(new_value); | 570 PutTypedUrlSpecificsAndMarkForSyncing(new_value); |
| 474 } | 571 } |
| 475 | 572 |
| 476 void WriteNode::SetExtensionSpecifics( | 573 void WriteNode::SetExtensionSpecifics( |
| 477 const sync_pb::ExtensionSpecifics& new_value) { | 574 const sync_pb::ExtensionSpecifics& new_value) { |
| 478 DCHECK(GetModelType() == syncable::EXTENSIONS); | 575 DCHECK(GetModelType() == syncable::EXTENSIONS); |
| 479 PutExtensionSpecificsAndMarkForSyncing(new_value); | 576 PutExtensionSpecificsAndMarkForSyncing(new_value); |
| 480 } | 577 } |
| 481 | 578 |
| 482 void WriteNode::PutAppSpecificsAndMarkForSyncing( | 579 void WriteNode::PutAppSpecificsAndMarkForSyncing( |
| 483 const sync_pb::AppSpecifics& new_value) { | 580 const sync_pb::AppSpecifics& new_value) { |
| 484 sync_pb::EntitySpecifics entity_specifics; | 581 sync_pb::EntitySpecifics entity_specifics; |
| 485 entity_specifics.MutableExtension(sync_pb::app)->CopyFrom(new_value); | 582 entity_specifics.MutableExtension(sync_pb::app)->CopyFrom(new_value); |
| 583 EncryptIfNecessary(&entity_specifics); | |
| 486 PutSpecificsAndMarkForSyncing(entity_specifics); | 584 PutSpecificsAndMarkForSyncing(entity_specifics); |
| 487 } | 585 } |
| 488 | 586 |
| 489 void WriteNode::PutThemeSpecificsAndMarkForSyncing( | 587 void WriteNode::PutThemeSpecificsAndMarkForSyncing( |
| 490 const sync_pb::ThemeSpecifics& new_value) { | 588 const sync_pb::ThemeSpecifics& new_value) { |
| 491 sync_pb::EntitySpecifics entity_specifics; | 589 sync_pb::EntitySpecifics entity_specifics; |
| 492 entity_specifics.MutableExtension(sync_pb::theme)->CopyFrom(new_value); | 590 entity_specifics.MutableExtension(sync_pb::theme)->CopyFrom(new_value); |
| 591 EncryptIfNecessary(&entity_specifics); | |
| 493 PutSpecificsAndMarkForSyncing(entity_specifics); | 592 PutSpecificsAndMarkForSyncing(entity_specifics); |
| 494 } | 593 } |
| 495 | 594 |
| 496 void WriteNode::PutTypedUrlSpecificsAndMarkForSyncing( | 595 void WriteNode::PutTypedUrlSpecificsAndMarkForSyncing( |
| 497 const sync_pb::TypedUrlSpecifics& new_value) { | 596 const sync_pb::TypedUrlSpecifics& new_value) { |
| 498 sync_pb::EntitySpecifics entity_specifics; | 597 sync_pb::EntitySpecifics entity_specifics; |
| 499 entity_specifics.MutableExtension(sync_pb::typed_url)->CopyFrom(new_value); | 598 entity_specifics.MutableExtension(sync_pb::typed_url)->CopyFrom(new_value); |
| 599 EncryptIfNecessary(&entity_specifics); | |
| 500 PutSpecificsAndMarkForSyncing(entity_specifics); | 600 PutSpecificsAndMarkForSyncing(entity_specifics); |
| 501 } | 601 } |
| 502 | 602 |
| 503 void WriteNode::PutExtensionSpecificsAndMarkForSyncing( | 603 void WriteNode::PutExtensionSpecificsAndMarkForSyncing( |
| 504 const sync_pb::ExtensionSpecifics& new_value) { | 604 const sync_pb::ExtensionSpecifics& new_value) { |
| 505 sync_pb::EntitySpecifics entity_specifics; | 605 sync_pb::EntitySpecifics entity_specifics; |
| 506 entity_specifics.MutableExtension(sync_pb::extension)->CopyFrom(new_value); | 606 entity_specifics.MutableExtension(sync_pb::extension)->CopyFrom(new_value); |
| 607 EncryptIfNecessary(&entity_specifics); | |
| 507 PutSpecificsAndMarkForSyncing(entity_specifics); | 608 PutSpecificsAndMarkForSyncing(entity_specifics); |
| 508 } | 609 } |
| 509 | 610 |
| 510 | |
| 511 void WriteNode::PutSessionSpecificsAndMarkForSyncing( | 611 void WriteNode::PutSessionSpecificsAndMarkForSyncing( |
| 512 const sync_pb::SessionSpecifics& new_value) { | 612 const sync_pb::SessionSpecifics& new_value) { |
| 513 sync_pb::EntitySpecifics entity_specifics; | 613 sync_pb::EntitySpecifics entity_specifics; |
| 514 entity_specifics.MutableExtension(sync_pb::session)->CopyFrom(new_value); | 614 entity_specifics.MutableExtension(sync_pb::session)->CopyFrom(new_value); |
| 615 EncryptIfNecessary(&entity_specifics); | |
| 515 PutSpecificsAndMarkForSyncing(entity_specifics); | 616 PutSpecificsAndMarkForSyncing(entity_specifics); |
| 516 } | 617 } |
| 517 | 618 |
| 518 | |
| 519 void WriteNode::PutSpecificsAndMarkForSyncing( | 619 void WriteNode::PutSpecificsAndMarkForSyncing( |
| 520 const sync_pb::EntitySpecifics& specifics) { | 620 const sync_pb::EntitySpecifics& specifics) { |
| 521 // Skip redundant changes. | 621 // Skip redundant changes. |
| 522 if (specifics.SerializeAsString() == | 622 if (specifics.SerializeAsString() == |
| 523 entry_->Get(SPECIFICS).SerializeAsString()) { | 623 entry_->Get(SPECIFICS).SerializeAsString()) { |
| 524 return; | 624 return; |
| 525 } | 625 } |
| 526 entry_->Put(SPECIFICS, specifics); | 626 entry_->Put(SPECIFICS, specifics); |
| 527 MarkForSyncing(); | 627 MarkForSyncing(); |
| 528 } | 628 } |
| (...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 997 | 1097 |
| 998 // Update tokens that we're using in Sync. Email must stay the same. | 1098 // Update tokens that we're using in Sync. Email must stay the same. |
| 999 void UpdateCredentials(const SyncCredentials& credentials); | 1099 void UpdateCredentials(const SyncCredentials& credentials); |
| 1000 | 1100 |
| 1001 // Tell the sync engine to start the syncing process. | 1101 // Tell the sync engine to start the syncing process. |
| 1002 void StartSyncing(); | 1102 void StartSyncing(); |
| 1003 | 1103 |
| 1004 // Whether or not the Nigori node is encrypted using an explicit passphrase. | 1104 // Whether or not the Nigori node is encrypted using an explicit passphrase. |
| 1005 bool IsUsingExplicitPassphrase(); | 1105 bool IsUsingExplicitPassphrase(); |
| 1006 | 1106 |
| 1107 // Set the datatypes we want to encrypt and encrypt any nodes as necessary. | |
| 1108 void EncryptDataTypes(const syncable::ModelTypeSet& encrypted_types); | |
| 1109 | |
| 1007 // Try to set the current passphrase to |passphrase|, and record whether | 1110 // Try to set the current passphrase to |passphrase|, and record whether |
| 1008 // it is an explicit passphrase or implicitly using gaia in the Nigori | 1111 // it is an explicit passphrase or implicitly using gaia in the Nigori |
| 1009 // node. | 1112 // node. |
| 1010 void SetPassphrase(const std::string& passphrase, bool is_explicit); | 1113 void SetPassphrase(const std::string& passphrase, bool is_explicit); |
| 1011 | 1114 |
| 1012 // Call periodically from a database-safe thread to persist recent changes | 1115 // Call periodically from a database-safe thread to persist recent changes |
| 1013 // to the syncapi model. | 1116 // to the syncapi model. |
| 1014 void SaveChanges(); | 1117 void SaveChanges(); |
| 1015 | 1118 |
| 1016 // This listener is called upon completion of a syncable transaction, and | 1119 // This listener is called upon completion of a syncable transaction, and |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1069 // See SyncManager::Shutdown for information. | 1172 // See SyncManager::Shutdown for information. |
| 1070 void Shutdown(); | 1173 void Shutdown(); |
| 1071 | 1174 |
| 1072 // Whether we're initialized to the point of being able to accept changes | 1175 // Whether we're initialized to the point of being able to accept changes |
| 1073 // (and hence allow transaction creation). See initialized_ for details. | 1176 // (and hence allow transaction creation). See initialized_ for details. |
| 1074 bool initialized() const { | 1177 bool initialized() const { |
| 1075 base::AutoLock lock(initialized_mutex_); | 1178 base::AutoLock lock(initialized_mutex_); |
| 1076 return initialized_; | 1179 return initialized_; |
| 1077 } | 1180 } |
| 1078 | 1181 |
| 1182 // If this is a deletion for a password, sets the legacy | |
| 1183 // ExtraPasswordChangeRecordData field of |buffer|. Otherwise sets | |
| 1184 // |buffer|'s specifics field to contain the unencrypted data. | |
| 1079 void SetExtraChangeRecordData(int64 id, | 1185 void SetExtraChangeRecordData(int64 id, |
| 1080 syncable::ModelType type, | 1186 syncable::ModelType type, |
| 1081 ChangeReorderBuffer* buffer, | 1187 ChangeReorderBuffer* buffer, |
| 1082 Cryptographer* cryptographer, | 1188 Cryptographer* cryptographer, |
| 1083 const syncable::EntryKernel& original, | 1189 const syncable::EntryKernel& original, |
| 1084 bool existed_before, | 1190 bool existed_before, |
| 1085 bool exists_now); | 1191 bool exists_now); |
| 1086 | 1192 |
| 1087 // Called only by our NetworkChangeNotifier. | 1193 // Called only by our NetworkChangeNotifier. |
| 1088 virtual void OnIPAddressChanged(); | 1194 virtual void OnIPAddressChanged(); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1185 return true; | 1291 return true; |
| 1186 if (a.ref(syncable::PARENT_ID) != b.Get(syncable::PARENT_ID)) | 1292 if (a.ref(syncable::PARENT_ID) != b.Get(syncable::PARENT_ID)) |
| 1187 return true; | 1293 return true; |
| 1188 return false; | 1294 return false; |
| 1189 } | 1295 } |
| 1190 | 1296 |
| 1191 // Determine if any of the fields made visible to clients of the Sync API | 1297 // Determine if any of the fields made visible to clients of the Sync API |
| 1192 // differ between the versions of an entry stored in |a| and |b|. A return | 1298 // differ between the versions of an entry stored in |a| and |b|. A return |
| 1193 // value of false means that it should be OK to ignore this change. | 1299 // value of false means that it should be OK to ignore this change. |
| 1194 static bool VisiblePropertiesDiffer(const syncable::EntryKernel& a, | 1300 static bool VisiblePropertiesDiffer(const syncable::EntryKernel& a, |
| 1195 const syncable::Entry& b) { | 1301 const syncable::Entry& b, |
| 1302 Cryptographer* cryptographer) { | |
| 1196 syncable::ModelType model_type = b.GetModelType(); | 1303 syncable::ModelType model_type = b.GetModelType(); |
| 1197 // Suppress updates to items that aren't tracked by any browser model. | 1304 // Suppress updates to items that aren't tracked by any browser model. |
| 1198 if (model_type == syncable::UNSPECIFIED || | 1305 if (model_type == syncable::UNSPECIFIED || |
| 1199 model_type == syncable::TOP_LEVEL_FOLDER) { | 1306 model_type == syncable::TOP_LEVEL_FOLDER) { |
| 1200 return false; | 1307 return false; |
| 1201 } | 1308 } |
| 1202 if (a.ref(syncable::NON_UNIQUE_NAME) != b.Get(syncable::NON_UNIQUE_NAME)) | 1309 if (a.ref(syncable::NON_UNIQUE_NAME) != b.Get(syncable::NON_UNIQUE_NAME)) |
| 1203 return true; | 1310 return true; |
| 1204 if (a.ref(syncable::IS_DIR) != b.Get(syncable::IS_DIR)) | 1311 if (a.ref(syncable::IS_DIR) != b.Get(syncable::IS_DIR)) |
| 1205 return true; | 1312 return true; |
| 1206 if (a.ref(SPECIFICS).SerializeAsString() != | 1313 // Check if data has changed (account for encryption). |
| 1207 b.Get(SPECIFICS).SerializeAsString()) { | 1314 std::string a_str, b_str; |
| 1315 if (a.ref(SPECIFICS).has_encrypted()) { | |
| 1316 const sync_pb::EncryptedData& encrypted = a.ref(SPECIFICS).encrypted(); | |
| 1317 a_str = cryptographer->DecryptToString(encrypted); | |
| 1318 } else { | |
| 1319 a_str = a.ref(SPECIFICS).SerializeAsString(); | |
| 1320 } | |
| 1321 if (b.Get(SPECIFICS).has_encrypted()) { | |
| 1322 const sync_pb::EncryptedData& encrypted = b.Get(SPECIFICS).encrypted(); | |
| 1323 b_str = cryptographer->DecryptToString(encrypted); | |
| 1324 } else { | |
| 1325 b_str = b.Get(SPECIFICS).SerializeAsString(); | |
| 1326 } | |
| 1327 if (a_str != b_str) { | |
| 1208 return true; | 1328 return true; |
| 1209 } | 1329 } |
| 1210 if (VisiblePositionsDiffer(a, b)) | 1330 if (VisiblePositionsDiffer(a, b)) |
| 1211 return true; | 1331 return true; |
| 1212 return false; | 1332 return false; |
| 1213 } | 1333 } |
| 1214 | 1334 |
| 1215 bool ChangeBuffersAreEmpty() { | 1335 bool ChangeBuffersAreEmpty() { |
| 1216 for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) { | 1336 for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) { |
| 1217 if (!change_buffers_[i].IsEmpty()) | 1337 if (!change_buffers_[i].IsEmpty()) |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1388 syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set, | 1508 syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set, |
| 1389 const syncable::AutofillMigrationDebugInfo& info) { | 1509 const syncable::AutofillMigrationDebugInfo& info) { |
| 1390 return data_->SetAutofillMigrationDebugInfo(property_to_set, info); | 1510 return data_->SetAutofillMigrationDebugInfo(property_to_set, info); |
| 1391 } | 1511 } |
| 1392 | 1512 |
| 1393 void SyncManager::SetPassphrase(const std::string& passphrase, | 1513 void SyncManager::SetPassphrase(const std::string& passphrase, |
| 1394 bool is_explicit) { | 1514 bool is_explicit) { |
| 1395 data_->SetPassphrase(passphrase, is_explicit); | 1515 data_->SetPassphrase(passphrase, is_explicit); |
| 1396 } | 1516 } |
| 1397 | 1517 |
| 1518 void SyncManager::EncryptDataTypes( | |
| 1519 const syncable::ModelTypeSet& encrypted_types) { | |
| 1520 data_->EncryptDataTypes(encrypted_types); | |
| 1521 } | |
| 1522 | |
| 1398 bool SyncManager::IsUsingExplicitPassphrase() { | 1523 bool SyncManager::IsUsingExplicitPassphrase() { |
| 1399 return data_ && data_->IsUsingExplicitPassphrase(); | 1524 return data_ && data_->IsUsingExplicitPassphrase(); |
| 1400 } | 1525 } |
| 1401 | 1526 |
| 1402 bool SyncManager::RequestPause() { | 1527 bool SyncManager::RequestPause() { |
| 1403 if (data_->syncer_thread()) | 1528 if (data_->syncer_thread()) |
| 1404 return data_->syncer_thread()->RequestPause(); | 1529 return data_->syncer_thread()->RequestPause(); |
| 1405 return false; | 1530 return false; |
| 1406 } | 1531 } |
| 1407 | 1532 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1493 NOTREACHED(); | 1618 NOTREACHED(); |
| 1494 return; | 1619 return; |
| 1495 } | 1620 } |
| 1496 | 1621 |
| 1497 if (!lookup->initial_sync_ended_for_type(syncable::NIGORI)) | 1622 if (!lookup->initial_sync_ended_for_type(syncable::NIGORI)) |
| 1498 return; | 1623 return; |
| 1499 | 1624 |
| 1500 Cryptographer* cryptographer = share_.dir_manager->cryptographer(); | 1625 Cryptographer* cryptographer = share_.dir_manager->cryptographer(); |
| 1501 cryptographer->Bootstrap(restored_key_for_bootstrapping); | 1626 cryptographer->Bootstrap(restored_key_for_bootstrapping); |
| 1502 | 1627 |
| 1503 ReadTransaction trans(GetUserShare()); | 1628 sync_pb::NigoriSpecifics nigori; |
| 1504 ReadNode node(&trans); | 1629 { |
| 1505 if (!node.InitByTagLookup(kNigoriTag)) { | 1630 ReadTransaction trans(GetUserShare()); |
| 1506 NOTREACHED(); | 1631 ReadNode node(&trans); |
| 1507 return; | 1632 if (!node.InitByTagLookup(kNigoriTag)) { |
| 1633 NOTREACHED(); | |
| 1634 return; | |
| 1635 } | |
| 1636 | |
| 1637 nigori.CopyFrom(node.GetNigoriSpecifics()); | |
| 1638 if (!nigori.encrypted().blob().empty()) { | |
| 1639 if (cryptographer->CanDecrypt(nigori.encrypted())) { | |
| 1640 cryptographer->SetKeys(nigori.encrypted()); | |
| 1641 } else { | |
| 1642 cryptographer->SetPendingKeys(nigori.encrypted()); | |
| 1643 observer_->OnPassphraseRequired(true); | |
| 1644 } | |
| 1645 } | |
| 1508 } | 1646 } |
| 1509 | 1647 |
| 1510 const sync_pb::NigoriSpecifics& nigori = node.GetNigoriSpecifics(); | 1648 // Refresh list of encrypted datatypes. |
| 1511 if (!nigori.encrypted().blob().empty()) { | 1649 syncable::ModelTypeSet encrypted_types = |
| 1512 if (cryptographer->CanDecrypt(nigori.encrypted())) { | 1650 syncable::GetEncryptedDatatypesFromNigori(nigori); |
| 1513 cryptographer->SetKeys(nigori.encrypted()); | 1651 encrypted_types.insert(syncable::PASSWORDS); // Always on. |
| 1514 } else { | 1652 |
| 1515 cryptographer->SetPendingKeys(nigori.encrypted()); | 1653 // Ensure any datatypes that need encryption are encrypted. |
| 1516 observer_->OnPassphraseRequired(true); | 1654 EncryptDataTypes(encrypted_types); |
| 1517 } | |
| 1518 } | |
| 1519 } | 1655 } |
| 1520 | 1656 |
| 1521 void SyncManager::SyncInternal::StartSyncing() { | 1657 void SyncManager::SyncInternal::StartSyncing() { |
| 1522 if (syncer_thread()) // NULL during certain unittests. | 1658 if (syncer_thread()) // NULL during certain unittests. |
| 1523 syncer_thread()->Start(); // Start the syncer thread. This won't actually | 1659 syncer_thread()->Start(); // Start the syncer thread. This won't actually |
| 1524 // result in any syncing until at least the | 1660 // result in any syncing until at least the |
| 1525 // DirectoryManager broadcasts the OPENED event, | 1661 // DirectoryManager broadcasts the OPENED event, |
| 1526 // and a valid server connection is detected. | 1662 // and a valid server connection is detected. |
| 1527 } | 1663 } |
| 1528 | 1664 |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1692 observer_->OnPassphraseRequired(true); | 1828 observer_->OnPassphraseRequired(true); |
| 1693 return; | 1829 return; |
| 1694 } | 1830 } |
| 1695 | 1831 |
| 1696 // TODO(tim): If this is the first time the user has entered a passphrase | 1832 // TODO(tim): If this is the first time the user has entered a passphrase |
| 1697 // since the protocol changed to store passphrase preferences in the cloud, | 1833 // since the protocol changed to store passphrase preferences in the cloud, |
| 1698 // make sure we update this preference. See bug 62103. | 1834 // make sure we update this preference. See bug 62103. |
| 1699 if (is_explicit) | 1835 if (is_explicit) |
| 1700 SetUsingExplicitPassphrasePrefForMigration(); | 1836 SetUsingExplicitPassphrasePrefForMigration(); |
| 1701 | 1837 |
| 1702 // Nudge the syncer so that passwords updates that were waiting for this | 1838 // Nudge the syncer so that encrypted datatype updates that were waiting for |
| 1703 // passphrase get applied as soon as possible. | 1839 // this passphrase get applied as soon as possible. |
| 1704 sync_manager_->RequestNudge(); | 1840 sync_manager_->RequestNudge(); |
| 1705 } else { | 1841 } else { |
| 1706 WriteTransaction trans(GetUserShare()); | 1842 WriteTransaction trans(GetUserShare()); |
| 1707 WriteNode node(&trans); | 1843 WriteNode node(&trans); |
| 1708 if (!node.InitByTagLookup(kNigoriTag)) { | 1844 if (!node.InitByTagLookup(kNigoriTag)) { |
| 1709 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. | 1845 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. |
| 1710 NOTREACHED(); | 1846 NOTREACHED(); |
| 1711 return; | 1847 return; |
| 1712 } | 1848 } |
| 1713 | 1849 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 1739 ReadNode node(&trans); | 1875 ReadNode node(&trans); |
| 1740 if (!node.InitByTagLookup(kNigoriTag)) { | 1876 if (!node.InitByTagLookup(kNigoriTag)) { |
| 1741 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. | 1877 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS. |
| 1742 NOTREACHED(); | 1878 NOTREACHED(); |
| 1743 return false; | 1879 return false; |
| 1744 } | 1880 } |
| 1745 | 1881 |
| 1746 return node.GetNigoriSpecifics().using_explicit_passphrase(); | 1882 return node.GetNigoriSpecifics().using_explicit_passphrase(); |
| 1747 } | 1883 } |
| 1748 | 1884 |
| 1885 void SyncManager::SyncInternal::EncryptDataTypes( | |
| 1886 const syncable::ModelTypeSet& encrypted_types) { | |
| 1887 // Verify the encrypted types are all enabled. | |
| 1888 ModelSafeRoutingInfo routes; | |
| 1889 registrar_->GetModelSafeRoutingInfo(&routes); | |
| 1890 size_t count = 0; | |
| 1891 for (ModelSafeRoutingInfo::iterator iter = routes.begin(); | |
| 1892 iter != routes.end(); ++iter, ++count) { | |
| 1893 if (iter->first == syncable::PASSWORDS && | |
| 1894 encrypted_types.count(syncable::PASSWORDS) == 0) { | |
| 1895 LOG(ERROR) << "Attempted to set PASSWORDS as unencrypted."; | |
| 1896 NOTREACHED(); | |
| 1897 return; | |
| 1898 } | |
| 1899 } | |
| 1900 WriteTransaction trans(GetUserShare()); | |
| 1901 WriteNode node(&trans); | |
| 1902 if (!node.InitByTagLookup(kNigoriTag)) { | |
| 1903 LOG(ERROR) << "Unable to set encrypted datatypes because Nigori node not " | |
| 1904 "found."; | |
| 1905 NOTREACHED(); | |
| 1906 return; | |
| 1907 } | |
| 1908 | |
| 1909 // Update the Nigori node set of encrypted datatypes so other machines notice. | |
| 1910 sync_pb::NigoriSpecifics nigori = node.GetNigoriSpecifics(); | |
| 1911 syncable::FillNigoriEncryptedTypes(encrypted_types, &nigori); | |
| 1912 node.SetNigoriSpecifics(nigori); | |
| 1913 | |
| 1914 // Update syncable::directory's cache of encrypted datatypes. | |
| 1915 trans.GetWrappedTrans()->SetEncryptedDataTypes(encrypted_types); | |
| 1916 | |
| 1917 // TODO(zea): only reencrypt this datatype? ReEncrypting everything is a | |
| 1918 // safer approach, and should not impact anything that is already encrypted | |
| 1919 // (redundant changes are ignored). | |
| 1920 ReEncryptEverything(&trans); | |
| 1921 return; | |
| 1922 } | |
| 1923 | |
| 1924 // TODO(zea): unit tests. | |
| 1749 void SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) { | 1925 void SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) { |
| 1750 // TODO(tim): bug 59242. We shouldn't lookup by data type and instead use | 1926 syncable::ModelTypeSet encrypted_types = trans->GetWrappedTrans()-> |
| 1751 // a protocol flag or existence of an EncryptedData message, but for now, | 1927 GetEncryptedDatatypes(); |
| 1752 // encryption is on if-and-only-if the type is passwords, and we haven't | 1928 std::string tag; |
| 1753 // ironed out the protocol for generic encryption. | 1929 for (syncable::ModelTypeSet::iterator iter = encrypted_types.begin(); |
| 1754 static const char* passwords_tag = "google_chrome_passwords"; | 1930 iter != encrypted_types.end(); ++iter) { |
| 1931 if (*iter == syncable::PASSWORDS) | |
| 1932 continue; // Has special implementation below. | |
| 1933 ReadNode type_root(trans); | |
| 1934 tag = syncable::ModelTypeToRootTag(*iter); | |
| 1935 if (!type_root.InitByTagLookup(tag)) { | |
| 1936 NOTREACHED(); | |
| 1937 return; | |
| 1938 } | |
| 1939 | |
| 1940 // Iterate through all children of this datatype. | |
| 1941 std::queue<int64> to_visit; | |
| 1942 int64 child_id = type_root.GetFirstChildId(); | |
| 1943 to_visit.push(child_id); | |
| 1944 while (!to_visit.empty()) { | |
| 1945 child_id = to_visit.front(); | |
| 1946 to_visit.pop(); | |
| 1947 if (child_id == kInvalidId) | |
| 1948 continue; | |
| 1949 | |
| 1950 WriteNode child(trans); | |
| 1951 if (!child.InitByIdLookup(child_id)) { | |
| 1952 NOTREACHED(); | |
| 1953 return; | |
| 1954 } | |
| 1955 if (child.GetIsFolder()) { | |
| 1956 to_visit.push(child.GetFirstChildId()); | |
| 1957 } else { | |
| 1958 // Rewrite the specifics of the node with encrypted data if necessary. | |
| 1959 child.ResetFromSpecifics(); | |
| 1960 } | |
| 1961 to_visit.push(child.GetSuccessorId()); | |
| 1962 } | |
| 1963 } | |
| 1964 | |
| 1755 ReadNode passwords_root(trans); | 1965 ReadNode passwords_root(trans); |
| 1966 std::string passwords_tag = syncable::ModelTypeToRootTag(syncable::PASSWORDS); | |
| 1756 if (!passwords_root.InitByTagLookup(passwords_tag)) { | 1967 if (!passwords_root.InitByTagLookup(passwords_tag)) { |
| 1757 LOG(WARNING) << "No passwords to reencrypt."; | 1968 LOG(WARNING) << "No passwords to reencrypt."; |
| 1758 return; | 1969 return; |
| 1759 } | 1970 } |
| 1760 | 1971 |
| 1761 int64 child_id = passwords_root.GetFirstChildId(); | 1972 int64 child_id = passwords_root.GetFirstChildId(); |
| 1762 while (child_id != kInvalidId) { | 1973 while (child_id != kInvalidId) { |
| 1763 WriteNode child(trans); | 1974 WriteNode child(trans); |
| 1764 if (!child.InitByIdLookup(child_id)) { | 1975 if (!child.InitByIdLookup(child_id)) { |
| 1765 NOTREACHED(); | 1976 NOTREACHED(); |
| 1766 return; | 1977 return; |
| 1767 } | 1978 } |
| 1768 child.SetPasswordSpecifics(child.GetPasswordSpecifics()); | 1979 child.SetPasswordSpecifics(child.GetPasswordSpecifics()); |
| 1769 child_id = child.GetSuccessorId(); | 1980 child_id = child.GetSuccessorId(); |
| 1770 } | 1981 } |
| 1982 observer_->OnEncryptionComplete(encrypted_types); | |
| 1771 } | 1983 } |
| 1772 | 1984 |
| 1773 SyncManager::~SyncManager() { | 1985 SyncManager::~SyncManager() { |
| 1774 delete data_; | 1986 delete data_; |
| 1775 } | 1987 } |
| 1776 | 1988 |
| 1777 void SyncManager::SetObserver(Observer* observer) { | 1989 void SyncManager::SetObserver(Observer* observer) { |
| 1778 data_->set_observer(observer); | 1990 data_->set_observer(observer); |
| 1779 } | 1991 } |
| 1780 | 1992 |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1996 nudge_delay, | 2208 nudge_delay, |
| 1997 SyncerThread::kLocal, | 2209 SyncerThread::kLocal, |
| 1998 model_types); | 2210 model_types); |
| 1999 } | 2211 } |
| 2000 } | 2212 } |
| 2001 | 2213 |
| 2002 void SyncManager::SyncInternal::SetExtraChangeRecordData(int64 id, | 2214 void SyncManager::SyncInternal::SetExtraChangeRecordData(int64 id, |
| 2003 syncable::ModelType type, ChangeReorderBuffer* buffer, | 2215 syncable::ModelType type, ChangeReorderBuffer* buffer, |
| 2004 Cryptographer* cryptographer, const syncable::EntryKernel& original, | 2216 Cryptographer* cryptographer, const syncable::EntryKernel& original, |
| 2005 bool existed_before, bool exists_now) { | 2217 bool existed_before, bool exists_now) { |
| 2006 // If this is a deletion, attach the entity specifics as extra data | 2218 // If this is a deletion and the datatype was encrypted, we need to decrypt it |
| 2007 // so that the delete can be processed. | 2219 // and attach it to the buffer. |
| 2008 if (!exists_now && existed_before) { | 2220 if (!exists_now && existed_before) { |
| 2009 buffer->SetSpecificsForId(id, original.ref(SPECIFICS)); | 2221 sync_pb::EntitySpecifics original_specifics(original.ref(SPECIFICS)); |
| 2010 if (type == syncable::PASSWORDS) { | 2222 if (type == syncable::PASSWORDS) { |
| 2011 // Need to dig a bit deeper as passwords are encrypted. | 2223 // Passwords must use their own legacy ExtraPasswordChangeRecordData. |
| 2012 scoped_ptr<sync_pb::PasswordSpecificsData> data( | 2224 scoped_ptr<sync_pb::PasswordSpecificsData> data( |
| 2013 DecryptPasswordSpecifics(original.ref(SPECIFICS), cryptographer)); | 2225 DecryptPasswordSpecifics(original_specifics, cryptographer)); |
| 2014 if (!data.get()) { | 2226 if (!data.get()) { |
| 2015 NOTREACHED(); | 2227 NOTREACHED(); |
| 2016 return; | 2228 return; |
| 2017 } | 2229 } |
| 2018 buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data)); | 2230 buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data)); |
| 2231 } else if (original_specifics.has_encrypted()) { | |
| 2232 // All other datatypes can just create a new unencrypted specifics and | |
| 2233 // attach it. | |
| 2234 const sync_pb::EncryptedData& encrypted = original_specifics.encrypted(); | |
| 2235 if (!cryptographer->Decrypt(encrypted, &original_specifics)) { | |
| 2236 NOTREACHED(); | |
| 2237 return; | |
| 2238 } | |
| 2019 } | 2239 } |
| 2240 buffer->SetSpecificsForId(id, original_specifics); | |
| 2020 } | 2241 } |
| 2021 } | 2242 } |
| 2022 | 2243 |
| 2023 void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer( | 2244 void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer( |
| 2024 const syncable::DirectoryChangeEvent& event) { | 2245 const syncable::DirectoryChangeEvent& event) { |
| 2025 // We only expect one notification per sync step, so change_buffers_ should | 2246 // We only expect one notification per sync step, so change_buffers_ should |
| 2026 // contain no pending entries. | 2247 // contain no pending entries. |
| 2027 DCHECK_EQ(event.todo, syncable::DirectoryChangeEvent::CALCULATE_CHANGES); | 2248 DCHECK_EQ(event.todo, syncable::DirectoryChangeEvent::CALCULATE_CHANGES); |
| 2028 DCHECK(event.writer == syncable::SYNCER || | 2249 DCHECK(event.writer == syncable::SYNCER || |
| 2029 event.writer == syncable::UNITTEST); | 2250 event.writer == syncable::UNITTEST); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 2040 | 2261 |
| 2041 // Omit items that aren't associated with a model. | 2262 // Omit items that aren't associated with a model. |
| 2042 syncable::ModelType type = e.GetModelType(); | 2263 syncable::ModelType type = e.GetModelType(); |
| 2043 if (type == syncable::TOP_LEVEL_FOLDER || type == syncable::UNSPECIFIED) | 2264 if (type == syncable::TOP_LEVEL_FOLDER || type == syncable::UNSPECIFIED) |
| 2044 continue; | 2265 continue; |
| 2045 | 2266 |
| 2046 if (exists_now && !existed_before) | 2267 if (exists_now && !existed_before) |
| 2047 change_buffers_[type].PushAddedItem(id); | 2268 change_buffers_[type].PushAddedItem(id); |
| 2048 else if (!exists_now && existed_before) | 2269 else if (!exists_now && existed_before) |
| 2049 change_buffers_[type].PushDeletedItem(id); | 2270 change_buffers_[type].PushDeletedItem(id); |
| 2050 else if (exists_now && existed_before && VisiblePropertiesDiffer(*i, e)) | 2271 else if (exists_now && existed_before && |
| 2272 VisiblePropertiesDiffer(*i, e, dir_manager()->cryptographer())) { | |
| 2051 change_buffers_[type].PushUpdatedItem(id, VisiblePositionsDiffer(*i, e)); | 2273 change_buffers_[type].PushUpdatedItem(id, VisiblePositionsDiffer(*i, e)); |
| 2274 } | |
| 2052 | 2275 |
| 2053 SetExtraChangeRecordData(id, type, &change_buffers_[type], | 2276 SetExtraChangeRecordData(id, type, &change_buffers_[type], |
| 2054 dir_manager()->cryptographer(), *i, | 2277 dir_manager()->cryptographer(), *i, |
| 2055 existed_before, exists_now); | 2278 existed_before, exists_now); |
| 2056 } | 2279 } |
| 2057 } | 2280 } |
| 2058 | 2281 |
| 2059 SyncManager::Status SyncManager::SyncInternal::GetStatus() { | 2282 SyncManager::Status SyncManager::SyncInternal::GetStatus() { |
| 2060 return allstatus_.status(); | 2283 return allstatus_.status(); |
| 2061 } | 2284 } |
| 2062 | 2285 |
| 2063 void SyncManager::SyncInternal::OnSyncEngineEvent( | 2286 void SyncManager::SyncInternal::OnSyncEngineEvent( |
| 2064 const SyncEngineEvent& event) { | 2287 const SyncEngineEvent& event) { |
| 2065 if (!observer_) | 2288 if (!observer_) |
| 2066 return; | 2289 return; |
| 2067 | 2290 |
| 2068 // Only send an event if this is due to a cycle ending and this cycle | 2291 // Only send an event if this is due to a cycle ending and this cycle |
| 2069 // concludes a canonical "sync" process; that is, based on what is known | 2292 // concludes a canonical "sync" process; that is, based on what is known |
| 2070 // locally we are "all happy" and up-to-date. There may be new changes on | 2293 // locally we are "all happy" and up-to-date. There may be new changes on |
| 2071 // the server, but we'll get them on a subsequent sync. | 2294 // the server, but we'll get them on a subsequent sync. |
| 2072 // | 2295 // |
| 2073 // Notifications are sent at the end of every sync cycle, regardless of | 2296 // Notifications are sent at the end of every sync cycle, regardless of |
| 2074 // whether we should sync again. | 2297 // whether we should sync again. |
| 2075 if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) { | 2298 if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) { |
| 2076 ModelSafeRoutingInfo enabled_types; | 2299 ModelSafeRoutingInfo enabled_types; |
| 2077 registrar_->GetModelSafeRoutingInfo(&enabled_types); | 2300 registrar_->GetModelSafeRoutingInfo(&enabled_types); |
| 2078 if (enabled_types.count(syncable::PASSWORDS) > 0) { | 2301 { |
| 2079 Cryptographer* cryptographer = | 2302 // Check to see if we need to notify the frontend that we have newly |
| 2080 GetUserShare()->dir_manager->cryptographer(); | 2303 // encrypted types or that we require a passphrase. |
| 2081 if (!cryptographer->is_ready() && !cryptographer->has_pending_keys()) { | 2304 sync_api::ReadTransaction trans(GetUserShare()); |
| 2082 sync_api::ReadTransaction trans(GetUserShare()); | 2305 sync_api::ReadNode node(&trans); |
| 2083 sync_api::ReadNode node(&trans); | 2306 if (!node.InitByTagLookup(kNigoriTag)) { |
| 2084 if (!node.InitByTagLookup(kNigoriTag)) { | 2307 DCHECK(!event.snapshot->is_share_usable); |
| 2085 DCHECK(!event.snapshot->is_share_usable); | 2308 return; |
| 2086 return; | 2309 } |
| 2310 const sync_pb::NigoriSpecifics& nigori = node.GetNigoriSpecifics(); | |
| 2311 syncable::ModelTypeSet encrypted_types = | |
| 2312 syncable::GetEncryptedDatatypesFromNigori(nigori); | |
| 2313 // If this is a first time sync with encryption, it's possible Passwords | |
| 2314 // hasn't been added to the encryption types list. | |
| 2315 if (enabled_types.count(syncable::PASSWORDS) > 0) | |
| 2316 encrypted_types.insert(syncable::PASSWORDS); | |
| 2317 if (encrypted_types.size() > 0) { | |
| 2318 syncable::ModelTypeSet old_types = | |
| 2319 trans.GetWrappedTrans()->GetEncryptedDatatypes(); | |
| 2320 if (encrypted_types != old_types) { | |
| 2321 if (!includes(encrypted_types.begin(), encrypted_types.end(), | |
| 2322 old_types.begin(), old_types.end())) { | |
| 2323 // The set of encrypted datatypes should only ever increase. | |
| 2324 NOTREACHED(); | |
| 2325 encrypted_types = old_types; | |
| 2326 } else { | |
| 2327 // We have some newly encrypted types. Notify the frontend. | |
| 2328 trans.GetWrappedTrans()->SetEncryptedDataTypes(encrypted_types); | |
| 2329 observer_->OnEncryptionComplete(encrypted_types); | |
| 2330 } | |
| 2087 } | 2331 } |
| 2088 const sync_pb::NigoriSpecifics& nigori = node.GetNigoriSpecifics(); | 2332 |
| 2089 if (!nigori.encrypted().blob().empty()) { | 2333 Cryptographer* cryptographer = |
| 2090 DCHECK(!cryptographer->CanDecrypt(nigori.encrypted())); | 2334 GetUserShare()->dir_manager->cryptographer(); |
| 2091 cryptographer->SetPendingKeys(nigori.encrypted()); | 2335 if (!cryptographer->is_ready() && !cryptographer->has_pending_keys()) { |
| 2336 if (!nigori.encrypted().blob().empty()) { | |
| 2337 DCHECK(!cryptographer->CanDecrypt(nigori.encrypted())); | |
| 2338 cryptographer->SetPendingKeys(nigori.encrypted()); | |
| 2339 } | |
| 2092 } | 2340 } |
| 2093 } | |
| 2094 | 2341 |
| 2095 // If we've completed a sync cycle and the cryptographer isn't ready yet, | 2342 // If we've completed a sync cycle and the cryptographer isn't ready |
| 2096 // prompt the user for a passphrase. | 2343 // yet, prompt the user for a passphrase. |
| 2097 if (cryptographer->has_pending_keys()) { | 2344 if (cryptographer->has_pending_keys()) { |
| 2098 observer_->OnPassphraseRequired(true); | 2345 observer_->OnPassphraseRequired(true); |
| 2099 } else if (!cryptographer->is_ready()) { | 2346 } else if (!cryptographer->is_ready()) { |
| 2100 observer_->OnPassphraseRequired(false); | 2347 observer_->OnPassphraseRequired(false); |
| 2348 } | |
| 2101 } | 2349 } |
| 2102 } | 2350 } |
| 2103 | 2351 |
| 2104 if (!initialized()) | 2352 if (!initialized()) |
| 2105 return; | 2353 return; |
| 2106 | 2354 |
| 2107 if (!event.snapshot->has_more_to_sync) { | 2355 if (!event.snapshot->has_more_to_sync) { |
| 2108 observer_->OnSyncCycleCompleted(event.snapshot); | 2356 observer_->OnSyncCycleCompleted(event.snapshot); |
| 2109 } | 2357 } |
| 2110 | 2358 |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2315 DCHECK(data_->initialized()) << "GetUserShare requires initialization!"; | 2563 DCHECK(data_->initialized()) << "GetUserShare requires initialization!"; |
| 2316 return data_->GetUserShare(); | 2564 return data_->GetUserShare(); |
| 2317 } | 2565 } |
| 2318 | 2566 |
| 2319 bool SyncManager::HasUnsyncedItems() const { | 2567 bool SyncManager::HasUnsyncedItems() const { |
| 2320 sync_api::ReadTransaction trans(GetUserShare()); | 2568 sync_api::ReadTransaction trans(GetUserShare()); |
| 2321 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0); | 2569 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0); |
| 2322 } | 2570 } |
| 2323 | 2571 |
| 2324 } // namespace sync_api | 2572 } // namespace sync_api |
| OLD | NEW |