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