Index: chrome/browser/password_manager/password_syncable_service.cc |
diff --git a/chrome/browser/password_manager/password_syncable_service.cc b/chrome/browser/password_manager/password_syncable_service.cc |
index 67355e2a9668629a1af517a96612ca85160b350c..e634802261815a2d6aa7ee50ae6e040e97a6d52f 100644 |
--- a/chrome/browser/password_manager/password_syncable_service.cc |
+++ b/chrome/browser/password_manager/password_syncable_service.cc |
@@ -5,40 +5,19 @@ |
#include "chrome/browser/password_manager/password_syncable_service.h" |
#include "base/location.h" |
+#include "base/memory/scoped_ptr.h" |
Nicolas Zea
2013/10/21 23:55:14
already have scoped_ptr in header
lipalani1
2013/10/24 00:13:58
Done.
|
+#include "base/memory/scoped_vector.h" |
+#include "base/metrics/histogram.h" |
+#include "base/stl_util.h" |
#include "base/strings/utf_string_conversions.h" |
#include "chrome/browser/password_manager/password_store.h" |
#include "components/autofill/core/common/password_form.h" |
#include "net/base/escape.h" |
+#include "sync/api/sync_error.h" |
Nicolas Zea
2013/10/21 23:55:14
already have in header
lipalani1
2013/10/24 00:13:58
Done.
|
#include "sync/api/sync_error_factory.h" |
namespace { |
-// Converts the |PasswordSpecifics| obtained from sync to an |
-// object of type |PasswordForm|. |
-void ExtractPasswordFromSpecifics( |
- const sync_pb::PasswordSpecificsData& password, |
- autofill::PasswordForm* new_password) { |
- new_password->scheme = |
- static_cast<autofill::PasswordForm::Scheme>(password.scheme()); |
- new_password->signon_realm = password.signon_realm(); |
- new_password->origin = GURL(password.origin()); |
- new_password->action = GURL(password.action()); |
- new_password->username_element = |
- UTF8ToUTF16(password.username_element()); |
- new_password->password_element = |
- UTF8ToUTF16(password.password_element()); |
- new_password->username_value = |
- UTF8ToUTF16(password.username_value()); |
- new_password->password_value = |
- UTF8ToUTF16(password.password_value()); |
- new_password->ssl_valid = password.ssl_valid(); |
- new_password->preferred = password.preferred(); |
- new_password->date_created = |
- base::Time::FromInternalValue(password.date_created()); |
- new_password->blacklisted_by_user = |
- password.blacklisted(); |
-} |
- |
// Merges the sync password (obtained from the password specifics) and |
// local password and stores the output in the |new_password_form| pointer. |
bool MergeLocalAndSyncPasswords( |
@@ -71,7 +50,9 @@ bool MergeLocalAndSyncPasswords( |
password_form.date_created) { |
*new_password_form = password_form; |
} else { |
- ExtractPasswordFromSpecifics(password_specifics, new_password_form); |
+ PasswordSyncableService::ExtractPasswordFromSpecifics( |
+ password_specifics, |
+ new_password_form); |
} |
return true; |
@@ -86,6 +67,47 @@ PasswordSyncableService::PasswordSyncableService( |
PasswordSyncableService::~PasswordSyncableService() {} |
+void PasswordSyncableService::CreateOrUpdateEntry( |
+ const syncer::SyncData& data, |
+ PasswordEntryMap* loaded_data, |
+ ScopedVector<autofill::PasswordForm>* new_entries, |
+ ScopedVector<autofill::PasswordForm>* updated_entries) { |
+ const sync_pb::EntitySpecifics& specifics = data.GetSpecifics(); |
+ const sync_pb::PasswordSpecificsData& password_specifics( |
+ specifics.password().client_only_encrypted_data()); |
+ |
+ std::string tag = MakeTag(password_specifics); |
+ |
+ // Find if the data from sync is already in password store. |
+ PasswordEntryMap::iterator it = loaded_data->find(tag); |
+ |
+ if (it == loaded_data->end()) { |
+ // The sync data is not in password store, so we need to create it in |
+ // password store. Add the entry to the new_entries list. |
+ autofill::PasswordForm* new_password = new autofill::PasswordForm(); |
+ ExtractPasswordFromSpecifics(password_specifics, new_password); |
+ // The new_password pointer is owned by the caller. |
+ new_entries->push_back(new_password); |
+ } else { |
+ // The entry is in password store. If the entries are not identical the |
+ // entries need to be merged. |
+ scoped_ptr<autofill::PasswordForm> new_password( |
+ new autofill::PasswordForm()); |
+ if (MergeLocalAndSyncPasswords(password_specifics, |
+ **(it->second.second), |
+ new_password.get())) { |
+ **(it->second.second) = *(new_password.get()); |
+ it->second.first = syncer::SyncChange::ACTION_UPDATE; |
+ |
+ updated_entries->push_back(new_password.release()); |
+ } else { |
+ // The entries are identical. Remove it from the |loaded_data| list to |
+ // prevent it from being treated as an unassociated entry. |
+ loaded_data->erase(it); |
+ } |
+ } |
+} |
+ |
syncer::SyncMergeResult |
PasswordSyncableService::MergeDataAndStartSyncing( |
syncer::ModelType type, |
@@ -96,9 +118,61 @@ PasswordSyncableService::MergeDataAndStartSyncing( |
sync_error_factory_ = sync_error_factory.Pass(); |
sync_processor_ = sync_processor.Pass(); |
- merge_result.set_error(sync_error_factory->CreateAndUploadError( |
- FROM_HERE, |
- "Password Syncable Service Not Implemented.")); |
+ ScopedVector<autofill::PasswordForm> password_entries; |
+ if (!password_store_->FillAutofillableLogins(&(password_entries.get())) || |
+ !password_store_->FillBlacklistLogins(&(password_entries.get()))) { |
+ // Password store often fails to load passwords. Track failures with UMA. |
+ // (http://crbug.com/249000) |
+ UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad", |
+ ModelTypeToHistogramInt(syncer::PASSWORDS), |
+ syncer::MODEL_TYPE_COUNT); |
+ merge_result.set_error(sync_error_factory->CreateAndUploadError( |
+ FROM_HERE, |
+ "Failed to get passwords from store.")); |
+ return merge_result;; |
+ } |
+ |
+ PasswordEntryMap new_db_entries; |
+ for (std::vector<autofill::PasswordForm*>::iterator |
+ it = password_entries.begin(); |
+ it != password_entries.end(); |
+ ++it) { |
+ // We add all the db entries as |new_db_entries| initially. While |
+ // association entries with matching sync entries will be removed and this |
+ // list will only contain entries that are not in sync. |
+ new_db_entries[MakeTag(**it)] = |
+ std::make_pair(syncer::SyncChange::ACTION_ADD, it); |
+ } |
+ |
+ // List that contains the entries that are known only to sync. |
+ ScopedVector<autofill::PasswordForm> new_synced_entries; |
+ |
+ // List that contains the entries that are known to both sync and db but |
+ // have to be updated in sync. |
+ ScopedVector<autofill::PasswordForm> updated_sync_entries; |
+ for (syncer::SyncDataList::const_iterator sync_iter = |
+ initial_sync_data.begin(); |
+ sync_iter != initial_sync_data.end(); ++sync_iter) { |
+ CreateOrUpdateEntry(*sync_iter, |
+ &new_db_entries, |
+ &new_synced_entries, |
+ &updated_sync_entries); |
+ } |
+ |
+ WriteToPasswordStore(&(new_synced_entries.get()), |
Nicolas Zea
2013/10/21 23:55:14
nit: WriteToPasswordStore should be taking const r
lipalani1
2013/10/24 00:13:58
Done.
|
+ &(updated_sync_entries.get())); |
+ |
+ syncer::SyncChangeList new_changes; |
+ for (PasswordEntryMap::iterator it = new_db_entries.begin(); |
+ it != new_db_entries.end(); |
+ ++it) { |
+ new_changes.push_back(syncer::SyncChange(FROM_HERE, |
+ it->second.first, |
+ CreateSyncData(**(it->second.second)))); |
+ } |
+ |
+ merge_result.set_error( |
+ sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes)); |
return merge_result; |
} |
@@ -141,10 +215,14 @@ void PasswordSyncableService::WriteToPasswordStore( |
if (!new_entries->empty() || !updated_entries->empty()) { |
// We have to notify password store observers of the change by hand since |
// we use internal password store interfaces to make changes synchronously. |
- password_store_->PostNotifyLoginsChanged(); |
+ NotifyPasswordStore(); |
} |
} |
+void PasswordSyncableService::NotifyPasswordStore() { |
+ password_store_->PostNotifyLoginsChanged(); |
+} |
+ |
syncer::SyncData PasswordSyncableService::CreateSyncData( |
const autofill::PasswordForm& password_form) { |
sync_pb::EntitySpecifics password_data; |
@@ -206,3 +284,28 @@ std::string PasswordSyncableService::MakeTag( |
password.signon_realm()); |
} |
+// static |
+void PasswordSyncableService::ExtractPasswordFromSpecifics( |
+ const sync_pb::PasswordSpecificsData& password, |
+ autofill::PasswordForm* new_password) { |
+ new_password->scheme = |
+ static_cast<autofill::PasswordForm::Scheme>(password.scheme()); |
+ new_password->signon_realm = password.signon_realm(); |
+ new_password->origin = GURL(password.origin()); |
+ new_password->action = GURL(password.action()); |
+ new_password->username_element = |
+ UTF8ToUTF16(password.username_element()); |
+ new_password->password_element = |
+ UTF8ToUTF16(password.password_element()); |
+ new_password->username_value = |
+ UTF8ToUTF16(password.username_value()); |
+ new_password->password_value = |
+ UTF8ToUTF16(password.password_value()); |
+ new_password->ssl_valid = password.ssl_valid(); |
+ new_password->preferred = password.preferred(); |
+ new_password->date_created = |
+ base::Time::FromInternalValue(password.date_created()); |
+ new_password->blacklisted_by_user = |
+ password.blacklisted(); |
+} |
+ |