1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sync/glue/password_model_associator.h"
9 #include "base/location.h"
10 #include "base/metrics/histogram.h"
11 #include "base/stl_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/sync/profile_sync_service.h"
14 #include "components/autofill/core/common/password_form.h"
15 #include "components/password_manager/core/browser/password_store.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "net/base/escape.h"
18 #include "sync/api/sync_error.h"
19 #include "sync/internal_api/public/read_node.h"
20 #include "sync/internal_api/public/read_transaction.h"
21 #include "sync/internal_api/public/write_node.h"
22 #include "sync/internal_api/public/write_transaction.h"
23 #include "sync/protocol/password_specifics.pb.h"
25 using base::UTF8ToUTF16;
26 using base::UTF16ToUTF8;
27 using content::BrowserThread;
31 void AppendChanges(const PasswordStoreChangeList& new_changes,
32 PasswordStoreChangeList* all_changes) {
33 all_changes->insert(all_changes->end(),
40 namespace browser_sync {
42 const char kPasswordTag[] = "google_chrome_passwords";
44 PasswordModelAssociator::PasswordModelAssociator(
45 ProfileSyncService* sync_service,
46 PasswordStore* password_store,
47 DataTypeErrorHandler* error_handler)
48 : sync_service_(sync_service),
49 password_store_(password_store),
50 password_node_id_(syncer::kInvalidId),
51 abort_association_requested_(false),
52 expected_loop_(base::MessageLoop::current()),
53 error_handler_(error_handler) {
54 DCHECK(sync_service_);
55 DCHECK(password_store->GetBackgroundTaskRunner()->RunsTasksOnCurrentThread());
58 PasswordModelAssociator::~PasswordModelAssociator() {
59 DCHECK(thread_checker_.CalledOnValidThread());
62 syncer::SyncError PasswordModelAssociator::AssociateModels(
63 syncer::SyncMergeResult* local_merge_result,
64 syncer::SyncMergeResult* syncer_merge_result) {
65 DCHECK(expected_loop_ == base::MessageLoop::current());
67 PasswordVector new_passwords;
68 PasswordVector updated_passwords;
70 base::AutoLock lock(association_lock_);
71 if (abort_association_requested_)
72 return syncer::SyncError();
74 CHECK(password_store_.get());
76 // We must not be holding a transaction when we interact with the password
77 // store, as it can post tasks to the UI thread which can itself be blocked
78 // on our transaction, resulting in deadlock. (http://crbug.com/70658)
79 std::vector<autofill::PasswordForm*> passwords;
80 if (!password_store_->FillAutofillableLogins(&passwords) ||
81 !password_store_->FillBlacklistLogins(&passwords)) {
82 STLDeleteElements(&passwords);
84 // Password store often fails to load passwords. Track failures with UMA.
85 // (http://crbug.com/249000)
86 UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad",
87 ModelTypeToHistogramInt(syncer::PASSWORDS),
88 syncer::MODEL_TYPE_COUNT);
89 return syncer::SyncError(FROM_HERE,
90 syncer::SyncError::DATATYPE_ERROR,
91 "Could not get the password entries.",
95 std::set<std::string> current_passwords;
96 syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare());
97 syncer::ReadNode password_root(&trans);
98 if (password_root.InitByTagLookup(kPasswordTag) !=
99 syncer::BaseNode::INIT_OK) {
100 return error_handler_->CreateAndUploadError(
102 "Server did not create the top-level password node. We "
103 "might be running against an out-of-date server.",
107 for (std::vector<autofill::PasswordForm*>::iterator ix =
109 ix != passwords.end(); ++ix) {
110 std::string tag = MakeTag(**ix);
112 syncer::ReadNode node(&trans);
113 if (node.InitByClientTagLookup(syncer::PASSWORDS, tag) ==
114 syncer::BaseNode::INIT_OK) {
115 const sync_pb::PasswordSpecificsData& password =
116 node.GetPasswordSpecifics();
117 DCHECK_EQ(tag, MakeTag(password));
119 autofill::PasswordForm new_password;
121 if (MergePasswords(password, **ix, &new_password)) {
122 syncer::WriteNode write_node(&trans);
123 if (write_node.InitByClientTagLookup(syncer::PASSWORDS, tag) !=
124 syncer::BaseNode::INIT_OK) {
125 STLDeleteElements(&passwords);
126 return error_handler_->CreateAndUploadError(
128 "Failed to edit password sync node.",
131 WriteToSyncNode(new_password, &write_node);
132 updated_passwords.push_back(new_password);
135 Associate(&tag, node.GetId());
137 syncer::WriteNode node(&trans);
138 syncer::WriteNode::InitUniqueByCreationResult result =
139 node.InitUniqueByCreation(syncer::PASSWORDS, password_root, tag);
140 if (result != syncer::WriteNode::INIT_SUCCESS) {
141 STLDeleteElements(&passwords);
142 return error_handler_->CreateAndUploadError(
144 "Failed to create password sync node.",
148 WriteToSyncNode(**ix, &node);
150 Associate(&tag, node.GetId());
153 current_passwords.insert(tag);
156 STLDeleteElements(&passwords);
158 int64 sync_child_id = password_root.GetFirstChildId();
159 while (sync_child_id != syncer::kInvalidId) {
160 syncer::ReadNode sync_child_node(&trans);
161 if (sync_child_node.InitByIdLookup(sync_child_id) !=
162 syncer::BaseNode::INIT_OK) {
163 return error_handler_->CreateAndUploadError(
165 "Failed to fetch child node.",
168 const sync_pb::PasswordSpecificsData& password =
169 sync_child_node.GetPasswordSpecifics();
170 std::string tag = MakeTag(password);
172 // The password only exists on the server. Add it to the local
174 if (current_passwords.find(tag) == current_passwords.end()) {
175 autofill::PasswordForm new_password;
177 CopyPassword(password, &new_password);
178 Associate(&tag, sync_child_node.GetId());
179 new_passwords.push_back(new_password);
182 sync_child_id = sync_child_node.GetSuccessorId();
186 // We must not be holding a transaction when we interact with the password
187 // store, as it can post tasks to the UI thread which can itself be blocked
188 // on our transaction, resulting in deadlock. (http://crbug.com/70658)
189 return WriteToPasswordStore(&new_passwords,
194 bool PasswordModelAssociator::DeleteAllNodes(
195 syncer::WriteTransaction* trans) {
196 DCHECK(expected_loop_ == base::MessageLoop::current());
197 for (PasswordToSyncIdMap::iterator node_id = id_map_.begin();
198 node_id != id_map_.end(); ++node_id) {
199 syncer::WriteNode sync_node(trans);
200 if (sync_node.InitByIdLookup(node_id->second) !=
201 syncer::BaseNode::INIT_OK) {
202 LOG(ERROR) << "Typed url node lookup failed.";
205 sync_node.Tombstone();
209 id_map_inverse_.clear();
213 syncer::SyncError PasswordModelAssociator::DisassociateModels() {
215 id_map_inverse_.clear();
216 return syncer::SyncError();
219 bool PasswordModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
222 int64 password_sync_id;
223 if (!GetSyncIdForTaggedNode(kPasswordTag, &password_sync_id)) {
224 LOG(ERROR) << "Server did not create the top-level password node. We "
225 << "might be running against an out-of-date server.";
228 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
230 syncer::ReadNode password_node(&trans);
231 if (password_node.InitByIdLookup(password_sync_id) !=
232 syncer::BaseNode::INIT_OK) {
233 LOG(ERROR) << "Server did not create the top-level password node. We "
234 << "might be running against an out-of-date server.";
238 // The sync model has user created nodes if the password folder has any
240 *has_nodes = password_node.HasChildren();
244 void PasswordModelAssociator::AbortAssociation() {
245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
246 base::AutoLock lock(association_lock_);
247 abort_association_requested_ = true;
248 password_store_ = NULL;
251 bool PasswordModelAssociator::CryptoReadyIfNecessary() {
252 // We only access the cryptographer while holding a transaction.
253 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
254 // We always encrypt passwords, so no need to check if encryption is enabled.
255 return sync_service_->IsCryptographerReady(&trans);
258 const std::string* PasswordModelAssociator::GetChromeNodeFromSyncId(
263 bool PasswordModelAssociator::InitSyncNodeFromChromeId(
264 const std::string& node_id,
265 syncer::BaseNode* sync_node) {
269 int64 PasswordModelAssociator::GetSyncIdFromChromeId(
270 const std::string& password) {
271 PasswordToSyncIdMap::const_iterator iter = id_map_.find(password);
272 return iter == id_map_.end() ? syncer::kInvalidId : iter->second;
275 void PasswordModelAssociator::Associate(
276 const std::string* password, int64 sync_id) {
277 DCHECK(expected_loop_ == base::MessageLoop::current());
278 DCHECK_NE(syncer::kInvalidId, sync_id);
279 DCHECK(id_map_.find(*password) == id_map_.end());
280 DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end());
281 id_map_[*password] = sync_id;
282 id_map_inverse_[sync_id] = *password;
285 void PasswordModelAssociator::Disassociate(int64 sync_id) {
286 DCHECK(expected_loop_ == base::MessageLoop::current());
287 SyncIdToPasswordMap::iterator iter = id_map_inverse_.find(sync_id);
288 if (iter == id_map_inverse_.end())
290 CHECK(id_map_.erase(iter->second));
291 id_map_inverse_.erase(iter);
294 bool PasswordModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
296 syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
297 syncer::ReadNode sync_node(&trans);
298 if (sync_node.InitByTagLookup(tag.c_str()) != syncer::BaseNode::INIT_OK)
300 *sync_id = sync_node.GetId();
304 syncer::SyncError PasswordModelAssociator::WriteToPasswordStore(
305 const PasswordVector* new_passwords,
306 const PasswordVector* updated_passwords,
307 const PasswordVector* deleted_passwords) {
308 base::AutoLock lock(association_lock_);
309 if (abort_association_requested_)
310 return syncer::SyncError();
312 CHECK(password_store_.get());
314 PasswordStoreChangeList changes;
316 for (PasswordVector::const_iterator password = new_passwords->begin();
317 password != new_passwords->end(); ++password) {
318 AppendChanges(password_store_->AddLoginImpl(*password),
323 if (updated_passwords) {
324 for (PasswordVector::const_iterator password = updated_passwords->begin();
325 password != updated_passwords->end(); ++password) {
326 AppendChanges(password_store_->UpdateLoginImpl(*password),
331 if (deleted_passwords) {
332 for (PasswordVector::const_iterator password = deleted_passwords->begin();
333 password != deleted_passwords->end(); ++password) {
334 AppendChanges(password_store_->RemoveLoginImpl(*password),
339 // We have to notify password store observers of the change by hand since
340 // we use internal password store interfaces to make changes synchronously.
341 password_store_->NotifyLoginsChanged(changes);
343 return syncer::SyncError();
347 void PasswordModelAssociator::CopyPassword(
348 const sync_pb::PasswordSpecificsData& password,
349 autofill::PasswordForm* new_password) {
350 new_password->scheme =
351 static_cast<autofill::PasswordForm::Scheme>(password.scheme());
352 new_password->signon_realm = password.signon_realm();
353 new_password->origin = GURL(password.origin());
354 new_password->action = GURL(password.action());
355 new_password->username_element =
356 UTF8ToUTF16(password.username_element());
357 new_password->password_element =
358 UTF8ToUTF16(password.password_element());
359 new_password->username_value =
360 UTF8ToUTF16(password.username_value());
361 new_password->password_value =
362 UTF8ToUTF16(password.password_value());
363 new_password->ssl_valid = password.ssl_valid();
364 new_password->preferred = password.preferred();
365 new_password->date_created =
366 base::Time::FromInternalValue(password.date_created());
367 new_password->blacklisted_by_user =
368 password.blacklisted();
372 bool PasswordModelAssociator::MergePasswords(
373 const sync_pb::PasswordSpecificsData& password,
374 const autofill::PasswordForm& password_form,
375 autofill::PasswordForm* new_password) {
376 DCHECK(new_password);
378 if (password.scheme() == password_form.scheme &&
379 password_form.signon_realm == password.signon_realm() &&
380 password_form.origin.spec() == password.origin() &&
381 password_form.action.spec() == password.action() &&
382 UTF16ToUTF8(password_form.username_element) ==
383 password.username_element() &&
384 UTF16ToUTF8(password_form.password_element) ==
385 password.password_element() &&
386 UTF16ToUTF8(password_form.username_value) ==
387 password.username_value() &&
388 UTF16ToUTF8(password_form.password_value) ==
389 password.password_value() &&
390 password.ssl_valid() == password_form.ssl_valid &&
391 password.preferred() == password_form.preferred &&
392 password.date_created() == password_form.date_created.ToInternalValue() &&
393 password.blacklisted() == password_form.blacklisted_by_user) {
397 // If the passwords differ, we take the one that was created more recently.
398 if (base::Time::FromInternalValue(password.date_created()) <=
399 password_form.date_created) {
400 *new_password = password_form;
402 CopyPassword(password, new_password);
409 void PasswordModelAssociator::WriteToSyncNode(
410 const autofill::PasswordForm& password_form,
411 syncer::WriteNode* node) {
412 sync_pb::PasswordSpecificsData password;
413 password.set_scheme(password_form.scheme);
414 password.set_signon_realm(password_form.signon_realm);
415 password.set_origin(password_form.origin.spec());
416 password.set_action(password_form.action.spec());
417 password.set_username_element(UTF16ToUTF8(password_form.username_element));
418 password.set_password_element(UTF16ToUTF8(password_form.password_element));
419 password.set_username_value(UTF16ToUTF8(password_form.username_value));
420 password.set_password_value(UTF16ToUTF8(password_form.password_value));
421 password.set_ssl_valid(password_form.ssl_valid);
422 password.set_preferred(password_form.preferred);
423 password.set_date_created(password_form.date_created.ToInternalValue());
424 password.set_blacklisted(password_form.blacklisted_by_user);
426 node->SetPasswordSpecifics(password);
430 std::string PasswordModelAssociator::MakeTag(
431 const autofill::PasswordForm& password) {
432 return MakeTag(password.origin.spec(),
433 UTF16ToUTF8(password.username_element),
434 UTF16ToUTF8(password.username_value),
435 UTF16ToUTF8(password.password_element),
436 password.signon_realm);
440 std::string PasswordModelAssociator::MakeTag(
441 const sync_pb::PasswordSpecificsData& password) {
442 return MakeTag(password.origin(),
443 password.username_element(),
444 password.username_value(),
445 password.password_element(),
446 password.signon_realm());
450 std::string PasswordModelAssociator::MakeTag(
451 const std::string& origin_url,
452 const std::string& username_element,
453 const std::string& username_value,
454 const std::string& password_element,
455 const std::string& signon_realm) {
456 return net::EscapePath(origin_url) + "|" +
457 net::EscapePath(username_element) + "|" +
458 net::EscapePath(username_value) + "|" +
459 net::EscapePath(password_element) + "|" +
460 net::EscapePath(signon_realm);
463 } // namespace browser_sync