File: child_account_service.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (242 lines) | stat: -rw-r--r-- 9,389 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/supervised_user/core/browser/child_account_service.h"

#include <functional>
#include <utility>

#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/metrics/field_trial.h"
#include "base/no_destructor.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/signin/public/base/consent_level.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
#include "components/signin/public/identity_manager/tribool.h"
#include "components/supervised_user/core/browser/family_link_user_capabilities.h"
#include "components/supervised_user/core/browser/list_family_members_service.h"
#include "components/supervised_user/core/browser/proto/families_common.pb.h"
#include "components/supervised_user/core/browser/proto_fetcher.h"
#include "components/supervised_user/core/browser/supervised_user_preferences.h"
#include "components/supervised_user/core/browser/supervised_user_settings_service.h"
#include "components/supervised_user/core/common/features.h"
#include "components/supervised_user/core/common/pref_names.h"
#include "components/supervised_user/core/common/supervised_user_constants.h"
#include "google_apis/gaia/core_account_id.h"

namespace supervised_user {

namespace {
using ::base::BindRepeating;
}  // namespace

ChildAccountService::ChildAccountService(
    PrefService& user_prefs,
    signin::IdentityManager* identity_manager,
    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
    base::OnceCallback<void(bool)> check_user_child_status_callback,
    ListFamilyMembersService& list_family_members_service)
    : identity_manager_(identity_manager),
      user_prefs_(user_prefs),
      url_loader_factory_(url_loader_factory),
      check_user_child_status_callback_(
          std::move(check_user_child_status_callback)) {
  set_custodian_prefs_subscription_ =
      list_family_members_service.SubscribeToSuccessfulFetches(BindRepeating(
          &RegisterFamilyPrefs,
          std::ref(user_prefs)));  // list_family_members_service is
                                   // an instance of a keyed service
                                   // and PrefService outlives it.
}

ChildAccountService::~ChildAccountService() = default;

void ChildAccountService::Init() {
  identity_manager_->AddObserver(this);

  std::move(check_user_child_status_callback_)
      .Run(supervised_user::IsSubjectToParentalControls(user_prefs_.get()));

  // If we're already signed in, check the account immediately just to be sure.
  // (We might have missed an update before registering as an observer.)
  // "Unconsented" because this class doesn't care about browser sync consent.
  AccountInfo primary_account_info = identity_manager_->FindExtendedAccountInfo(
      identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin));

  if (!primary_account_info.IsEmpty()) {
    OnExtendedAccountInfoUpdated(primary_account_info);
    UpdateForceGoogleSafeSearch();
  }
}

void ChildAccountService::Shutdown() {
  identity_manager_->RemoveObserver(this);
}

#if BUILDFLAG(IS_CHROMEOS)
bool ChildAccountService::IsChildAccountStatusKnown() {
  return supervised_user::IsChildAccountStatusKnown(user_prefs_.get());
}

void ChildAccountService::AddChildStatusReceivedCallback(
    base::OnceClosure callback) {
  if (supervised_user::IsChildAccountStatusKnown(user_prefs_.get())) {
    std::move(callback).Run();
  } else {
    status_received_callback_list_.push_back(std::move(callback));
  }
}
#endif

ChildAccountService::AuthState ChildAccountService::GetGoogleAuthState() const {
  CoreAccountId primary_account_id =
      identity_manager_->GetPrimaryAccountId(signin::ConsentLevel::kSignin);
  if (primary_account_id.empty()) {
    return AuthState::NOT_AUTHENTICATED;
  }

  signin::AccountsInCookieJarInfo accounts_in_cookie_jar_info =
      identity_manager_->GetAccountsInCookieJar();
  bool primary_account_has_cookie =
      accounts_in_cookie_jar_info.AreAccountsFresh() &&
      std::ranges::any_of(
          accounts_in_cookie_jar_info.GetPotentiallyInvalidSignedInAccounts(),
          [primary_account_id](const gaia::ListedAccount& account) {
            return account.id == primary_account_id && account.valid;
          });
  bool primary_account_has_token =
      !identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
          primary_account_id);

  if (primary_account_has_cookie && primary_account_has_token) {
    return AuthState::AUTHENTICATED;
  }
  if (primary_account_has_token && !primary_account_has_cookie) {
    // The account reconcilor should automatically fix this state, by rebuilding
    // the account cookie.
    return AuthState::TRANSIENT_MOVING_TO_AUTHENTICATED;
  }
  // We either have no token or cookie (in which case we're in the stable
  // pending state), or we have a cookie and no token (in which case the
  // reconcilor will eventually get us to the stable pending state).
  return AuthState::PENDING;
}

