| 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
|
|
|