| // 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/user_manager/user.h" |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| |
| #include "ash/constants/ash_pref_names.h" |
| #include "base/functional/callback.h" |
| #include "base/logging.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "components/account_id/account_id.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/user_manager/user_manager.h" |
| #include "google_apis/gaia/gaia_auth_util.h" |
| |
| namespace user_manager { |
| |
| namespace { |
| |
| // Must be in sync with histogram enum UserTypeChanged in enums.xml. |
| // The values must never be changed (only new ones can be added) as they |
| // are stored in UMA logs. |
| enum class UserTypeChangeHistogram { |
| UNKNOWN_FATAL = 0, |
| REGULAR_TO_CHILD = 1, |
| CHILD_TO_REGULAR = 2, |
| COUNT, // Not a value, just a count of other values. |
| }; |
| void UMAUserTypeChanged(const UserTypeChangeHistogram value) { |
| UMA_HISTOGRAM_ENUMERATION("UserManager.UserTypeChanged", value, |
| UserTypeChangeHistogram::COUNT); |
| } |
| |
| // Returns account name portion of an email. |
| std::string GetUserName(const std::string& email) { |
| std::string::size_type i = email.find('@'); |
| if (i == 0 || i == std::string::npos) { |
| return email; |
| } |
| return email.substr(0, i); |
| } |
| |
| } // namespace |
| |
| // static |
| bool User::TypeHasGaiaAccount(UserType user_type) { |
| return user_type == UserType::kRegular || user_type == UserType::kChild; |
| } |
| |
| // static |
| bool User::TypeIsKiosk(UserType type) { |
| return type == UserType::kKioskApp || type == UserType::kWebKioskApp; |
| } |
| |
| User::User(const AccountId& account_id, UserType type) |
| : account_id_(account_id), type_(type), user_image_(new UserImage()) { |
| switch (type_) { |
| case user_manager::UserType::kRegular: |
| case user_manager::UserType::kChild: |
| case user_manager::UserType::kKioskApp: |
| case user_manager::UserType::kWebKioskApp: |
| set_display_email(account_id.GetUserEmail()); |
| break; |
| case user_manager::UserType::kGuest: |
| case user_manager::UserType::kPublicAccount: |
| // Public accounts nor guest account do not have a real email address, |
| // so they do not set |display_email_|. |
| break; |
| } |
| } |
| |
| User::~User() = default; |
| |
| std::string User::GetDisplayEmail() const { |
| return display_email(); |
| } |
| |
| std::u16string User::GetDisplayName() const { |
| // Fallback to the email account name in case display name haven't been set. |
| return display_name_.empty() ? base::UTF8ToUTF16(GetAccountName(true)) |
| : display_name_; |
| } |
| |
| std::u16string User::GetGivenName() const { |
| return given_name_; |
| } |
| |
| const gfx::ImageSkia& User::GetImage() const { |
| return user_image_->image(); |
| } |
| |
| const AccountId& User::GetAccountId() const { |
| return account_id_; |
| } |
| |
| void User::UpdateType(UserType new_type) { |
| // Can only change between regular and child. |
| if ((type_ == user_manager::UserType::kChild || |
| type_ == user_manager::UserType::kRegular) && |
| (new_type == user_manager::UserType::kChild || |
| new_type == user_manager::UserType::kRegular)) { |
| // We want all the other type changes to crash, that is why this check is |
| // not at the top level. |
| if (type_ == new_type) { |
| return; |
| } |
| |
| LOG(WARNING) << "User type has changed: " << type_ << " -> " << new_type; |
| type_ = new_type; |
| |
| UMAUserTypeChanged(new_type == user_manager::UserType::kChild |
| ? UserTypeChangeHistogram::REGULAR_TO_CHILD |
| : UserTypeChangeHistogram::CHILD_TO_REGULAR); |
| return; |
| } |
| |
| UMAUserTypeChanged(UserTypeChangeHistogram::UNKNOWN_FATAL); |
| LOG(FATAL) << "Unsupported user type change " << type_ << "=>" << new_type; |
| } |
| |
| bool User::HasGaiaAccount() const { |
| return TypeHasGaiaAccount(GetType()); |
| } |
| |
| bool User::IsChild() const { |
| return GetType() == UserType::kChild; |
| } |
| |
| std::string User::GetAccountName(bool use_display_email) const { |
| if (use_display_email && !display_email_.empty()) |
| return GetUserName(display_email_); |
| else |
| return GetUserName(account_id_.GetUserEmail()); |
| } |
| |
| bool User::CanLock() const { |
| switch (type_) { |
| case user_manager::UserType::kRegular: |
| case user_manager::UserType::kChild: |
| if (!profile_prefs_) { |
| return false; |
| } |
| break; |
| case user_manager::UserType::kKioskApp: |
| case user_manager::UserType::kWebKioskApp: |
| case user_manager::UserType::kGuest: |
| return false; |
| case user_manager::UserType::kPublicAccount: |
| if (!profile_prefs_ || |
| !profile_prefs_->GetBoolean( |
| ash::prefs::kLoginExtensionApiCanLockManagedGuestSession)) { |
| return false; |
| } |
| break; |
| } |
| |
| return profile_prefs_->GetBoolean(ash::prefs::kAllowScreenLock); |
| } |
| |
| std::string User::display_email() const { |
| return display_email_; |
| } |
| |
| const std::string& User::username_hash() const { |
| return username_hash_; |
| } |
| |
| bool User::is_logged_in() const { |
| return is_logged_in_; |
| } |
| |
| bool User::is_active() const { |
| return is_active_; |
| } |
| |
| bool User::has_gaia_account() const { |
| static_assert(static_cast<int>(user_manager::UserType::kMaxValue) == 9, |
| "kMaxValue should equal 9"); |
| switch (GetType()) { |
| case user_manager::UserType::kRegular: |
| case user_manager::UserType::kChild: |
| return true; |
| case user_manager::UserType::kGuest: |
| case user_manager::UserType::kPublicAccount: |
| case user_manager::UserType::kKioskApp: |
| case user_manager::UserType::kWebKioskApp: |
| return false; |
| } |
| return false; |
| } |
| |
| void User::AddProfileCreatedObserver(base::OnceClosure on_profile_created) { |
| if (profile_is_created_) |
| std::move(on_profile_created).Run(); |
| else |
| on_profile_created_observers_.push_back(std::move(on_profile_created)); |
| } |
| |
| void User::SetProfileIsCreated() { |
| profile_is_created_ = true; |
| for (auto& callback : on_profile_created_observers_) { |
| std::move(callback).Run(); |
| } |
| on_profile_created_observers_.clear(); |
| } |
| |
| bool User::IsAffiliated() const { |
| // Device local accounts are always affiliated. |
| if (IsDeviceLocalAccount()) { |
| return true; |
| } |
| |
| return is_affiliated_.value_or(false); |
| } |
| |
| void User::IsAffiliatedAsync( |
| base::OnceCallback<void(bool)> is_affiliated_callback) { |
| // TODO(b/278643115): Conceptually, we should call |
| // std::move(is_affiliated_callback).Run(true) |
| // here immediately if this is for device local account. |
| |
| if (is_affiliated_.has_value()) { |
| std::move(is_affiliated_callback).Run(is_affiliated_.value()); |
| } else { |
| on_affiliation_set_callbacks_.push_back(std::move(is_affiliated_callback)); |
| } |
| } |
| |
| void User::SetAffiliated(bool is_affiliated) { |
| // Device local accounts are always affiliated. No affiliation |
| // modification must happen. |
| CHECK(!IsDeviceLocalAccount()); |
| |
| is_affiliated_ = is_affiliated; |
| for (auto& callback : on_affiliation_set_callbacks_) { |
| std::move(callback).Run(is_affiliated_.value()); |
| } |
| on_affiliation_set_callbacks_.clear(); |
| } |
| |
| bool User::IsDeviceLocalAccount() const { |
| switch (type_) { |
| case user_manager::UserType::kRegular: |
| case user_manager::UserType::kChild: |
| case user_manager::UserType::kGuest: |
| return false; |
| case user_manager::UserType::kPublicAccount: |
| case user_manager::UserType::kKioskApp: |
| case user_manager::UserType::kWebKioskApp: |
| return true; |
| } |
| return false; |
| } |
| |
| bool User::IsKioskType() const { |
| return TypeIsKiosk(GetType()); |
| } |
| |
| User* User::CreateRegularUser(const AccountId& account_id, |
| const UserType type) { |
| CHECK(type == UserType::kRegular || type == UserType::kChild) |
| << "Invalid user type " << type; |
| |
| return new User(account_id, type); |
| } |
| |
| User* User::CreateGuestUser(const AccountId& guest_account_id) { |
| return new User(guest_account_id, UserType::kGuest); |
| } |
| |
| User* User::CreateKioskAppUser(const AccountId& kiosk_app_account_id) { |
| return new User(kiosk_app_account_id, UserType::kKioskApp); |
| } |
| |
| User* User::CreateWebKioskAppUser(const AccountId& web_kiosk_account_id) { |
| return new User(web_kiosk_account_id, UserType::kWebKioskApp); |
| } |
| |
| User* User::CreatePublicAccountUser(const AccountId& account_id, |
| bool is_using_saml) { |
| User* user = new User(account_id, UserType::kPublicAccount); |
| user->set_using_saml(is_using_saml); |
| return user; |
| } |
| |
| void User::SetAccountLocale(const std::string& resolved_account_locale) { |
| account_locale_ = std::make_unique<std::string>(resolved_account_locale); |
| } |
| |
| void User::SetImage(std::unique_ptr<UserImage> user_image, int image_index) { |
| user_image_ = std::move(user_image); |
| image_index_ = image_index; |
| image_is_stub_ = false; |
| image_is_loading_ = false; |
| } |
| |
| void User::SetImageURL(const GURL& image_url) { |
| user_image_->set_url(image_url); |
| } |
| |
| void User::SetStubImage(std::unique_ptr<UserImage> stub_user_image, |
| int image_index, |
| bool is_loading) { |
| user_image_ = std::move(stub_user_image); |
| image_index_ = image_index; |
| image_is_stub_ = true; |
| image_is_loading_ = is_loading; |
| } |
| |
| } // namespace user_manager |