OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync/glue/password_model_associator.h" | 5 #include "chrome/browser/sync/glue/password_model_associator.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "base/location.h" | 9 #include "base/location.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 #include "webkit/forms/password_form.h" | 21 #include "webkit/forms/password_form.h" |
22 | 22 |
23 using content::BrowserThread; | 23 using content::BrowserThread; |
24 | 24 |
25 namespace browser_sync { | 25 namespace browser_sync { |
26 | 26 |
27 const char kPasswordTag[] = "google_chrome_passwords"; | 27 const char kPasswordTag[] = "google_chrome_passwords"; |
28 | 28 |
29 PasswordModelAssociator::PasswordModelAssociator( | 29 PasswordModelAssociator::PasswordModelAssociator( |
30 ProfileSyncService* sync_service, | 30 ProfileSyncService* sync_service, |
31 PasswordStore* password_store) | 31 PasswordStore* password_store, |
| 32 DataTypeErrorHandler* error_handler) |
32 : sync_service_(sync_service), | 33 : sync_service_(sync_service), |
33 password_store_(password_store), | 34 password_store_(password_store), |
34 password_node_id_(sync_api::kInvalidId), | 35 password_node_id_(sync_api::kInvalidId), |
35 abort_association_pending_(false), | 36 abort_association_pending_(false), |
36 expected_loop_(MessageLoop::current()) { | 37 expected_loop_(MessageLoop::current()), |
| 38 error_handler_(error_handler) { |
37 DCHECK(sync_service_); | 39 DCHECK(sync_service_); |
38 DCHECK(password_store_); | 40 DCHECK(password_store_); |
39 #if defined(OS_MACOSX) | 41 #if defined(OS_MACOSX) |
40 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); | 42 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); |
41 #else | 43 #else |
42 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | 44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
43 #endif | 45 #endif |
44 } | 46 } |
45 | 47 |
46 PasswordModelAssociator::~PasswordModelAssociator() {} | 48 PasswordModelAssociator::~PasswordModelAssociator() {} |
47 | 49 |
48 bool PasswordModelAssociator::AssociateModels(SyncError* error) { | 50 SyncError PasswordModelAssociator::AssociateModels() { |
| 51 SyncError error; |
49 DCHECK(expected_loop_ == MessageLoop::current()); | 52 DCHECK(expected_loop_ == MessageLoop::current()); |
50 { | 53 { |
51 base::AutoLock lock(abort_association_pending_lock_); | 54 base::AutoLock lock(abort_association_pending_lock_); |
52 abort_association_pending_ = false; | 55 abort_association_pending_ = false; |
53 } | 56 } |
54 | 57 |
55 // We must not be holding a transaction when we interact with the password | 58 // We must not be holding a transaction when we interact with the password |
56 // store, as it can post tasks to the UI thread which can itself be blocked | 59 // store, as it can post tasks to the UI thread which can itself be blocked |
57 // on our transaction, resulting in deadlock. (http://crbug.com/70658) | 60 // on our transaction, resulting in deadlock. (http://crbug.com/70658) |
58 std::vector<webkit::forms::PasswordForm*> passwords; | 61 std::vector<webkit::forms::PasswordForm*> passwords; |
59 if (!password_store_->FillAutofillableLogins(&passwords) || | 62 if (!password_store_->FillAutofillableLogins(&passwords) || |
60 !password_store_->FillBlacklistLogins(&passwords)) { | 63 !password_store_->FillBlacklistLogins(&passwords)) { |
61 STLDeleteElements(&passwords); | 64 STLDeleteElements(&passwords); |
62 error->Reset(FROM_HERE, | 65 return error_handler_->CreateAndUploadError( |
63 "Could not get the password entries.", | 66 FROM_HERE, |
64 model_type()); | 67 "Could not get the password entries.", |
65 return false; | 68 model_type()); |
66 } | 69 } |
67 | 70 |
68 std::set<std::string> current_passwords; | 71 std::set<std::string> current_passwords; |
69 PasswordVector new_passwords; | 72 PasswordVector new_passwords; |
70 PasswordVector updated_passwords; | 73 PasswordVector updated_passwords; |
71 { | 74 { |
72 sync_api::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); | 75 sync_api::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); |
73 sync_api::ReadNode password_root(&trans); | 76 sync_api::ReadNode password_root(&trans); |
74 if (!password_root.InitByTagLookup(kPasswordTag)) { | 77 if (!password_root.InitByTagLookup(kPasswordTag)) { |
75 error->Reset(FROM_HERE, | 78 return error_handler_->CreateAndUploadError( |
76 "Server did not create the top-level password node. We " | 79 FROM_HERE, |
77 "might be running against an out-of-date server.", | 80 "Server did not create the top-level password node. We " |
78 model_type()); | 81 "might be running against an out-of-date server.", |
79 return false; | 82 model_type()); |
80 } | 83 } |
81 | 84 |
82 for (std::vector<webkit::forms::PasswordForm*>::iterator ix = | 85 for (std::vector<webkit::forms::PasswordForm*>::iterator ix = |
83 passwords.begin(); | 86 passwords.begin(); |
84 ix != passwords.end(); ++ix) { | 87 ix != passwords.end(); ++ix) { |
85 if (IsAbortPending()) { | 88 if (IsAbortPending()) { |
86 error->Reset(FROM_HERE, "Abort pending", model_type()); | 89 return SyncError(); |
87 return false; | |
88 } | 90 } |
89 std::string tag = MakeTag(**ix); | 91 std::string tag = MakeTag(**ix); |
90 | 92 |
91 sync_api::ReadNode node(&trans); | 93 sync_api::ReadNode node(&trans); |
92 if (node.InitByClientTagLookup(syncable::PASSWORDS, tag)) { | 94 if (node.InitByClientTagLookup(syncable::PASSWORDS, tag)) { |
93 const sync_pb::PasswordSpecificsData& password = | 95 const sync_pb::PasswordSpecificsData& password = |
94 node.GetPasswordSpecifics(); | 96 node.GetPasswordSpecifics(); |
95 DCHECK_EQ(tag, MakeTag(password)); | 97 DCHECK_EQ(tag, MakeTag(password)); |
96 | 98 |
97 webkit::forms::PasswordForm new_password; | 99 webkit::forms::PasswordForm new_password; |
98 | 100 |
99 if (MergePasswords(password, **ix, &new_password)) { | 101 if (MergePasswords(password, **ix, &new_password)) { |
100 sync_api::WriteNode write_node(&trans); | 102 sync_api::WriteNode write_node(&trans); |
101 if (!write_node.InitByClientTagLookup(syncable::PASSWORDS, tag)) { | 103 if (!write_node.InitByClientTagLookup(syncable::PASSWORDS, tag)) { |
102 STLDeleteElements(&passwords); | 104 STLDeleteElements(&passwords); |
103 error->Reset(FROM_HERE, | 105 return error_handler_->CreateAndUploadError( |
104 "Failed to edit password sync node.", | 106 FROM_HERE, |
105 model_type()); | 107 "Failed to edit password sync node.", |
106 return false; | 108 model_type()); |
107 } | 109 } |
108 WriteToSyncNode(new_password, &write_node); | 110 WriteToSyncNode(new_password, &write_node); |
109 updated_passwords.push_back(new_password); | 111 updated_passwords.push_back(new_password); |
110 } | 112 } |
111 | 113 |
112 Associate(&tag, node.GetId()); | 114 Associate(&tag, node.GetId()); |
113 } else { | 115 } else { |
114 sync_api::WriteNode node(&trans); | 116 sync_api::WriteNode node(&trans); |
115 if (!node.InitUniqueByCreation(syncable::PASSWORDS, | 117 if (!node.InitUniqueByCreation(syncable::PASSWORDS, |
116 password_root, tag)) { | 118 password_root, tag)) { |
117 STLDeleteElements(&passwords); | 119 STLDeleteElements(&passwords); |
118 error->Reset(FROM_HERE, | 120 return error_handler_->CreateAndUploadError( |
119 "Failed to create password sync node.", | 121 FROM_HERE, |
120 model_type()); | 122 "Failed to create password sync node.", |
121 return false; | 123 model_type()); |
122 } | 124 } |
123 | 125 |
124 WriteToSyncNode(**ix, &node); | 126 WriteToSyncNode(**ix, &node); |
125 | 127 |
126 Associate(&tag, node.GetId()); | 128 Associate(&tag, node.GetId()); |
127 } | 129 } |
128 | 130 |
129 current_passwords.insert(tag); | 131 current_passwords.insert(tag); |
130 } | 132 } |
131 | 133 |
132 STLDeleteElements(&passwords); | 134 STLDeleteElements(&passwords); |
133 | 135 |
134 int64 sync_child_id = password_root.GetFirstChildId(); | 136 int64 sync_child_id = password_root.GetFirstChildId(); |
135 while (sync_child_id != sync_api::kInvalidId) { | 137 while (sync_child_id != sync_api::kInvalidId) { |
136 sync_api::ReadNode sync_child_node(&trans); | 138 sync_api::ReadNode sync_child_node(&trans); |
137 if (!sync_child_node.InitByIdLookup(sync_child_id)) { | 139 if (!sync_child_node.InitByIdLookup(sync_child_id)) { |
138 error->Reset(FROM_HERE, "Failed to fetch child node.", model_type()); | 140 return error_handler_->CreateAndUploadError( |
139 return false; | 141 FROM_HERE, |
| 142 "Failed to fetch child node.", |
| 143 model_type()); |
140 } | 144 } |
141 const sync_pb::PasswordSpecificsData& password = | 145 const sync_pb::PasswordSpecificsData& password = |
142 sync_child_node.GetPasswordSpecifics(); | 146 sync_child_node.GetPasswordSpecifics(); |
143 std::string tag = MakeTag(password); | 147 std::string tag = MakeTag(password); |
144 | 148 |
145 // The password only exists on the server. Add it to the local | 149 // The password only exists on the server. Add it to the local |
146 // model. | 150 // model. |
147 if (current_passwords.find(tag) == current_passwords.end()) { | 151 if (current_passwords.find(tag) == current_passwords.end()) { |
148 webkit::forms::PasswordForm new_password; | 152 webkit::forms::PasswordForm new_password; |
149 | 153 |
150 CopyPassword(password, &new_password); | 154 CopyPassword(password, &new_password); |
151 Associate(&tag, sync_child_node.GetId()); | 155 Associate(&tag, sync_child_node.GetId()); |
152 new_passwords.push_back(new_password); | 156 new_passwords.push_back(new_password); |
153 } | 157 } |
154 | 158 |
155 sync_child_id = sync_child_node.GetSuccessorId(); | 159 sync_child_id = sync_child_node.GetSuccessorId(); |
156 } | 160 } |
157 } | 161 } |
158 | 162 |
159 // We must not be holding a transaction when we interact with the password | 163 // We must not be holding a transaction when we interact with the password |
160 // store, as it can post tasks to the UI thread which can itself be blocked | 164 // store, as it can post tasks to the UI thread which can itself be blocked |
161 // on our transaction, resulting in deadlock. (http://crbug.com/70658) | 165 // on our transaction, resulting in deadlock. (http://crbug.com/70658) |
162 if (!WriteToPasswordStore(&new_passwords, &updated_passwords, NULL)) { | 166 error = WriteToPasswordStore(&new_passwords, |
163 error->Reset(FROM_HERE, "Failed to write passwords.", model_type()); | 167 &updated_passwords, |
164 return false; | 168 NULL); |
| 169 if (error.IsSet()) { |
| 170 return error; |
165 } | 171 } |
166 | 172 |
167 return true; | 173 return error; |
168 } | 174 } |
169 | 175 |
170 bool PasswordModelAssociator::DeleteAllNodes( | 176 bool PasswordModelAssociator::DeleteAllNodes( |
171 sync_api::WriteTransaction* trans) { | 177 sync_api::WriteTransaction* trans) { |
172 DCHECK(expected_loop_ == MessageLoop::current()); | 178 DCHECK(expected_loop_ == MessageLoop::current()); |
173 for (PasswordToSyncIdMap::iterator node_id = id_map_.begin(); | 179 for (PasswordToSyncIdMap::iterator node_id = id_map_.begin(); |
174 node_id != id_map_.end(); ++node_id) { | 180 node_id != id_map_.end(); ++node_id) { |
175 sync_api::WriteNode sync_node(trans); | 181 sync_api::WriteNode sync_node(trans); |
176 if (!sync_node.InitByIdLookup(node_id->second)) { | 182 if (!sync_node.InitByIdLookup(node_id->second)) { |
177 LOG(ERROR) << "Typed url node lookup failed."; | 183 LOG(ERROR) << "Typed url node lookup failed."; |
178 return false; | 184 return false; |
179 } | 185 } |
180 sync_node.Remove(); | 186 sync_node.Remove(); |
181 } | 187 } |
182 | 188 |
183 id_map_.clear(); | 189 id_map_.clear(); |
184 id_map_inverse_.clear(); | 190 id_map_inverse_.clear(); |
185 return true; | 191 return true; |
186 } | 192 } |
187 | 193 |
188 bool PasswordModelAssociator::DisassociateModels(SyncError* error) { | 194 SyncError PasswordModelAssociator::DisassociateModels() { |
189 id_map_.clear(); | 195 id_map_.clear(); |
190 id_map_inverse_.clear(); | 196 id_map_inverse_.clear(); |
191 return true; | 197 return SyncError(); |
192 } | 198 } |
193 | 199 |
194 bool PasswordModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) { | 200 bool PasswordModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) { |
195 DCHECK(has_nodes); | 201 DCHECK(has_nodes); |
196 *has_nodes = false; | 202 *has_nodes = false; |
197 int64 password_sync_id; | 203 int64 password_sync_id; |
198 if (!GetSyncIdForTaggedNode(kPasswordTag, &password_sync_id)) { | 204 if (!GetSyncIdForTaggedNode(kPasswordTag, &password_sync_id)) { |
199 LOG(ERROR) << "Server did not create the top-level password node. We " | 205 LOG(ERROR) << "Server did not create the top-level password node. We " |
200 << "might be running against an out-of-date server."; | 206 << "might be running against an out-of-date server."; |
201 return false; | 207 return false; |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 bool PasswordModelAssociator::GetSyncIdForTaggedNode(const std::string& tag, | 278 bool PasswordModelAssociator::GetSyncIdForTaggedNode(const std::string& tag, |
273 int64* sync_id) { | 279 int64* sync_id) { |
274 sync_api::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); | 280 sync_api::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); |
275 sync_api::ReadNode sync_node(&trans); | 281 sync_api::ReadNode sync_node(&trans); |
276 if (!sync_node.InitByTagLookup(tag.c_str())) | 282 if (!sync_node.InitByTagLookup(tag.c_str())) |
277 return false; | 283 return false; |
278 *sync_id = sync_node.GetId(); | 284 *sync_id = sync_node.GetId(); |
279 return true; | 285 return true; |
280 } | 286 } |
281 | 287 |
282 bool PasswordModelAssociator::WriteToPasswordStore( | 288 SyncError PasswordModelAssociator::WriteToPasswordStore( |
283 const PasswordVector* new_passwords, | 289 const PasswordVector* new_passwords, |
284 const PasswordVector* updated_passwords, | 290 const PasswordVector* updated_passwords, |
285 const PasswordVector* deleted_passwords) { | 291 const PasswordVector* deleted_passwords) { |
286 if (new_passwords) { | 292 if (new_passwords) { |
287 for (PasswordVector::const_iterator password = new_passwords->begin(); | 293 for (PasswordVector::const_iterator password = new_passwords->begin(); |
288 password != new_passwords->end(); ++password) { | 294 password != new_passwords->end(); ++password) { |
289 password_store_->AddLoginImpl(*password); | 295 password_store_->AddLoginImpl(*password); |
290 } | 296 } |
291 } | 297 } |
292 | 298 |
293 if (updated_passwords) { | 299 if (updated_passwords) { |
294 for (PasswordVector::const_iterator password = updated_passwords->begin(); | 300 for (PasswordVector::const_iterator password = updated_passwords->begin(); |
295 password != updated_passwords->end(); ++password) { | 301 password != updated_passwords->end(); ++password) { |
296 password_store_->UpdateLoginImpl(*password); | 302 password_store_->UpdateLoginImpl(*password); |
297 } | 303 } |
298 } | 304 } |
299 | 305 |
300 if (deleted_passwords) { | 306 if (deleted_passwords) { |
301 for (PasswordVector::const_iterator password = deleted_passwords->begin(); | 307 for (PasswordVector::const_iterator password = deleted_passwords->begin(); |
302 password != deleted_passwords->end(); ++password) { | 308 password != deleted_passwords->end(); ++password) { |
303 password_store_->RemoveLoginImpl(*password); | 309 password_store_->RemoveLoginImpl(*password); |
304 } | 310 } |
305 } | 311 } |
306 | 312 |
307 if (new_passwords || updated_passwords || deleted_passwords) { | 313 if (new_passwords || updated_passwords || deleted_passwords) { |
308 // We have to notify password store observers of the change by hand since | 314 // We have to notify password store observers of the change by hand since |
309 // we use internal password store interfaces to make changes synchronously. | 315 // we use internal password store interfaces to make changes synchronously. |
310 password_store_->PostNotifyLoginsChanged(); | 316 password_store_->PostNotifyLoginsChanged(); |
311 } | 317 } |
312 return true; | 318 return SyncError(); |
313 } | 319 } |
314 | 320 |
315 // static | 321 // static |
316 void PasswordModelAssociator::CopyPassword( | 322 void PasswordModelAssociator::CopyPassword( |
317 const sync_pb::PasswordSpecificsData& password, | 323 const sync_pb::PasswordSpecificsData& password, |
318 webkit::forms::PasswordForm* new_password) { | 324 webkit::forms::PasswordForm* new_password) { |
319 new_password->scheme = | 325 new_password->scheme = |
320 static_cast<webkit::forms::PasswordForm::Scheme>(password.scheme()); | 326 static_cast<webkit::forms::PasswordForm::Scheme>(password.scheme()); |
321 new_password->signon_realm = password.signon_realm(); | 327 new_password->signon_realm = password.signon_realm(); |
322 new_password->origin = GURL(password.origin()); | 328 new_password->origin = GURL(password.origin()); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 const std::string& password_element, | 429 const std::string& password_element, |
424 const std::string& signon_realm) { | 430 const std::string& signon_realm) { |
425 return net::EscapePath(origin_url) + "|" + | 431 return net::EscapePath(origin_url) + "|" + |
426 net::EscapePath(username_element) + "|" + | 432 net::EscapePath(username_element) + "|" + |
427 net::EscapePath(username_value) + "|" + | 433 net::EscapePath(username_value) + "|" + |
428 net::EscapePath(password_element) + "|" + | 434 net::EscapePath(password_element) + "|" + |
429 net::EscapePath(signon_realm); | 435 net::EscapePath(signon_realm); |
430 } | 436 } |
431 | 437 |
432 } // namespace browser_sync | 438 } // namespace browser_sync |
OLD | NEW |