diff options
-rw-r--r-- | chrome/browser/password_manager/password_store_mac.cc | 131 | ||||
-rw-r--r-- | chrome/browser/password_manager/password_store_mac.h | 9 | ||||
-rw-r--r-- | chrome/common/notification_type.h | 8 |
3 files changed, 113 insertions, 35 deletions
diff --git a/chrome/browser/password_manager/password_store_mac.cc b/chrome/browser/password_manager/password_store_mac.cc index f35d5ba..de8e5d5 100644 --- a/chrome/browser/password_manager/password_store_mac.cc +++ b/chrome/browser/password_manager/password_store_mac.cc @@ -13,9 +13,11 @@ #include "base/mac_util.h" #include "base/stl_util-inl.h" #include "base/string_util.h" +#include "base/task.h" #include "base/utf_string_conversions.h" #include "chrome/browser/keychain_mac.h" #include "chrome/browser/password_manager/login_database.h" +#include "chrome/browser/password_manager/password_store_change.h" using webkit_glue::PasswordForm; @@ -716,6 +718,10 @@ PasswordStoreMac::PasswordStoreMac(MacKeychain* keychain, } PasswordStoreMac::~PasswordStoreMac() { + if (thread_.get()) { + thread_->message_loop()->DeleteSoon(FROM_HERE, + notification_service_.release()); + } } bool PasswordStoreMac::Init() { @@ -725,6 +731,8 @@ bool PasswordStoreMac::Init() { thread_.reset(NULL); return false; } + ScheduleTask(NewRunnableMethod(this, + &PasswordStoreMac::CreateNotificationService)); return PasswordStore::Init(); } @@ -736,7 +744,14 @@ void PasswordStoreMac::ScheduleTask(Task* task) { void PasswordStoreMac::AddLoginImpl(const PasswordForm& form) { if (AddToKeychainIfNecessary(form)) { - login_metadata_db_->AddLogin(form); + if (login_metadata_db_->AddLogin(form)) { + PasswordStoreChangeList changes; + changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, form)); + NotificationService::current()->Notify( + NotificationType::LOGINS_CHANGED, + NotificationService::AllSources(), + Details<PasswordStoreChangeList>(&changes)); + } } } @@ -745,51 +760,93 @@ void PasswordStoreMac::UpdateLoginImpl(const PasswordForm& form) { // isn't, which is the behavior we want, so there's no separate update call. if (AddToKeychainIfNecessary(form)) { int update_count = 0; - login_metadata_db_->UpdateLogin(form, &update_count); - // Update will catch any database entries that we already had, but we could - // also be updating a keychain-only form, in which case we need to add. - if (update_count == 0) { - login_metadata_db_->AddLogin(form); + if (login_metadata_db_->UpdateLogin(form, &update_count)) { + // Update will catch any database entries that we already had, but we + // could also be updating a keychain-only form, in which case we need to + // add. + PasswordStoreChangeList changes; + if (update_count == 0) { + if (login_metadata_db_->AddLogin(form)) { + changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, + form)); + } + } else { + changes.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE, + form)); + } + if (!changes.empty()) { + NotificationService::current()->Notify( + NotificationType::LOGINS_CHANGED, + NotificationService::AllSources(), + Details<PasswordStoreChangeList>(&changes)); + } } } } void PasswordStoreMac::RemoveLoginImpl(const PasswordForm& form) { - login_metadata_db_->RemoveLogin(form); - - // See if we own a Keychain item associated with this item. We can do an exact - // search rather than messing around with trying to do fuzzy matching because - // passwords that we created will always have an exact-match database entry. - // (If a user does lose their profile but not their keychain we'll treat the - // entries we find like other imported entries anyway, so it's reasonable to - // handle deletes on them the way we would for an imported item.) - MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get()); - owned_keychain_adapter.SetFindsOnlyOwnedItems(true); - PasswordForm* owned_password_form = - owned_keychain_adapter.PasswordExactlyMatchingForm(form); - if (owned_password_form) { - // If we don't have other forms using it (i.e., a form differing only by - // the names of the form elements), delete the keychain entry. - if (!DatabaseHasFormMatchingKeychainForm(form)) { - owned_keychain_adapter.RemovePassword(form); + if (login_metadata_db_->RemoveLogin(form)) { + // See if we own a Keychain item associated with this item. We can do an + // exact search rather than messing around with trying to do fuzzy matching + // because passwords that we created will always have an exact-match + // database entry. + // (If a user does lose their profile but not their keychain we'll treat the + // entries we find like other imported entries anyway, so it's reasonable to + // handle deletes on them the way we would for an imported item.) + MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get()); + owned_keychain_adapter.SetFindsOnlyOwnedItems(true); + PasswordForm* owned_password_form = + owned_keychain_adapter.PasswordExactlyMatchingForm(form); + if (owned_password_form) { + // If we don't have other forms using it (i.e., a form differing only by + // the names of the form elements), delete the keychain entry. + if (!DatabaseHasFormMatchingKeychainForm(form)) { + owned_keychain_adapter.RemovePassword(form); + } } + + PasswordStoreChangeList changes; + changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form)); + NotificationService::current()->Notify( + NotificationType::LOGINS_CHANGED, + NotificationService::AllSources(), + Details<PasswordStoreChangeList>(&changes)); } } void PasswordStoreMac::RemoveLoginsCreatedBetweenImpl( const base::Time& delete_begin, const base::Time& delete_end) { - login_metadata_db_->RemoveLoginsCreatedBetween(delete_begin, delete_end); - - // We can't delete from the Keychain by date because we may be sharing items - // with database entries that weren't in the delete range. Instead, we find - // all the Keychain items we own but aren't using any more and delete those. - std::vector<PasswordForm*> orphan_keychain_forms = GetUnusedKeychainForms(); - // This is inefficient, since we have to re-look-up each keychain item one at - // a time to delete it even though the search step already had a list of - // Keychain item references. If this turns out to be noticeably slow we'll - // need to rearchitect to allow the search and deletion steps to share. - RemoveKeychainForms(orphan_keychain_forms); - STLDeleteElements(&orphan_keychain_forms); + std::vector<PasswordForm*> forms; + if (login_metadata_db_->GetLoginsCreatedBetween(delete_begin, delete_end, + &forms)) { + if (login_metadata_db_->RemoveLoginsCreatedBetween(delete_begin, + delete_end)) { + // We can't delete from the Keychain by date because we may be sharing + // items with database entries that weren't in the delete range. Instead, + // we find all the Keychain items we own but aren't using any more and + // delete those. + std::vector<PasswordForm*> orphan_keychain_forms = + GetUnusedKeychainForms(); + // This is inefficient, since we have to re-look-up each keychain item + // one at a time to delete it even though the search step already had a + // list of Keychain item references. If this turns out to be noticeably + // slow we'll need to rearchitect to allow the search and deletion steps + // to share. + RemoveKeychainForms(orphan_keychain_forms); + STLDeleteElements(&orphan_keychain_forms); + + PasswordStoreChangeList changes; + for (std::vector<PasswordForm*>::const_iterator it = forms.begin(); + it != forms.end(); ++it) { + changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, + **it)); + } + NotificationService::current()->Notify( + NotificationType::LOGINS_CHANGED, + NotificationService::AllSources(), + Details<PasswordStoreChangeList>(&changes)); + } + } } void PasswordStoreMac::GetLoginsImpl(GetLoginsRequest* request, @@ -906,3 +963,7 @@ void PasswordStoreMac::RemoveKeychainForms( owned_keychain_adapter.RemovePassword(**i); } } + +void PasswordStoreMac::CreateNotificationService() { + notification_service_.reset(new NotificationService); +} diff --git a/chrome/browser/password_manager/password_store_mac.h b/chrome/browser/password_manager/password_store_mac.h index b746c4b..36dc7b4 100644 --- a/chrome/browser/password_manager/password_store_mac.h +++ b/chrome/browser/password_manager/password_store_mac.h @@ -11,6 +11,7 @@ #include "base/thread.h" #include "chrome/browser/password_manager/login_database.h" #include "chrome/browser/password_manager/password_store.h" +#include "chrome/common/notification_service.h" class MacKeychain; @@ -68,12 +69,20 @@ class PasswordStoreMac : public PasswordStore { void RemoveKeychainForms( const std::vector<webkit_glue::PasswordForm*>& forms); + // Allows the creation of |notification_service_| to be scheduled on the right + // thread. + void CreateNotificationService(); + scoped_ptr<MacKeychain> keychain_; scoped_ptr<LoginDatabase> login_metadata_db_; // Thread that the synchronous methods are run on. scoped_ptr<base::Thread> thread_; + // Since we aren't running on a well-known thread but still want to send out + // notifications, we need to run our own service. + scoped_ptr<NotificationService> notification_service_; + DISALLOW_COPY_AND_ASSIGN(PasswordStoreMac); }; diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index 0793b94..eb9c51aa 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -964,6 +964,14 @@ class NotificationType { BOOKMARK_CONTEXT_MENU_SHOWN, #endif + // Password Store ---------------------------------------------------------- + // This notification is sent whenenever login entries stored in the password + // store are changed. The detail of this notification is a list of changes + // represented by a vector of PasswordStoreChange. Each change includes a + // change type (ADD, UPDATE, or REMOVE) as well as the + // |webkit_glue::PasswordForm|s that were affected. + LOGINS_CHANGED, + // Count (must be last) ---------------------------------------------------- // Used to determine the number of notification types. Not valid as // a type parameter when registering for or posting notifications. |