1// Copyright 2020 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#import "ios/web_view/internal/passwords/web_view_account_password_store_factory.h"
6
7#include <memory>
8#include <utility>
9
10#include "base/bind.h"
11#include "base/callback_helpers.h"
12#include "base/task/post_task.h"
13#include "components/keyed_service/ios/browser_state_dependency_manager.h"
14#include "components/password_manager/core/browser/login_database.h"
15#include "components/password_manager/core/browser/password_manager_constants.h"
16#include "components/password_manager/core/browser/password_manager_util.h"
17#include "components/password_manager/core/browser/password_store_default.h"
18#include "components/password_manager/core/browser/password_store_factory_util.h"
19#include "components/password_manager/core/common/password_manager_features.h"
20#include "components/prefs/pref_service.h"
21#include "ios/web/public/thread/web_task_traits.h"
22#include "ios/web/public/thread/web_thread.h"
23#include "ios/web_view/internal/webdata_services/web_view_web_data_service_wrapper_factory.h"
24
25#if !defined(__has_feature) || !__has_feature(objc_arc)
26#error "This file requires ARC support."
27#endif
28
29NSNotificationName const CWVPasswordStoreSyncToggledNotification =
30    @"CWVPasswordStoreSyncToggledNotification";
31NSString* const CWVPasswordStoreNotificationBrowserStateKey =
32    @"CWVPasswordStoreNotificationBrowserStateKey";
33
34namespace ios_web_view {
35
36namespace {
37
38void UpdateFormManager(WebViewBrowserState* browser_state) {
39  NSValue* wrapped_browser_state = [NSValue valueWithPointer:browser_state];
40  [NSNotificationCenter.defaultCenter
41      postNotificationName:CWVPasswordStoreSyncToggledNotification
42                    object:nil
43                  userInfo:@{
44                    CWVPasswordStoreNotificationBrowserStateKey :
45                        wrapped_browser_state
46                  }];
47}
48
49void SyncEnabledOrDisabled(WebViewBrowserState* browser_state) {
50  base::PostTask(FROM_HERE, {web::WebThread::UI},
51                 base::BindOnce(&UpdateFormManager, browser_state));
52}
53
54}  // namespace
55
56// static
57scoped_refptr<password_manager::PasswordStore>
58WebViewAccountPasswordStoreFactory::GetForBrowserState(
59    WebViewBrowserState* browser_state,
60    ServiceAccessType access_type) {
61  if (!base::FeatureList::IsEnabled(
62          password_manager::features::kEnablePasswordsAccountStorage)) {
63    return nullptr;
64  }
65
66  // |browser_state| always gets redirected to a the recording version in
67  // |GetBrowserStateToUse|.
68  if (access_type == ServiceAccessType::IMPLICIT_ACCESS &&
69      browser_state->IsOffTheRecord()) {
70    return nullptr;
71  }
72
73  return base::WrapRefCounted(static_cast<password_manager::PasswordStore*>(
74      GetInstance()->GetServiceForBrowserState(browser_state, true).get()));
75}
76
77// static
78WebViewAccountPasswordStoreFactory*
79WebViewAccountPasswordStoreFactory::GetInstance() {
80  static base::NoDestructor<WebViewAccountPasswordStoreFactory> instance;
81  return instance.get();
82}
83
84WebViewAccountPasswordStoreFactory::WebViewAccountPasswordStoreFactory()
85    : RefcountedBrowserStateKeyedServiceFactory(
86          "AccountPasswordStore",
87          BrowserStateDependencyManager::GetInstance()) {
88  DependsOn(WebViewWebDataServiceWrapperFactory::GetInstance());
89}
90
91WebViewAccountPasswordStoreFactory::~WebViewAccountPasswordStoreFactory() {}
92
93scoped_refptr<RefcountedKeyedService>
94WebViewAccountPasswordStoreFactory::BuildServiceInstanceFor(
95    web::BrowserState* context) const {
96  DCHECK(base::FeatureList::IsEnabled(
97      password_manager::features::kEnablePasswordsAccountStorage));
98
99  WebViewBrowserState* browser_state =
100      WebViewBrowserState::FromBrowserState(context);
101
102  std::unique_ptr<password_manager::LoginDatabase> login_db(
103      password_manager::CreateLoginDatabaseForAccountStorage(
104          browser_state->GetStatePath()));
105
106  scoped_refptr<password_manager::PasswordStore> ps =
107      new password_manager::PasswordStoreDefault(std::move(login_db));
108  if (!ps->Init(browser_state->GetPrefs(),
109                base::BindRepeating(&SyncEnabledOrDisabled, browser_state))) {
110    // TODO(crbug.com/479725): Remove the LOG once this error is visible in the
111    // UI.
112    LOG(WARNING) << "Could not initialize password store.";
113    return nullptr;
114  }
115
116  return ps;
117}
118
119web::BrowserState* WebViewAccountPasswordStoreFactory::GetBrowserStateToUse(
120    web::BrowserState* context) const {
121  WebViewBrowserState* browser_state =
122      WebViewBrowserState::FromBrowserState(context);
123  return browser_state->GetRecordingBrowserState();
124}
125
126bool WebViewAccountPasswordStoreFactory::ServiceIsNULLWhileTesting() const {
127  return true;
128}
129
130}  // namespace ios_web_view
131