summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/password_manager/password_store.h6
-rw-r--r--chrome/browser/password_manager/password_syncable_service.cc161
-rw-r--r--chrome/browser/password_manager/password_syncable_service.h45
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__