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#ifndef CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_H_
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#define CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_H_
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#pragma once
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/callback.h"
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/ref_counted.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/observer_list.h"
143f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/cancelable_request.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass PasswordStoreConsumer;
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass Task;
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass PasswordDataTypeController;
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass PasswordModelAssociator;
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass PasswordModelWorker;
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace webkit_glue {
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstruct PasswordForm;
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Interface for storing form passwords in a platform-specific secure way.
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// The login request/manipulation API is not threadsafe and must be used
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// from the UI thread.
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass PasswordStore
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : public base::RefCountedThreadSafe<PasswordStore>,
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      public CancelableRequestProvider {
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  typedef Callback2<Handle,
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                    const std::vector<webkit_glue::PasswordForm*>&>::Type
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetLoginsCallback;
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // PasswordForm vector elements are meant to be owned by the
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // PasswordStoreConsumer. However, if the request is canceled after the
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // allocation, then the request must take care of the deletion.
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(scr) If we can convert vector<PasswordForm*> to
46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // ScopedVector<PasswordForm>, then we can move the following class to merely
47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // a typedef. At the moment, a subclass of CancelableRequest1 is required to
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // provide a destructor, which cleans up after canceled requests by deleting
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // vector elements.
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  class GetLoginsRequest : public CancelableRequest1<
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    GetLoginsCallback, std::vector<webkit_glue::PasswordForm*> > {
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   public:
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    explicit GetLoginsRequest(GetLoginsCallback* callback);
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual ~GetLoginsRequest();
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   private:
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DISALLOW_COPY_AND_ASSIGN(GetLoginsRequest);
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // An interface used to notify clients (observers) of this object that data in
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the password store has changed. Register the observer via
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // PasswordStore::SetObserver.
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  class Observer {
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   public:
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Notifies the observer that password data changed in some way.
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual void OnLoginsChanged() = 0;
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   protected:
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    virtual ~Observer() {}
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PasswordStore();
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Reimplement this to add custom initialization. Always call this too.
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual bool Init();
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
773dff810fe0cc4962a5fa554318e9bf8bc45f5274Kristian Monsen  // Invoked from the profiles destructor to shutdown the PasswordStore.
783dff810fe0cc4962a5fa554318e9bf8bc45f5274Kristian Monsen  virtual void Shutdown();
793dff810fe0cc4962a5fa554318e9bf8bc45f5274Kristian Monsen
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Adds the given PasswordForm to the secure password store asynchronously.
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void AddLogin(const webkit_glue::PasswordForm& form);
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Updates the matching PasswordForm in the secure password store (async).
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void UpdateLogin(const webkit_glue::PasswordForm& form);
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Removes the matching PasswordForm from the secure password store (async).
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void RemoveLogin(const webkit_glue::PasswordForm& form);
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Removes all logins created in the given date range.
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void RemoveLoginsCreatedBetween(const base::Time& delete_begin,
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  const base::Time& delete_end);
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Searches for a matching PasswordForm and returns a handle so the async
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // request can be tracked. Implement the PasswordStoreConsumer interface to be
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // notified on completion.
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual Handle GetLogins(const webkit_glue::PasswordForm& form,
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           PasswordStoreConsumer* consumer);
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Gets the complete list of PasswordForms that are not blacklist entries--and
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // are thus auto-fillable--and returns a handle so the async request can be
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // tracked. Implement the PasswordStoreConsumer interface to be notified on
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // completion.
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Handle GetAutofillableLogins(PasswordStoreConsumer* consumer);
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Gets the complete list of PasswordForms that are blacklist entries, and
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // returns a handle so the async request can be tracked. Implement the
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // PasswordStoreConsumer interface to be notified on completion.
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Handle GetBlacklistLogins(PasswordStoreConsumer* consumer);
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Reports usage metrics for the database.
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void ReportMetrics();
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Adds an observer to be notified when the password store data changes.
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void AddObserver(Observer* observer);
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Removes |observer| from the observer list.
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void RemoveObserver(Observer* observer);
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected:
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  friend class base::RefCountedThreadSafe<PasswordStore>;
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  friend class browser_sync::PasswordDataTypeController;
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  friend class browser_sync::PasswordModelAssociator;
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  friend class browser_sync::PasswordModelWorker;
124731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  friend class LivePasswordsSyncTest;
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  virtual ~PasswordStore();
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Provided to allow subclasses to extend GetLoginsRequest if additional info
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // is needed between a call and its Impl.
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual GetLoginsRequest* NewGetLoginsRequest(GetLoginsCallback* callback);
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Schedule the given |task| to be run in the PasswordStore's own thread.
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void ScheduleTask(Task* task);
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // These will be run in PasswordStore's own thread.
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Synchronous implementation that reports usage metrics.
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void ReportMetricsImpl() = 0;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Synchronous implementation to add the given login.
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void AddLoginImpl(const webkit_glue::PasswordForm& form) = 0;
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Synchronous implementation to update the given login.
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void UpdateLoginImpl(const webkit_glue::PasswordForm& form) = 0;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Synchronous implementation to remove the given login.
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void RemoveLoginImpl(const webkit_glue::PasswordForm& form) = 0;
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Synchronous implementation to remove the given logins.
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void RemoveLoginsCreatedBetweenImpl(const base::Time& delete_begin,
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                              const base::Time& delete_end) = 0;
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Should find all PasswordForms with the same signon_realm. The results
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // will then be scored by the PasswordFormManager. Once they are found
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // (or not), the consumer should be notified.
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void GetLoginsImpl(GetLoginsRequest* request,
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             const webkit_glue::PasswordForm& form) = 0;
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Finds all non-blacklist PasswordForms, and notifies the consumer.
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void GetAutofillableLoginsImpl(GetLoginsRequest* request) = 0;
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Finds all blacklist PasswordForms, and notifies the consumer.
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void GetBlacklistLoginsImpl(GetLoginsRequest* request) = 0;
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Finds all non-blacklist PasswordForms, and fills the vector.
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual bool FillAutofillableLogins(
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::vector<webkit_glue::PasswordForm*>* forms) = 0;
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Finds all blacklist PasswordForms, and fills the vector.
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual bool FillBlacklistLogins(
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::vector<webkit_glue::PasswordForm*>* forms) = 0;
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Dispatches the result to the PasswordStoreConsumer on the original caller's
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // thread so the callback can be executed there.  This should be the UI
166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // thread.
167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void ForwardLoginsResult(GetLoginsRequest* request);
168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Schedule the given |func| to be run in the PasswordStore's own thread with
170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // responses delivered to |consumer| on the current thread.
171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  template<typename BackendFunc>
172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Handle Schedule(BackendFunc func, PasswordStoreConsumer* consumer);
173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Schedule the given |func| to be run in the PasswordStore's own thread with
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // argument |a| and responses delivered to |consumer| on the current thread.
176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  template<typename BackendFunc, typename ArgA>
177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Handle Schedule(BackendFunc func, PasswordStoreConsumer* consumer,
178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                  const ArgA& a);
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Wrapper method called on the destination thread (DB for non-mac) that calls
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the method specified in |task| and then calls back into the source thread
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // to notify observers that the password store may have been modified via
184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // NotifyLoginsChanged(). Note that there is no guarantee that the called
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // method will actually modify the password store data. |task| may not be
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // NULL. This method owns and will delete |task|.
187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void WrapModificationTask(Task* task);
188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Post a message to the UI thread to run NotifyLoginsChanged(). Called by
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // WrapModificationTask() above, and split out as a separate method so that
191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // password sync can call it as well after synchronously updating the password
192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // store.
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void PostNotifyLoginsChanged();
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Called by WrapModificationTask() once the underlying data-modifying
196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // operation has been performed. Notifies observers that password store data
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // may have been changed.
198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  void NotifyLoginsChanged();
199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The observers.
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ObserverList<Observer> observers_;
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(PasswordStore);
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif  // CHROME_BROWSER_PASSWORD_MANAGER_PASSWORD_STORE_H_
207