base::CallbackListSubscription ChildAccountService::ObserveGoogleAuthState(
    const base::RepeatingCallback<void()>& callback) {
  return google_auth_state_observers_.Add(callback);
}

void ChildAccountService::SetSupervisionStatusAndNotifyObservers(
    bool supervision_status) {
  if (supervised_user::IsSubjectToParentalControls(user_prefs_.get()) !=
      supervision_status) {
    if (supervision_status) {
      EnableParentalControls(user_prefs_.get());
    } else {
      DisableParentalControls(user_prefs_.get());
    }
  }

  for (auto& callback : status_received_callback_list_) {
    std::move(callback).Run();
  }
  status_received_callback_list_.clear();
}

void ChildAccountService::OnPrimaryAccountChanged(
    const signin::PrimaryAccountChangeEvent& event_details) {
  signin::PrimaryAccountChangeEvent::Type event_type =
      event_details.GetEventTypeFor(signin::ConsentLevel::kSignin);
  if (event_type == signin::PrimaryAccountChangeEvent::Type::kSet) {
    AccountInfo account_info = identity_manager_->FindExtendedAccountInfo(
        event_details.GetCurrentState().primary_account);
    if (!account_info.IsEmpty()) {
      OnExtendedAccountInfoUpdated(account_info);
    }
    // Otherwise OnExtendedAccountInfoUpdated will be notified once
    // the account info is available.
  } else if (event_type == signin::PrimaryAccountChangeEvent::Type::kCleared) {
    SetSupervisionStatusAndNotifyObservers(false);
  }
}

void ChildAccountService::UpdateForceGoogleSafeSearch() {
  if (!base::FeatureList::IsEnabled(
          supervised_user::kForceSafeSearchForUnauthenticatedSupervisedUsers)) {
    return;
  }
  bool is_subject_to_parental_controls =
      IsPrimaryAccountSubjectToParentalControls(identity_manager_) ==
      signin::Tribool::kTrue;

  // Supervised users who are signed in to Chrome and to the content area will
  // have account-level SafeSearch configuration applied based on their parent's
  // choices, and this setting should not be overridden.
  // Therefore, we only force SafeSearch on for an unauthenticated and
  // supervised primary account as a safe default.
  bool should_force_google_safe_search =
      (is_subject_to_parental_controls &&
       GetGoogleAuthState() != AuthState::AUTHENTICATED);
  SetGoogleSafeSearch(*user_prefs_, static_cast<GoogleSafeSearchStateStatus>(
                                        should_force_google_safe_search));
}

void ChildAccountService::OnExtendedAccountInfoUpdated(
    const AccountInfo& info) {
  // This method may get called when the account info isn't complete yet.
  // We deliberately don't check for that, as we are only interested in the
  // child account status.

  // This class doesn't care about browser sync consent.
  CoreAccountId auth_account_id =
      identity_manager_->GetPrimaryAccountId(signin::ConsentLevel::kSignin);
  if (info.account_id != auth_account_id) {
    return;
  }

  SetSupervisionStatusAndNotifyObservers(info.is_child_account ==
                                         signin::Tribool::kTrue);
  OnAuthStateUpdated();
}

void ChildAccountService::OnRefreshTokenUpdatedForAccount(
    const CoreAccountInfo& account_info) {
  if (account_info.account_id !=
      identity_manager_->GetPrimaryAccountId(signin::ConsentLevel::kSignin)) {
    return;
  }

  OnAuthStateUpdated();
}

void ChildAccountService::OnErrorStateOfRefreshTokenUpdatedForAccount(
    const CoreAccountInfo& account_info,
    const GoogleServiceAuthError& error,
    signin_metrics::SourceForRefreshTokenOperation token_operation_source) {
  if (account_info.account_id !=
      identity_manager_->GetPrimaryAccountId(signin::ConsentLevel::kSignin)) {
    return;
  }

  OnAuthStateUpdated();
}

void ChildAccountService::OnAccountsInCookieUpdated(
    const signin::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
    const GoogleServiceAuthError& error) {
  OnAuthStateUpdated();
}

void ChildAccountService::OnAuthStateUpdated() {
  UpdateForceGoogleSafeSearch();
  google_auth_state_observers_.Notify();
}

}  // namespace supervised_user