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/password_manager/password_store.h"
14 #include "chrome/browser/sync/profile_sync_service.h"
15 #include "components/autofill/core/common/password_form.h"
16 #include "net/base/escape.h"
17 #include "sync/api/sync_error.h"
18 #include "sync/internal_api/public/read_node.h"
19 #include "sync/internal_api/public/read_transaction.h"
20 #include "sync/internal_api/public/write_node.h"
21 #include "sync/internal_api/public/write_transaction.h"
22 #include "sync/protocol/password_specifics.pb.h"
24 using base::UTF8ToUTF16
;
25 using base::UTF16ToUTF8
;
26 using content::BrowserThread
;
28 namespace browser_sync
{
30 const char kPasswordTag
[] = "google_chrome_passwords";
32 PasswordModelAssociator::PasswordModelAssociator(
33 ProfileSyncService
* sync_service
,
34 PasswordStore
* password_store
,
35 DataTypeErrorHandler
* error_handler
)
36 : sync_service_(sync_service
),
37 password_store_(password_store
),
38 password_node_id_(syncer::kInvalidId
),
39 abort_association_requested_(false),
40 expected_loop_(base::MessageLoop::current()),
41 error_handler_(error_handler
) {
42 DCHECK(sync_service_
);
43 #if defined(OS_MACOSX)
44 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI
));
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
50 PasswordModelAssociator::~PasswordModelAssociator() {
51 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI
));
54 syncer::SyncError
PasswordModelAssociator::AssociateModels(
55 syncer::SyncMergeResult
* local_merge_result
,
56 syncer::SyncMergeResult
* syncer_merge_result
) {
57 DCHECK(expected_loop_
== base::MessageLoop::current());
59 PasswordVector new_passwords
;
60 PasswordVector updated_passwords
;
62 base::AutoLock
lock(association_lock_
);
63 if (abort_association_requested_
)
64 return syncer::SyncError();
66 CHECK(password_store_
.get());
68 // We must not be holding a transaction when we interact with the password
69 // store, as it can post tasks to the UI thread which can itself be blocked
70 // on our transaction, resulting in deadlock. (http://crbug.com/70658)
71 std::vector
<autofill::PasswordForm
*> passwords
;
72 if (!password_store_
->FillAutofillableLogins(&passwords
) ||
73 !password_store_
->FillBlacklistLogins(&passwords
)) {
74 STLDeleteElements(&passwords
);
76 // Password store often fails to load passwords. Track failures with UMA.
77 // (http://crbug.com/249000)
78 UMA_HISTOGRAM_ENUMERATION("Sync.LocalDataFailedToLoad",
79 ModelTypeToHistogramInt(syncer::PASSWORDS
),
80 syncer::MODEL_TYPE_COUNT
);
81 return syncer::SyncError(FROM_HERE
,
82 syncer::SyncError::DATATYPE_ERROR
,
83 "Could not get the password entries.",
87 std::set
<std::string
> current_passwords
;
88 syncer::WriteTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
89 syncer::ReadNode
password_root(&trans
);
90 if (password_root
.InitByTagLookup(kPasswordTag
) !=
91 syncer::BaseNode::INIT_OK
) {
92 return error_handler_
->CreateAndUploadError(
94 "Server did not create the top-level password node. We "
95 "might be running against an out-of-date server.",
99 for (std::vector
<autofill::PasswordForm
*>::iterator ix
=
101 ix
!= passwords
.end(); ++ix
) {
102 std::string tag
= MakeTag(**ix
);
104 syncer::ReadNode
node(&trans
);
105 if (node
.InitByClientTagLookup(syncer::PASSWORDS
, tag
) ==
106 syncer::BaseNode::INIT_OK
) {
107 const sync_pb::PasswordSpecificsData
& password
=
108 node
.GetPasswordSpecifics();
109 DCHECK_EQ(tag
, MakeTag(password
));
111 autofill::PasswordForm new_password
;
113 if (MergePasswords(password
, **ix
, &new_password
)) {
114 syncer::WriteNode
write_node(&trans
);
115 if (write_node
.InitByClientTagLookup(syncer::PASSWORDS
, tag
) !=
116 syncer::BaseNode::INIT_OK
) {
117 STLDeleteElements(&passwords
);
118 return error_handler_
->CreateAndUploadError(
120 "Failed to edit password sync node.",
123 WriteToSyncNode(new_password
, &write_node
);
124 updated_passwords
.push_back(new_password
);
127 Associate(&tag
, node
.GetId());
129 syncer::WriteNode
node(&trans
);
130 syncer::WriteNode::InitUniqueByCreationResult result
=
131 node
.InitUniqueByCreation(syncer::PASSWORDS
, password_root
, tag
);
132 if (result
!= syncer::WriteNode::INIT_SUCCESS
) {
133 STLDeleteElements(&passwords
);
134 return error_handler_
->CreateAndUploadError(
136 "Failed to create password sync node.",
140 WriteToSyncNode(**ix
, &node
);
142 Associate(&tag
, node
.GetId());
145 current_passwords
.insert(tag
);
148 STLDeleteElements(&passwords
);
150 int64 sync_child_id
= password_root
.GetFirstChildId();
151 while (sync_child_id
!= syncer::kInvalidId
) {
152 syncer::ReadNode
sync_child_node(&trans
);
153 if (sync_child_node
.InitByIdLookup(sync_child_id
) !=
154 syncer::BaseNode::INIT_OK
) {
155 return error_handler_
->CreateAndUploadError(
157 "Failed to fetch child node.",
160 const sync_pb::PasswordSpecificsData
& password
=
161 sync_child_node
.GetPasswordSpecifics();
162 std::string tag
= MakeTag(password
);
164 // The password only exists on the server. Add it to the local
166 if (current_passwords
.find(tag
) == current_passwords
.end()) {
167 autofill::PasswordForm new_password
;
169 CopyPassword(password
, &new_password
);
170 Associate(&tag
, sync_child_node
.GetId());
171 new_passwords
.push_back(new_password
);
174 sync_child_id
= sync_child_node
.GetSuccessorId();
178 // We must not be holding a transaction when we interact with the password
179 // store, as it can post tasks to the UI thread which can itself be blocked
180 // on our transaction, resulting in deadlock. (http://crbug.com/70658)
181 return WriteToPasswordStore(&new_passwords
,
186 bool PasswordModelAssociator::DeleteAllNodes(
187 syncer::WriteTransaction
* trans
) {
188 DCHECK(expected_loop_
== base::MessageLoop::current());
189 for (PasswordToSyncIdMap::iterator node_id
= id_map_
.begin();
190 node_id
!= id_map_
.end(); ++node_id
) {
191 syncer::WriteNode
sync_node(trans
);
192 if (sync_node
.InitByIdLookup(node_id
->second
) !=
193 syncer::BaseNode::INIT_OK
) {
194 LOG(ERROR
) << "Typed url node lookup failed.";
197 sync_node
.Tombstone();
201 id_map_inverse_
.clear();
205 syncer::SyncError
PasswordModelAssociator::DisassociateModels() {
207 id_map_inverse_
.clear();
208 return syncer::SyncError();
211 bool PasswordModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes
) {
214 int64 password_sync_id
;
215 if (!GetSyncIdForTaggedNode(kPasswordTag
, &password_sync_id
)) {
216 LOG(ERROR
) << "Server did not create the top-level password node. We "
217 << "might be running against an out-of-date server.";
220 syncer::ReadTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
222 syncer::ReadNode
password_node(&trans
);
223 if (password_node
.InitByIdLookup(password_sync_id
) !=
224 syncer::BaseNode::INIT_OK
) {
225 LOG(ERROR
) << "Server did not create the top-level password node. We "
226 << "might be running against an out-of-date server.";
230 // The sync model has user created nodes if the password folder has any
232 *has_nodes
= password_node
.HasChildren();
236 void PasswordModelAssociator::AbortAssociation() {
237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
238 base::AutoLock
lock(association_lock_
);
239 abort_association_requested_
= true;
240 password_store_
= NULL
;
243 bool PasswordModelAssociator::CryptoReadyIfNecessary() {
244 // We only access the cryptographer while holding a transaction.
245 syncer::ReadTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
246 // We always encrypt passwords, so no need to check if encryption is enabled.
247 return sync_service_
->IsCryptographerReady(&trans
);
250 const std::string
* PasswordModelAssociator::GetChromeNodeFromSyncId(
255 bool PasswordModelAssociator::InitSyncNodeFromChromeId(
256 const std::string
& node_id
,
257 syncer::BaseNode
* sync_node
) {
261 int64
PasswordModelAssociator::GetSyncIdFromChromeId(
262 const std::string
& password
) {
263 PasswordToSyncIdMap::const_iterator iter
= id_map_
.find(password
);
264 return iter
== id_map_
.end() ? syncer::kInvalidId
: iter
->second
;
267 void PasswordModelAssociator::Associate(
268 const std::string
* password
, int64 sync_id
) {
269 DCHECK(expected_loop_
== base::MessageLoop::current());
270 DCHECK_NE(syncer::kInvalidId
, sync_id
);
271 DCHECK(id_map_
.find(*password
) == id_map_
.end());
272 DCHECK(id_map_inverse_
.find(sync_id
) == id_map_inverse_
.end());
273 id_map_
[*password
] = sync_id
;
274 id_map_inverse_
[sync_id
] = *password
;
277 void PasswordModelAssociator::Disassociate(int64 sync_id
) {
278 DCHECK(expected_loop_
== base::MessageLoop::current());
279 SyncIdToPasswordMap::iterator iter
= id_map_inverse_
.find(sync_id
);
280 if (iter
== id_map_inverse_
.end())
282 CHECK(id_map_
.erase(iter
->second
));
283 id_map_inverse_
.erase(iter
);
286 bool PasswordModelAssociator::GetSyncIdForTaggedNode(const std::string
& tag
,
288 syncer::ReadTransaction
trans(FROM_HERE
, sync_service_
->GetUserShare());
289 syncer::ReadNode
sync_node(&trans
);
290 if (sync_node
.InitByTagLookup(tag
.c_str()) != syncer::BaseNode::INIT_OK
)
292 *sync_id
= sync_node
.GetId();
296 syncer::SyncError
PasswordModelAssociator::WriteToPasswordStore(
297 const PasswordVector
* new_passwords
,
298 const PasswordVector
* updated_passwords
,
299 const PasswordVector
* deleted_passwords
) {
300 base::AutoLock
lock(association_lock_
);
301 if (abort_association_requested_
)
302 return syncer::SyncError();
304 CHECK(password_store_
.get());
307 for (PasswordVector::const_iterator password
= new_passwords
->begin();
308 password
!= new_passwords
->end(); ++password
) {
309 password_store_
->AddLoginImpl(*password
);
313 if (updated_passwords
) {
314 for (PasswordVector::const_iterator password
= updated_passwords
->begin();
315 password
!= updated_passwords
->end(); ++password
) {
316 password_store_
->UpdateLoginImpl(*password
);
320 if (deleted_passwords
) {
321 for (PasswordVector::const_iterator password
= deleted_passwords
->begin();
322 password
!= deleted_passwords
->end(); ++password
) {
323 password_store_
->RemoveLoginImpl(*password
);
327 if (new_passwords
|| updated_passwords
|| deleted_passwords
) {
328 // We have to notify password store observers of the change by hand since
329 // we use internal password store interfaces to make changes synchronously.
330 password_store_
->PostNotifyLoginsChanged();
332 return syncer::SyncError();
336 void PasswordModelAssociator::CopyPassword(
337 const sync_pb::PasswordSpecificsData
& password
,
338 autofill::PasswordForm
* new_password
) {
339 new_password
->scheme
=
340 static_cast<autofill::PasswordForm::Scheme
>(password
.scheme());
341 new_password
->signon_realm
= password
.signon_realm();
342 new_password
->origin
= GURL(password
.origin());
343 new_password
->action
= GURL(password
.action());
344 new_password
->username_element
=
345 UTF8ToUTF16(password
.username_element());
346 new_password
->password_element
=
347 UTF8ToUTF16(password
.password_element());
348 new_password
->username_value
=
349 UTF8ToUTF16(password
.username_value());
350 new_password
->password_value
=
351 UTF8ToUTF16(password
.password_value());
352 new_password
->ssl_valid
= password
.ssl_valid();
353 new_password
->preferred
= password
.preferred();
354 new_password
->date_created
=
355 base::Time::FromInternalValue(password
.date_created());
356 new_password
->blacklisted_by_user
=
357 password
.blacklisted();
361 bool PasswordModelAssociator::MergePasswords(
362 const sync_pb::PasswordSpecificsData
& password
,
363 const autofill::PasswordForm
& password_form
,
364 autofill::PasswordForm
* new_password
) {
365 DCHECK(new_password
);
367 if (password
.scheme() == password_form
.scheme
&&
368 password_form
.signon_realm
== password
.signon_realm() &&
369 password_form
.origin
.spec() == password
.origin() &&
370 password_form
.action
.spec() == password
.action() &&
371 UTF16ToUTF8(password_form
.username_element
) ==
372 password
.username_element() &&
373 UTF16ToUTF8(password_form
.password_element
) ==
374 password
.password_element() &&
375 UTF16ToUTF8(password_form
.username_value
) ==
376 password
.username_value() &&
377 UTF16ToUTF8(password_form
.password_value
) ==
378 password
.password_value() &&
379 password
.ssl_valid() == password_form
.ssl_valid
&&
380 password
.preferred() == password_form
.preferred
&&
381 password
.date_created() == password_form
.date_created
.ToInternalValue() &&
382 password
.blacklisted() == password_form
.blacklisted_by_user
) {
386 // If the passwords differ, we take the one that was created more recently.
387 if (base::Time::FromInternalValue(password
.date_created()) <=
388 password_form
.date_created
) {
389 *new_password
= password_form
;
391 CopyPassword(password
, new_password
);
398 void PasswordModelAssociator::WriteToSyncNode(
399 const autofill::PasswordForm
& password_form
,
400 syncer::WriteNode
* node
) {
401 sync_pb::PasswordSpecificsData password
;
402 password
.set_scheme(password_form
.scheme
);
403 password
.set_signon_realm(password_form
.signon_realm
);
404 password
.set_origin(password_form
.origin
.spec());
405 password
.set_action(password_form
.action
.spec());
406 password
.set_username_element(UTF16ToUTF8(password_form
.username_element
));
407 password
.set_password_element(UTF16ToUTF8(password_form
.password_element
));
408 password
.set_username_value(UTF16ToUTF8(password_form
.username_value
));
409 password
.set_password_value(UTF16ToUTF8(password_form
.password_value
));
410 password
.set_ssl_valid(password_form
.ssl_valid
);
411 password
.set_preferred(password_form
.preferred
);
412 password
.set_date_created(password_form
.date_created
.ToInternalValue());
413 password
.set_blacklisted(password_form
.blacklisted_by_user
);
415 node
->SetPasswordSpecifics(password
);
419 std::string
PasswordModelAssociator::MakeTag(
420 const autofill::PasswordForm
& password
) {
421 return MakeTag(password
.origin
.spec(),
422 UTF16ToUTF8(password
.username_element
),
423 UTF16ToUTF8(password
.username_value
),
424 UTF16ToUTF8(password
.password_element
),
425 password
.signon_realm
);
429 std::string
PasswordModelAssociator::MakeTag(
430 const sync_pb::PasswordSpecificsData
& password
) {
431 return MakeTag(password
.origin(),
432 password
.username_element(),
433 password
.username_value(),
434 password
.password_element(),
435 password
.signon_realm());
439 std::string
PasswordModelAssociator::MakeTag(
440 const std::string
& origin_url
,
441 const std::string
& username_element
,
442 const std::string
& username_value
,
443 const std::string
& password_element
,
444 const std::string
& signon_realm
) {
445 return net::EscapePath(origin_url
) + "|" +
446 net::EscapePath(username_element
) + "|" +
447 net::EscapePath(username_value
) + "|" +
448 net::EscapePath(password_element
) + "|" +
449 net::EscapePath(signon_realm
);
452 } // namespace browser_sync