Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(927)

Side by Side Diff: chrome/browser/sync/engine/syncapi.cc

Issue 6465005: [Sync] Initial support for encrypting any datatype (no UI hookup yet). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Self review Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698