Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / glue / password_model_associator.cc
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.
4
5 #include "chrome/browser/sync/glue/password_model_associator.h"
6
7 #include <set>
8
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"
24
25 using base::UTF8ToUTF16;
26 using base::UTF16ToUTF8;
27 using content::BrowserThread;
28
29 namespace {
30
31 void AppendChanges(const PasswordStoreChangeList& new_changes,
32                    PasswordStoreChangeList* all_changes) {
33   all_changes->insert(all_changes->end(),
34                       new_changes.begin(),
35                       new_changes.end());
36 }
37
38 }  // namespace
39
40 namespace browser_sync {
41
42 const char kPasswordTag[] = "google_chrome_passwords";
43
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());
56 }
57
58 PasswordModelAssociator::~PasswordModelAssociator() {
59   DCHECK(thread_checker_.CalledOnValidThread());
60 }
61
62 syncer::SyncError PasswordModelAssociator::AssociateModels(
63     syncer::SyncMergeResult* local_merge_result,
64     syncer::SyncMergeResult* syncer_merge_result) {
65   DCHECK(expected_loop_ == base::MessageLoop::current());
66
67   PasswordVector new_passwords;
68   PasswordVector updated_passwords;
69   {
70     base::AutoLock lock(association_lock_);
71     if (abort_association_requested_)
72       return syncer::SyncError();
73
74     CHECK(password_store_.get());
75
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);
83
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.",
92                                model_type());
93     }
94
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(
101           FROM_HERE,
102           "Server did not create the top-level password node. We "
103           "might be running against an out-of-date server.",
104           model_type());
105     }
106
107     for (std::vector<autofill::PasswordForm*>::iterator ix =
108              passwords.begin();
109          ix != passwords.end(); ++ix) {
110       std::string tag = MakeTag(**ix);
111
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));
118
119         autofill::PasswordForm new_password;
120
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(
127                 FROM_HERE,
128                 "Failed to edit password sync node.",
129                 model_type());
130           }
131           WriteToSyncNode(new_password, &write_node);
132           updated_passwords.push_back(new_password);
133         }
134
135         Associate(&tag, node.GetId());
136       } else {
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(
143               FROM_HERE,
144               "Failed to create password sync node.",
145               model_type());
146         }
147
148         WriteToSyncNode(**ix, &node);
149
150         Associate(&tag, node.GetId());
151       }
152
153       current_passwords.insert(tag);
154     }
155
156     STLDeleteElements(&passwords);
157
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(
164             FROM_HERE,
165             "Failed to fetch child node.",
166             model_type());
167       }
168       const sync_pb::PasswordSpecificsData& password =
169           sync_child_node.GetPasswordSpecifics();
170       std::string tag = MakeTag(password);
171
172       // The password only exists on the server.  Add it to the local
173       // model.
174       if (current_passwords.find(tag) == current_passwords.end()) {
175         autofill::PasswordForm new_password;
176
177         CopyPassword(password, &new_password);
178         Associate(&tag, sync_child_node.GetId());
179         new_passwords.push_back(new_password);
180       }
181
182       sync_child_id = sync_child_node.GetSuccessorId();
183     }
184   }
185
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,
190                               &updated_passwords,
191                               NULL);
192 }
193
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.";
203       return false;
204     }
205     sync_node.Tombstone();
206   }
207
208   id_map_.clear();
209   id_map_inverse_.clear();
210   return true;
211 }
212
213 syncer::SyncError PasswordModelAssociator::DisassociateModels() {
214   id_map_.clear();
215   id_map_inverse_.clear();
216   return syncer::SyncError();
217 }
218
219 bool PasswordModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
220   DCHECK(has_nodes);
221   *has_nodes = false;
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.";
226     return false;
227   }
228   syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare());
229
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.";
235     return false;
236   }
237
238   // The sync model has user created nodes if the password folder has any
239   // children.
240   *has_nodes = password_node.HasChildren();
241   return true;
242 }
243
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;
249 }
250
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);
256 }
257
258 const std::string* PasswordModelAssociator::GetChromeNodeFromSyncId(
259     int64 sync_id) {
260   return NULL;
261 }
262
263 bool PasswordModelAssociator::InitSyncNodeFromChromeId(
264     const std::string& node_id,
265     syncer::BaseNode* sync_node) {
266   return false;
267 }
268
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;
273 }
274
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;
283 }
284
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())
289     return;
290   CHECK(id_map_.erase(iter->second));
291   id_map_inverse_.erase(iter);
292 }
293
294 bool PasswordModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
295                                                      int64* sync_id) {
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)
299     return false;
300   *sync_id = sync_node.GetId();
301   return true;
302 }
303
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();
311
312   CHECK(password_store_.get());
313
314   PasswordStoreChangeList changes;
315   if (new_passwords) {
316     for (PasswordVector::const_iterator password = new_passwords->begin();
317          password != new_passwords->end(); ++password) {
318       AppendChanges(password_store_->AddLoginImpl(*password),
319                     &changes);
320     }
321   }
322
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),
327                     &changes);
328     }
329   }
330
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),
335                     &changes);
336     }
337   }
338
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);
342
343   return syncer::SyncError();
344 }
345
346 // static
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();
369 }
370
371 // static
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);
377
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) {
394     return false;
395   }
396
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;
401   } else {
402     CopyPassword(password, new_password);
403   }
404
405   return true;
406 }
407
408 // static
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);
425
426   node->SetPasswordSpecifics(password);
427 }
428
429 // static
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);
437 }
438
439 // static
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());
447 }
448
449 // static
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);
461 }
462
463 }  // namespace browser_sync