1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/glue/password_model_associator.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/password_manager/password_store.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/engine/syncapi.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/profile_sync_service.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/protocol/password_specifics.pb.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/escape.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "webkit/glue/password_form.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char kPasswordTag[] = "google_chrome_passwords";
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochPasswordModelAssociator::PasswordModelAssociator(
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ProfileSyncService* sync_service,
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PasswordStore* password_store)
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : sync_service_(sync_service),
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password_store_(password_store),
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password_node_id_(sync_api::kInvalidId),
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      abort_association_pending_(false),
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      expected_loop_(MessageLoop::current()) {
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(sync_service_);
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(password_store_);
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_MACOSX)
33731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
35731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39513209b27ff55e2841eac0e4120199c23acce758Ben MurdochPasswordModelAssociator::~PasswordModelAssociator() {}
40513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool PasswordModelAssociator::AssociateModels() {
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_loop_ == MessageLoop::current());
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
4472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock lock(abort_association_pending_lock_);
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    abort_association_pending_ = false;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We must not be holding a transaction when we interact with the password
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // store, as it can post tasks to the UI thread which can itself be blocked
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // on our transaction, resulting in deadlock. (http://crbug.com/70658)
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<webkit_glue::PasswordForm*> passwords;
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!password_store_->FillAutofillableLogins(&passwords) ||
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      !password_store_->FillBlacklistLogins(&passwords)) {
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    STLDeleteElements(&passwords);
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Could not get the password entries.";
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::set<std::string> current_passwords;
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PasswordVector new_passwords;
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PasswordVector updated_passwords;
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  {
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    sync_api::WriteTransaction trans(sync_service_->GetUserShare());
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    sync_api::ReadNode password_root(&trans);
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!password_root.InitByTagLookup(kPasswordTag)) {
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      LOG(ERROR) << "Server did not create the top-level password node. We "
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                 << "might be running against an out-of-date server.";
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (std::vector<webkit_glue::PasswordForm*>::iterator ix =
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen             passwords.begin();
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         ix != passwords.end(); ++ix) {
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (IsAbortPending())
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return false;
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::string tag = MakeTag(**ix);
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      sync_api::ReadNode node(&trans);
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (node.InitByClientTagLookup(syncable::PASSWORDS, tag)) {
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        const sync_pb::PasswordSpecificsData& password =
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            node.GetPasswordSpecifics();
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        DCHECK_EQ(tag, MakeTag(password));
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        webkit_glue::PasswordForm new_password;
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (MergePasswords(password, **ix, &new_password)) {
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          sync_api::WriteNode write_node(&trans);
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          if (!write_node.InitByClientTagLookup(syncable::PASSWORDS, tag)) {
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            STLDeleteElements(&passwords);
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            LOG(ERROR) << "Failed to edit password sync node.";
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            return false;
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          }
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          WriteToSyncNode(new_password, &write_node);
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          updated_passwords.push_back(new_password);
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        Associate(&tag, node.GetId());
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else {
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        sync_api::WriteNode node(&trans);
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (!node.InitUniqueByCreation(syncable::PASSWORDS,
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       password_root, tag)) {
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          STLDeleteElements(&passwords);
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          LOG(ERROR) << "Failed to create password sync node.";
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return false;
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        WriteToSyncNode(**ix, &node);
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        Associate(&tag, node.GetId());
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      current_passwords.insert(tag);
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    STLDeleteElements(&passwords);
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int64 sync_child_id = password_root.GetFirstChildId();
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    while (sync_child_id != sync_api::kInvalidId) {
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      sync_api::ReadNode sync_child_node(&trans);
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!sync_child_node.InitByIdLookup(sync_child_id)) {
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        LOG(ERROR) << "Failed to fetch child node.";
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return false;
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      const sync_pb::PasswordSpecificsData& password =
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          sync_child_node.GetPasswordSpecifics();
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::string tag = MakeTag(password);
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // The password only exists on the server.  Add it to the local
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // model.
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (current_passwords.find(tag) == current_passwords.end()) {
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        webkit_glue::PasswordForm new_password;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        CopyPassword(password, &new_password);
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        Associate(&tag, sync_child_node.GetId());
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        new_passwords.push_back(new_password);
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      sync_child_id = sync_child_node.GetSuccessorId();
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We must not be holding a transaction when we interact with the password
143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // store, as it can post tasks to the UI thread which can itself be blocked
144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // on our transaction, resulting in deadlock. (http://crbug.com/70658)
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!WriteToPasswordStore(&new_passwords, &updated_passwords, NULL)) {
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Failed to write passwords.";
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool PasswordModelAssociator::DeleteAllNodes(
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_api::WriteTransaction* trans) {
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_loop_ == MessageLoop::current());
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (PasswordToSyncIdMap::iterator node_id = id_map_.begin();
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       node_id != id_map_.end(); ++node_id) {
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_api::WriteNode sync_node(trans);
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!sync_node.InitByIdLookup(node_id->second)) {
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Typed url node lookup failed.";
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sync_node.Remove();
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_.clear();
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_inverse_.clear();
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool PasswordModelAssociator::DisassociateModels() {
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_.clear();
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_inverse_.clear();
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool PasswordModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) {
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(has_nodes);
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *has_nodes = false;
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 password_sync_id;
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetSyncIdForTaggedNode(kPasswordTag, &password_sync_id)) {
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Server did not create the top-level password node. We "
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << "might be running against an out-of-date server.";
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
18672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  sync_api::ReadTransaction trans(sync_service_->GetUserShare());
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_api::ReadNode password_node(&trans);
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!password_node.InitByIdLookup(password_sync_id)) {
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "Server did not create the top-level password node. We "
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               << "might be running against an out-of-date server.";
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The sync model has user created nodes if the password folder has any
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // children.
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *has_nodes = sync_api::kInvalidId != password_node.GetFirstChildId();
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordModelAssociator::AbortAssociation() {
202731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
20372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(abort_association_pending_lock_);
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  abort_association_pending_ = true;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool PasswordModelAssociator::CryptoReadyIfNecessary() {
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We only access the cryptographer while holding a transaction.
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  sync_api::ReadTransaction trans(sync_service_->GetUserShare());
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We always encrypt passwords, so no need to check if encryption is enabled.
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return sync_service_->IsCryptographerReady(&trans);
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
21421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenconst std::string* PasswordModelAssociator::GetChromeNodeFromSyncId(
21521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    int64 sync_id) {
21621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return NULL;
21721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
21821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
21921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool PasswordModelAssociator::InitSyncNodeFromChromeId(
22021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const std::string& node_id,
22121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    sync_api::BaseNode* sync_node) {
22221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return false;
22321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
22421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool PasswordModelAssociator::IsAbortPending() {
22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(abort_association_pending_lock_);
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return abort_association_pending_;
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint64 PasswordModelAssociator::GetSyncIdFromChromeId(
23121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const std::string& password) {
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PasswordToSyncIdMap::const_iterator iter = id_map_.find(password);
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return iter == id_map_.end() ? sync_api::kInvalidId : iter->second;
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordModelAssociator::Associate(
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string* password, int64 sync_id) {
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_loop_ == MessageLoop::current());
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(sync_api::kInvalidId, sync_id);
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(id_map_.find(*password) == id_map_.end());
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(id_map_inverse_.find(sync_id) == id_map_inverse_.end());
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_[*password] = sync_id;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_inverse_[sync_id] = *password;
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordModelAssociator::Disassociate(int64 sync_id) {
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(expected_loop_ == MessageLoop::current());
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SyncIdToPasswordMap::iterator iter = id_map_inverse_.find(sync_id);
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (iter == id_map_inverse_.end())
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(id_map_.erase(iter->second));
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  id_map_inverse_.erase(iter);
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool PasswordModelAssociator::GetSyncIdForTaggedNode(const std::string& tag,
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                     int64* sync_id) {
25772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  sync_api::ReadTransaction trans(sync_service_->GetUserShare());
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_api::ReadNode sync_node(&trans);
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!sync_node.InitByTagLookup(tag.c_str()))
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *sync_id = sync_node.GetId();
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool PasswordModelAssociator::WriteToPasswordStore(
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         const PasswordVector* new_passwords,
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         const PasswordVector* updated_passwords,
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         const PasswordVector* deleted_passwords) {
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (new_passwords) {
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (PasswordVector::const_iterator password = new_passwords->begin();
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         password != new_passwords->end(); ++password) {
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password_store_->AddLoginImpl(*password);
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (updated_passwords) {
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (PasswordVector::const_iterator password = updated_passwords->begin();
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         password != updated_passwords->end(); ++password) {
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password_store_->UpdateLoginImpl(*password);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (deleted_passwords) {
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (PasswordVector::const_iterator password = deleted_passwords->begin();
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         password != deleted_passwords->end(); ++password) {
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password_store_->RemoveLoginImpl(*password);
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (new_passwords || updated_passwords || deleted_passwords) {
291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // We have to notify password store observers of the change by hand since
292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // we use internal password store interfaces to make changes synchronously.
293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    password_store_->PostNotifyLoginsChanged();
294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordModelAssociator::CopyPassword(
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        const sync_pb::PasswordSpecificsData& password,
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        webkit_glue::PasswordForm* new_password) {
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->scheme =
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      static_cast<webkit_glue::PasswordForm::Scheme>(password.scheme());
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->signon_realm = password.signon_realm();
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->origin = GURL(password.origin());
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->action = GURL(password.action());
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->username_element =
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF8ToUTF16(password.username_element());
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->password_element =
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF8ToUTF16(password.password_element());
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->username_value =
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF8ToUTF16(password.username_value());
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->password_value =
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF8ToUTF16(password.password_value());
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->ssl_valid = password.ssl_valid();
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->preferred = password.preferred();
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->date_created =
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      base::Time::FromInternalValue(password.date_created());
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  new_password->blacklisted_by_user =
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password.blacklisted();
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool PasswordModelAssociator::MergePasswords(
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        const sync_pb::PasswordSpecificsData& password,
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        const webkit_glue::PasswordForm& password_form,
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        webkit_glue::PasswordForm* new_password) {
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(new_password);
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (password.scheme() == password_form.scheme &&
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password_form.signon_realm == password.signon_realm() &&
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password_form.origin.spec() == password.origin() &&
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password_form.action.spec() == password.action() &&
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF16ToUTF8(password_form.username_element) ==
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          password.username_element() &&
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF16ToUTF8(password_form.password_element) ==
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          password.password_element() &&
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF16ToUTF8(password_form.username_value) ==
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          password.username_value() &&
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      UTF16ToUTF8(password_form.password_value) ==
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          password.password_value() &&
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password.ssl_valid() == password_form.ssl_valid &&
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password.preferred() == password_form.preferred &&
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password.date_created() == password_form.date_created.ToInternalValue() &&
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password.blacklisted() == password_form.blacklisted_by_user) {
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the passwords differ, we take the one that was created more recently.
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (base::Time::FromInternalValue(password.date_created()) <=
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      password_form.date_created) {
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *new_password = password_form;
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CopyPassword(password, new_password);
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PasswordModelAssociator::WriteToSyncNode(
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         const webkit_glue::PasswordForm& password_form,
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         sync_api::WriteNode* node) {
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sync_pb::PasswordSpecificsData password;
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_scheme(password_form.scheme);
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_signon_realm(password_form.signon_realm);
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_origin(password_form.origin.spec());
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_action(password_form.action.spec());
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_username_element(UTF16ToUTF8(password_form.username_element));
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_password_element(UTF16ToUTF8(password_form.password_element));
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_username_value(UTF16ToUTF8(password_form.username_value));
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_password_value(UTF16ToUTF8(password_form.password_value));
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_ssl_valid(password_form.ssl_valid);
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_preferred(password_form.preferred);
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_date_created(password_form.date_created.ToInternalValue());
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  password.set_blacklisted(password_form.blacklisted_by_user);
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  node->SetPasswordSpecifics(password);
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string PasswordModelAssociator::MakeTag(
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                const webkit_glue::PasswordForm& password) {
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return MakeTag(password.origin.spec(),
3853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 UTF16ToUTF8(password.username_element),
3863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 UTF16ToUTF8(password.username_value),
3873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 UTF16ToUTF8(password.password_element),
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 password.signon_realm);
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string PasswordModelAssociator::MakeTag(
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                const sync_pb::PasswordSpecificsData& password) {
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return MakeTag(password.origin(),
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 password.username_element(),
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 password.username_value(),
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 password.password_element(),
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 password.signon_realm());
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string PasswordModelAssociator::MakeTag(
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& origin_url,
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& username_element,
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& username_value,
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& password_element,
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& signon_realm) {
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return EscapePath(origin_url) + "|" +
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         EscapePath(username_element) + "|" +
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         EscapePath(username_value) + "|" +
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         EscapePath(password_element) + "|" +
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         EscapePath(signon_realm);
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace browser_sync
416