1 // Copyright 2015 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 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_ANDROID_AFFILIATION_SERVICE_H_
6 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_ANDROID_AFFILIATION_SERVICE_H_
7 
8 #include <string>
9 
10 #include "base/callback.h"
11 #include "base/macros.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/sequence_checker.h"
15 #include "components/keyed_service/core/keyed_service.h"
16 #include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
17 
18 namespace base {
19 class FilePath;
20 class SequencedTaskRunner;
21 }  // namespace base
22 
23 namespace network {
24 class NetworkConnectionTracker;
25 class SharedURLLoaderFactory;
26 }  // namespace network
27 
28 namespace password_manager {
29 class AffiliationBackend;
30 
31 // A service that can be used to query the list of facets that are affiliated
32 // with a given facet, i.e., facets that belong to the same logical application.
33 // See affiliation_utils.h for details of what this means.
34 //
35 // The service must be accessed from the UI thread, and it can be utilized in
36 // two ways:
37 //
38 //   1.) On-demand fetching: For the one-off query that wishes to learn
39 //       affiliations of facet X when (potentially) issuing an on-demand
40 //       network request to the Affiliation API containing the URI of facet X
41 //       is acceptable from the privacy and/or performance perspective.
42 //
43 //       This mode of operation is achieved by invoking
44 //       GetAffiliationsAndBranding() with
45 //       StrategyOnCacheMiss::FETCH_OVER_NETWORK.
46 //
47 //   2.) Proactive fetching: For the compound query that is concerned with
48 //       checking, over time, whether or not each element in a sequence of
49 //       facets, W_1, W_2, ..., W_n, is affiliated with a fixed facet Y; and
50 //       when it is desired, for privacy and/or performance reasons, that only
51 //       facet Y be looked up against the Affiliation API and that subsequent
52 //       requests regarding each W_i not trigger additional requests.
53 //
54 //       This mode of operation can be useful when, for example, the password
55 //       manager has credentials stored for facet Y and wishes to check, for
56 //       each visited web site W_i, whether these credentials should be offered
57 //       to be autofilled onto W_i.
58 //
59 //       Example code:
60 //
61 //       class ExampleAffiliatedCredentialFiller
62 //           : public base::SupportsWeakPtr<...> {
63 //        public:
64 //         ExampleAffiliatedCredentialFiller(AndroidAffiliationService* service,
65 //                                           const FacetURI& y)
66 //             : service_(service), y_(y) {
67 //           cancel_handle_ = service_->Prefetch(y_, base::Time::Max());
68 //         }
69 //
70 //         ~ExampleAffiliatedCredentialFiller() { cancel_handle_.Run(); }
71 //
72 //         void ShouldFillInto(const FacetURI& wi, FillDelegate* delegate) {
73 //           service_->GetAffiliationsAndBranding(wi, StrategyOnCacheMiss::FAIL,
74 //               base::BindOnce(
75 //                   &ExampleAffiliatedCredentialFiller::OnAffiliationResult,
76 //                   AsWeakPtr(),
77 //                   delegate));
78 //         }
79 //
80 //         void OnAffiliationResult(FillDelegate* delegate,
81 //                                  const AffiliatedFacets& results,
82 //                                  bool success) {
83 //           if (success && std::count(results.begin(), results.end(), y_))
84 //             delegate->FillCredentialsFor(y_);
85 //         }
86 //
87 //        private:
88 //         AndroidAffiliationService* service_;
89 //         const FacetURI& y_;
90 //         CancelPrefetchingHandle cancel_handle_;
91 //       };
92 class AndroidAffiliationService : public KeyedService {
93  public:
94   using ResultCallback =
95       base::OnceCallback<void(const AffiliatedFacets& /* results */,
96                               bool /* success */)>;
97 
98   // Controls whether to send a network request or fail on a cache miss.
99   enum class StrategyOnCacheMiss { FETCH_OVER_NETWORK, FAIL };
100 
101   // The |backend_task_runner| should be a task runner corresponding to a thread
102   // that can take blocking I/O, and is normally Chrome's DB thread.
103   explicit AndroidAffiliationService(
104       scoped_refptr<base::SequencedTaskRunner> backend_task_runner);
105   ~AndroidAffiliationService() override;
106 
107   // Initializes the service by creating its backend and transferring it to the
108   // thread corresponding to |backend_task_runner_|.
109   void Initialize(
110       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
111       network::NetworkConnectionTracker* network_connection_tracker,
112       const base::FilePath& db_path);
113 
114   // Looks up facets affiliated with the facet identified by |facet_uri| and
115   // branding information, and invokes |result_callback| with the results. It is
116   // guaranteed that the results will contain one facet with URI equal to
117   // |facet_uri| when |result_callback| is invoked with success set to true.
118   //
119   // If the local cache contains fresh affiliation and branding information for
120   // |facet_uri|, the request will be served from cache. Otherwise,
121   // |cache_miss_policy| controls whether to issue an on-demand network request,
122   // or to fail the request without fetching.
123   virtual void GetAffiliationsAndBranding(
124       const FacetURI& facet_uri,
125       StrategyOnCacheMiss cache_miss_strategy,
126       ResultCallback result_callback);
127 
128   // Prefetches affiliation information for the facet identified by |facet_uri|,
129   // and keeps the information fresh by periodic re-fetches (as needed) until
130   // the clock strikes |keep_fresh_until| (exclusive), until a matching call to
131   // CancelPrefetch(), or until Chrome is shut down, whichever is sooner. It is
132   // a supported use-case to pass base::Time::Max() as |keep_fresh_until|.
133   //
134   // Canceling can be useful when a password is deleted, so that resources are
135   // no longer wasted on repeatedly refreshing affiliation information. Note
136   // that canceling will not blow away data already stored in the cache unless
137   // it becomes stale.
138   virtual void Prefetch(const FacetURI& facet_uri,
139                         const base::Time& keep_fresh_until);
140 
141   // Cancels the corresponding prefetch command, i.e., the one issued for the
142   // same |facet_uri| and with the same |keep_fresh_until|.
143   virtual void CancelPrefetch(const FacetURI& facet_uri,
144                               const base::Time& keep_fresh_until);
145 
146   // Wipes results of on-demand fetches and expired prefetches from the cache,
147   // but retains information corresponding to facets that are being kept fresh.
148   // As no required data is deleted, there will be no network requests directly
149   // triggered by this call. It will only potentially remove data
150   // corresponding to the given |facet_uri|, but still only as long as the
151   // data is no longer needed.
152   virtual void TrimCacheForFacetURI(const FacetURI& facet_uri);
153 
GetBackendForTesting()154   AffiliationBackend* GetBackendForTesting() { return backend_; }
155 
156  private:
157   // The backend, owned by this AndroidAffiliationService instance, but living
158   // on the DB thread. It will be deleted asynchronously during shutdown on the
159   // DB thread, so it will outlive |this| along with all its in-flight tasks.
160   AffiliationBackend* backend_;
161 
162   // TaskRunner to be used to run the |backend_|.
163   scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
164 
165   SEQUENCE_CHECKER(sequence_checker_);
166   base::WeakPtrFactory<AndroidAffiliationService> weak_ptr_factory_{this};
167 
168   DISALLOW_COPY_AND_ASSIGN(AndroidAffiliationService);
169 };
170 
171 }  // namespace password_manager
172 
173 #endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_ANDROID_AFFILIATION_SERVICE_H_
174