1 // Copyright 2014 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_GCM_DRIVER_GCM_ACCOUNT_TRACKER_H_
6 #define COMPONENTS_GCM_DRIVER_GCM_ACCOUNT_TRACKER_H_
7 
8 #include <stddef.h>
9 
10 #include <map>
11 #include <memory>
12 #include <string>
13 #include <vector>
14 
15 #include "base/macros.h"
16 #include "components/gcm_driver/account_tracker.h"
17 #include "components/gcm_driver/gcm_client.h"
18 #include "components/gcm_driver/gcm_connection_observer.h"
19 #include "components/signin/public/identity_manager/access_token_fetcher.h"
20 
21 namespace signin {
22 struct AccessTokenInfo;
23 class IdentityManager;
24 }  // namespace signin
25 
26 namespace base {
27 class Time;
28 }
29 
30 namespace gcm {
31 
32 class GCMDriver;
33 
34 // Class for reporting back which accounts are signed into. It is only meant to
35 // be used when the user is signed into sync.
36 //
37 // This class makes a check for tokens periodically, to make sure the user is
38 // still logged into the profile, so that in the case that the user is not, we
39 // can immediately report that to the GCM and stop messages addressed to that
40 // user from ever reaching Chrome.
41 class GCMAccountTracker : public AccountTracker::Observer,
42                           public GCMConnectionObserver {
43  public:
44   // State of the account.
45   // Allowed transitions:
46   // TOKEN_NEEDED - account info was created.
47   // TOKEN_NEEDED -> GETTING_TOKEN - access token was requested.
48   // GETTING_TOKEN -> TOKEN_NEEDED - access token fetching failed.
49   // GETTING_TOKEN -> TOKEN_PRESENT - access token fetching succeeded.
50   // GETTING_TOKEN -> ACCOUNT_REMOVED - account was removed.
51   // TOKEN_NEEDED -> ACCOUNT_REMOVED - account was removed.
52   // TOKEN_PRESENT -> ACCOUNT_REMOVED - account was removed.
53   enum AccountState {
54     TOKEN_NEEDED,     // Needs a token (AccountInfo was recently created or
55                       // token request failed).
56     GETTING_TOKEN,    // There is a pending token request.
57     TOKEN_PRESENT,    // We have a token for the account.
58     ACCOUNT_REMOVED,  // Account was removed, and we didn't report it yet.
59   };
60 
61   // Stores necessary account information and state of token fetching.
62   struct AccountInfo {
63     AccountInfo(const std::string& email, AccountState state);
64     ~AccountInfo();
65 
66     // Email address of the tracked account.
67     std::string email;
68     // OAuth2 access token, when |state| is TOKEN_PRESENT.
69     std::string access_token;
70     // Expiration time of the access tokens.
71     base::Time expiration_time;
72     // Status of the token fetching.
73     AccountState state;
74   };
75 
76   // |account_tracker| is used to deliver information about the accounts present
77   // in the browser context to |driver|.
78   GCMAccountTracker(std::unique_ptr<AccountTracker> account_tracker,
79                     signin::IdentityManager* identity_manager,
80                     GCMDriver* driver);
81   ~GCMAccountTracker() override;
82 
83   // Shuts down the tracker ensuring a proper clean up. After Shutdown() is
84   // called Start() and Stop() should no longer be used. Must be called before
85   // destruction.
86   void Shutdown();
87 
88   // Starts tracking accounts.
89   void Start();
90 
91   // Gets the number of pending token requests. Only used for testing.
get_pending_token_request_count()92   size_t get_pending_token_request_count() const {
93     return pending_token_requests_.size();
94   }
95 
96  private:
97   friend class GCMAccountTrackerTest;
98 
99   // Maps account keys to account states. Keyed by account_id as used by
100   // IdentityManager.
101   typedef std::map<CoreAccountId, AccountInfo> AccountInfos;
102 
103   // AccountTracker::Observer overrides.
104   void OnAccountSignInChanged(const CoreAccountInfo& account,
105                               bool is_signed_in) override;
106 
107   void OnAccessTokenFetchCompleteForAccount(
108       CoreAccountId account_id,
109       GoogleServiceAuthError error,
110       signin::AccessTokenInfo access_token_info);
111 
112   // GCMConnectionObserver overrides.
113   void OnConnected(const net::IPEndPoint& ip_endpoint) override;
114   void OnDisconnected() override;
115 
116   // Schedules token reporting.
117   void ScheduleReportTokens();
118   // Report the list of accounts with OAuth2 tokens back using the |callback_|
119   // function. If there are token requests in progress, do nothing.
120   void ReportTokens();
121   // Verify that all of the tokens are ready to be passed down to the GCM
122   // Driver, e.g. none of them has expired or is missing. Returns true if not
123   // all tokens are valid and a fetching yet more tokens is required.
124   void SanitizeTokens();
125   // Indicates whether token reporting is required, either because it is due, or
126   // some of the accounts were removed.
127   bool IsTokenReportingRequired() const;
128   // Indicates whether there are tokens that still need fetching.
129   bool IsTokenFetchingRequired() const;
130   // Gets the time until next token reporting.
131   base::TimeDelta GetTimeToNextTokenReporting() const;
132   // Checks on all known accounts, and calls GetToken(..) for those with
133   // |state == TOKEN_NEEDED|.
134   void GetAllNeededTokens();
135   // Starts fetching the OAuth2 token for the GCM group scope.
136   void GetToken(AccountInfos::iterator& account_iter);
137 
138   // Handling of actual sign in and sign out for accounts.
139   void OnAccountSignedIn(const CoreAccountInfo& account);
140   void OnAccountSignedOut(const CoreAccountInfo& account);
141 
142   // Account tracker.
143   std::unique_ptr<AccountTracker> account_tracker_;
144 
145   signin::IdentityManager* identity_manager_;
146 
147   GCMDriver* driver_;
148 
149   // State of the account.
150   AccountInfos account_infos_;
151 
152   // Indicates whether shutdown has been called.
153   bool shutdown_called_;
154 
155   // Stores the ongoing access token fetchers for deletion either upon
156   // completion or upon signout of the account for which the request is being
157   // made.
158   using AccountIDToTokenFetcherMap =
159       std::map<CoreAccountId, std::unique_ptr<signin::AccessTokenFetcher>>;
160   AccountIDToTokenFetcherMap pending_token_requests_;
161 
162   // Creates weak pointers used to postpone reporting tokens. See
163   // ScheduleReportTokens.
164   base::WeakPtrFactory<GCMAccountTracker> reporting_weak_ptr_factory_{this};
165 
166   DISALLOW_COPY_AND_ASSIGN(GCMAccountTracker);
167 };
168 
169 }  // namespace gcm
170 
171 #endif  // COMPONENTS_GCM_DRIVER_GCM_ACCOUNT_TRACKER_H_
172