Index: chrome/browser/sync/glue/password_change_processor.cc |
diff --git a/chrome/browser/sync/glue/password_change_processor.cc b/chrome/browser/sync/glue/password_change_processor.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..57a377de88c4739705492d06c4aa2f6b00d57d96 |
--- /dev/null |
+++ b/chrome/browser/sync/glue/password_change_processor.cc |
@@ -0,0 +1,213 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/sync/glue/password_change_processor.h" |
+ |
+#include "base/string_util.h" |
+#include "base/utf_string_conversions.h" |
+#include "chrome/browser/password_manager/password_store.h" |
+#include "chrome/browser/password_manager/password_store_change.h" |
+#include "chrome/browser/profile.h" |
+#include "chrome/browser/sync/glue/password_model_associator.h" |
+#include "chrome/browser/sync/profile_sync_service.h" |
+#include "chrome/browser/sync/protocol/password_specifics.pb.h" |
+#include "chrome/common/notification_service.h" |
+#include "chrome/common/notification_type.h" |
+#include "webkit/glue/password_form.h" |
+ |
+namespace browser_sync { |
+ |
+PasswordChangeProcessor::PasswordChangeProcessor( |
+ PasswordModelAssociator* model_associator, |
+ PasswordStore* password_store, |
+ UnrecoverableErrorHandler* error_handler) |
+ : ChangeProcessor(error_handler), |
+ model_associator_(model_associator), |
+ password_store_(password_store), |
+ observing_(false), |
+ expected_loop_(MessageLoop::current()) { |
+ DCHECK(model_associator); |
+ DCHECK(error_handler); |
+#if defined(OS_MACOSX) |
+ DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::UI)); |
+#else |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
+#endif |
+ StartObserving(); |
+} |
+ |
+PasswordChangeProcessor::~PasswordChangeProcessor() { |
+ DCHECK(expected_loop_ == MessageLoop::current()); |
+} |
+ |
+void PasswordChangeProcessor::Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details) { |
+ DCHECK(expected_loop_ == MessageLoop::current()); |
+ DCHECK(NotificationType::LOGINS_CHANGED == type); |
+ if (!observing_) |
+ return; |
+ |
+ DCHECK(running()); |
+ |
+ sync_api::WriteTransaction trans(share_handle()); |
+ |
+ sync_api::ReadNode password_root(&trans); |
+ if (!password_root.InitByTagLookup(kPasswordTag)) { |
+ error_handler()->OnUnrecoverableError(); |
+ LOG(ERROR) << "Server did not create the top-level password node. " |
+ << "We might be running against an out-of-date server."; |
+ return; |
+ } |
+ |
+ PasswordStoreChangeList* changes = |
+ Details<PasswordStoreChangeList>(details).ptr(); |
+ for (PasswordStoreChangeList::iterator change = changes->begin(); |
+ change != changes->end(); ++change) { |
+ std::string tag = PasswordModelAssociator::MakeTag(change->form()); |
+ switch (change->type()) { |
+ case PasswordStoreChange::ADD: { |
+ sync_api::WriteNode sync_node(&trans); |
+ if (!sync_node.InitUniqueByCreation(syncable::PASSWORD, |
+ password_root, tag)) { |
+ LOG(ERROR) << "Failed to create password sync node."; |
+ error_handler()->OnUnrecoverableError(); |
+ return; |
+ } |
+ |
+ PasswordModelAssociator::WriteToSyncNode(change->form(), &sync_node); |
+ model_associator_->Associate(&tag, sync_node.GetId()); |
+ break; |
+ } |
+ case PasswordStoreChange::UPDATE: { |
+ sync_api::WriteNode sync_node(&trans); |
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(tag); |
+ if (sync_api::kInvalidId == sync_id) { |
+ LOG(ERROR) << "Unexpected notification for: " << tag; |
+ error_handler()->OnUnrecoverableError(); |
+ return; |
+ } else { |
+ if (!sync_node.InitByIdLookup(sync_id)) { |
+ LOG(ERROR) << "Password node lookup failed."; |
+ error_handler()->OnUnrecoverableError(); |
+ return; |
+ } |
+ } |
+ |
+ PasswordModelAssociator::WriteToSyncNode(change->form(), &sync_node); |
+ break; |
+ } |
+ case PasswordStoreChange::REMOVE: { |
+ sync_api::WriteNode sync_node(&trans); |
+ int64 sync_id = model_associator_->GetSyncIdFromChromeId(tag); |
+ if (sync_api::kInvalidId == sync_id) { |
+ LOG(ERROR) << "Unexpected notification"; |
+ error_handler()->OnUnrecoverableError(); |
+ return; |
+ } else { |
+ if (!sync_node.InitByIdLookup(sync_id)) { |
+ LOG(ERROR) << "Password node lookup failed."; |
+ error_handler()->OnUnrecoverableError(); |
+ return; |
+ } |
+ model_associator_->Disassociate(sync_node.GetId()); |
+ sync_node.Remove(); |
+ } |
+ break; |
+ } |
+ } |
+ } |
+} |
+ |
+void PasswordChangeProcessor::ApplyChangesFromSyncModel( |
+ const sync_api::BaseTransaction* trans, |
+ const sync_api::SyncManager::ChangeRecord* changes, |
+ int change_count) { |
+ DCHECK(expected_loop_ == MessageLoop::current()); |
+ if (!running()) |
+ return; |
+ StopObserving(); |
+ |
+ sync_api::ReadNode password_root(trans); |
+ if (!password_root.InitByTagLookup(kPasswordTag)) { |
+ LOG(ERROR) << "Password root node lookup failed."; |
+ error_handler()->OnUnrecoverableError(); |
+ return; |
+ } |
+ |
+ PasswordModelAssociator::PasswordVector new_passwords; |
+ PasswordModelAssociator::PasswordVector updated_passwords; |
+ PasswordModelAssociator::PasswordVector deleted_passwords; |
+ |
+ for (int i = 0; i < change_count; ++i) { |
+ |
+ sync_api::ReadNode sync_node(trans); |
+ if (!sync_node.InitByIdLookup(changes[i].id)) { |
+ LOG(ERROR) << "Password node lookup failed."; |
+ error_handler()->OnUnrecoverableError(); |
+ return; |
+ } |
+ |
+ // Check that the changed node is a child of the passwords folder. |
+ DCHECK(password_root.GetId() == sync_node.GetParentId()); |
+ DCHECK(syncable::PASSWORD == sync_node.GetModelType()); |
+ |
+ sync_pb::PasswordSpecificsData password_data; |
+ if (!sync_node.GetPasswordSpecifics(&password_data)) { |
+ LOG(ERROR) << "Could not read password specifics"; |
+ error_handler()->OnUnrecoverableError(); |
+ return; |
+ } |
+ webkit_glue::PasswordForm password; |
+ PasswordModelAssociator::CopyPassword(password_data, |
+ &password); |
+ |
+ if (sync_api::SyncManager::ChangeRecord::ACTION_ADD == changes[i].action) { |
+ new_passwords.push_back(password); |
+ } else if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == |
+ changes[i].action) { |
+ deleted_passwords.push_back(password); |
+ } else { |
+ DCHECK(sync_api::SyncManager::ChangeRecord::ACTION_UPDATE == |
+ changes[i].action); |
+ updated_passwords.push_back(password); |
+ } |
+ } |
+ if (!model_associator_->WriteToPasswordStore(&new_passwords, |
+ &updated_passwords, |
+ &deleted_passwords)) { |
+ LOG(ERROR) << "Error writing passwords"; |
+ error_handler()->OnUnrecoverableError(); |
+ return; |
+ } |
+ |
+ StartObserving(); |
+} |
+ |
+void PasswordChangeProcessor::StartImpl(Profile* profile) { |
+ DCHECK(expected_loop_ == MessageLoop::current()); |
+ observing_ = true; |
+} |
+ |
+void PasswordChangeProcessor::StopImpl() { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
+ observing_ = false; |
+} |
+ |
+ |
+void PasswordChangeProcessor::StartObserving() { |
+ DCHECK(expected_loop_ == MessageLoop::current()); |
+ notification_registrar_.Add(this, |
+ NotificationType::LOGINS_CHANGED, |
+ NotificationService::AllSources()); |
+} |
+ |
+void PasswordChangeProcessor::StopObserving() { |
+ DCHECK(expected_loop_ == MessageLoop::current()); |
+ notification_registrar_.Remove(this, |
+ NotificationType::LOGINS_CHANGED, |
+ NotificationService::AllSources()); |
+} |
+ |
+} // namespace browser_sync |