| 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 |