diff options
3 files changed, 209 insertions, 3 deletions
diff --git a/chrome/browser/password_manager/password_store.h b/chrome/browser/password_manager/password_store.h index 266d3a6..c144670 100644 --- a/chrome/browser/password_manager/password_store.h +++ b/chrome/browser/password_manager/password_store.h @@ -18,6 +18,7 @@ class PasswordStore; class PasswordStoreConsumer; +class PasswordSyncableService; class Task; namespace autofill { @@ -133,10 +134,15 @@ class PasswordStore protected: friend class base::RefCountedThreadSafe<PasswordStore>; + // Sync's interaction with password store needs to be syncrhonous. + // Since the synchronous methods are private these classes are made + // as friends. This can be fixed by moving the private impl to a new + // class. See http://crbug.com/307750 friend class browser_sync::PasswordChangeProcessor; friend class browser_sync::PasswordDataTypeController; friend class browser_sync::PasswordModelAssociator; friend class browser_sync::PasswordModelWorker; + friend class PasswordSyncableService; friend void passwords_helper::AddLogin(PasswordStore*, const autofill::PasswordForm&); friend void passwords_helper::RemoveLogin(PasswordStore*, diff --git a/chrome/browser/password_manager/password_syncable_service.cc b/chrome/browser/password_manager/password_syncable_service.cc index 0db6b2f..67355e2 100644 --- a/chrome/browser/password_manager/password_syncable_service.cc +++ b/chrome/browser/password_manager/password_syncable_service.cc @@ -5,9 +5,83 @@ #include "chrome/browser/password_manager/password_syncable_service.h" #include "base/location.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_factory.h" -PasswordSyncableService::PasswordSyncableService() { +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( + const sync_pb::PasswordSpecificsData& password_specifics, + const autofill::PasswordForm& password_form, + autofill::PasswordForm* new_password_form) { + if (password_specifics.scheme() == password_form.scheme && + password_form.signon_realm == password_specifics.signon_realm() && + password_form.origin.spec() == password_specifics.origin() && + password_form.action.spec() == password_specifics.action() && + UTF16ToUTF8(password_form.username_element) == + password_specifics.username_element() && + UTF16ToUTF8(password_form.password_element) == + password_specifics.password_element() && + UTF16ToUTF8(password_form.username_value) == + password_specifics.username_value() && + UTF16ToUTF8(password_form.password_value) == + password_specifics.password_value() && + password_specifics.ssl_valid() == password_form.ssl_valid && + password_specifics.preferred() == password_form.preferred && + password_specifics.date_created() == + password_form.date_created.ToInternalValue() && + password_specifics.blacklisted() == + password_form.blacklisted_by_user) { + return false; + } + + // If the passwords differ, take the one that was created more recently. + if (base::Time::FromInternalValue(password_specifics.date_created()) <= + password_form.date_created) { + *new_password_form = password_form; + } else { + ExtractPasswordFromSpecifics(password_specifics, new_password_form); + } + + return true; +} + +} // namespace + +PasswordSyncableService::PasswordSyncableService( + scoped_refptr<PasswordStore> password_store) + : password_store_(password_store) { } PasswordSyncableService::~PasswordSyncableService() {} @@ -47,3 +121,88 @@ syncer::SyncError PasswordSyncableService::ProcessSyncChanges( return error; } +void PasswordSyncableService::WriteToPasswordStore( + PasswordForms* new_entries, + PasswordForms* updated_entries) { + for (std::vector<autofill::PasswordForm*>::const_iterator it = + new_entries->begin(); + it != new_entries->end(); + ++it) { + password_store_->AddLoginImpl(**it); + } + + for (std::vector<autofill::PasswordForm*>::const_iterator it = + updated_entries->begin(); + it != updated_entries->end(); + ++it) { + password_store_->UpdateLoginImpl(**it); + } + + 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(); + } +} + +syncer::SyncData PasswordSyncableService::CreateSyncData( + const autofill::PasswordForm& password_form) { + sync_pb::EntitySpecifics password_data; + sync_pb::PasswordSpecificsData* password_specifics = + password_data.mutable_password()->mutable_client_only_encrypted_data(); + password_specifics->set_scheme(password_form.scheme); + password_specifics->set_signon_realm(password_form.signon_realm); + password_specifics->set_origin(password_form.origin.spec()); + password_specifics->set_action(password_form.action.spec()); + password_specifics->set_username_element( + UTF16ToUTF8(password_form.username_element)); + password_specifics->set_password_element( + UTF16ToUTF8(password_form.password_element)); + password_specifics->set_username_value( + UTF16ToUTF8(password_form.username_value)); + password_specifics->set_password_value( + UTF16ToUTF8(password_form.password_value)); + password_specifics->set_ssl_valid(password_form.ssl_valid); + password_specifics->set_preferred(password_form.preferred); + password_specifics->set_date_created( + password_form.date_created.ToInternalValue()); + password_specifics->set_blacklisted(password_form.blacklisted_by_user); + + std::string tag = MakeTag(*password_specifics); + return syncer::SyncData::CreateLocalData(tag, tag, password_data); +} + +// static +std::string PasswordSyncableService::MakeTag( + const std::string& origin_url, + const std::string& username_element, + const std::string& username_value, + const std::string& password_element, + const std::string& signon_realm) { + return net::EscapePath(origin_url) + "|" + + net::EscapePath(username_element) + "|" + + net::EscapePath(username_value) + "|" + + net::EscapePath(password_element) + "|" + + net::EscapePath(signon_realm); +} + +// static +std::string PasswordSyncableService::MakeTag( + const autofill::PasswordForm& password) { + return MakeTag(password.origin.spec(), + UTF16ToUTF8(password.username_element), + UTF16ToUTF8(password.username_value), + UTF16ToUTF8(password.password_element), + password.signon_realm); +} + +// static +std::string PasswordSyncableService::MakeTag( + const sync_pb::PasswordSpecificsData& password) { + return MakeTag(password.origin(), + password.username_element(), + password.username_value(), + password.password_element(), + password.signon_realm()); +} + diff --git a/chrome/browser/password_manager/password_syncable_service.h b/chrome/browser/password_manager/password_syncable_service.h index 4b9c27e..dd32b2c 100644 --- a/chrome/browser/password_manager/password_syncable_service.h +++ b/chrome/browser/password_manager/password_syncable_service.h @@ -5,21 +5,36 @@ #ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_SYNCABLE_SERVICE_H__ #define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_SYNCABLE_SERVICE_H__ +#include <string> +#include <vector> + #include "base/memory/scoped_ptr.h" #include "sync/api/sync_change.h" #include "sync/api/sync_data.h" #include "sync/api/sync_error.h" #include "sync/api/syncable_service.h" +#include "sync/protocol/password_specifics.pb.h" +#include "sync/protocol/sync.pb.h" + +namespace autofill { +struct PasswordForm; +} namespace syncer { class SyncErrorFactory; -} // namespace syncer +} class PasswordStore; class PasswordSyncableService : public syncer::SyncableService { public: - PasswordSyncableService(); + // TODO(lipalani) - The |PasswordStore| should outlive + // |PasswordSyncableService| and there should be a code + // guarantee to that effect. Currently this object is not instantiated. + // When this class is completed and instantiated the object lifetime + // guarantee will be implemented. + explicit PasswordSyncableService( + scoped_refptr<PasswordStore> password_store); virtual ~PasswordSyncableService(); // syncer::SyncableServiceImplementations @@ -35,9 +50,35 @@ class PasswordSyncableService : public syncer::SyncableService { const tracked_objects::Location& from_here, const syncer::SyncChangeList& change_list) OVERRIDE; + // Returns the unique tag that will serve as the sync identifier for the + // |password| entry. + static std::string MakeTag(const autofill::PasswordForm& password); + static std::string MakeTag(const sync_pb::PasswordSpecificsData& password); + static std::string MakeTag(const std::string& origin_url, + const std::string& username_element, + const std::string& username_value, + const std::string& password_element, + const std::string& signon_realm); + private: + typedef std::vector<autofill::PasswordForm*> PasswordForms; + + // Use the |PasswordStore| APIs to add and update entries. + void WriteToPasswordStore(PasswordForms* new_entries, + PasswordForms* udpated_entries); + + // Converts the |PasswordForm| to |SyncData| suitable for syncing. + syncer::SyncData CreateSyncData(const autofill::PasswordForm& password); + + // The factory that creates sync errors. |SyncError| has rich data + // suitable for debugging. scoped_ptr<syncer::SyncErrorFactory> sync_error_factory_; + + // |SyncProcessor| will mirror the |PasswordStore| changes in the sync db. scoped_ptr<syncer::SyncChangeProcessor> sync_processor_; + + // The password store that adds/updates/deletes password entries. + scoped_refptr<PasswordStore> password_store_; }; #endif // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_SYNCABLE_SERVICE_H__ |