chromium/chromeos/ash/components/settings/cros_settings.h

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMEOS_ASH_COMPONENTS_SETTINGS_CROS_SETTINGS_H_
#define CHROMEOS_ASH_COMPONENTS_SETTINGS_CROS_SETTINGS_H_

#include <map>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>

#include "base/callback_list.h"
#include "base/component_export.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/sequence_checker.h"
#include "base/values.h"
#include "build/chromeos_buildflags.h"
#include "chromeos/ash/components/settings/cros_settings_names.h"
#include "chromeos/ash/components/settings/cros_settings_provider.h"
#include "components/user_manager/user_type.h"

static_assert(BUILDFLAG(IS_CHROMEOS_ASH), "For ChromeOS ash-chrome only");

namespace ash {

// This class manages per-device/global settings.
class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_SETTINGS) CrosSettings {
 public:
  // Returns the global singleton instance.
  // Life time is managed by CrosSettingsHolder or, if it is in tests,
  // ScopedTestingCrosSettings.
  static bool IsInitialized();
  static CrosSettings* Get();

  // Creates an instance with no providers as yet.
  CrosSettings();
  CrosSettings(const CrosSettings&) = delete;
  CrosSettings& operator=(const CrosSettings&) = delete;
  ~CrosSettings();

  // Helper function to test if the given |path| is a valid cros setting.
  static bool IsCrosSettings(std::string_view path);

  // Returns setting value for the given |path|.
  const base::Value* GetPref(std::string_view path) const;

  // Requests that all providers ensure the values they are serving were read
  // from a trusted store:
  // * If all providers are serving trusted values, returns TRUSTED. This
  //   indicates that the cros settings returned by |this| can be trusted during
  //   the current loop cycle.
  // * If at least one provider ran into a permanent failure while trying to
  //   read values from its trusted store, returns PERMANENTLY_UNTRUSTED. This
  //   indicates that the cros settings will never become trusted.
  // * Otherwise, returns TEMPORARILY_UNTRUSTED. This indicates that at least
  //   one provider needs to read values from its trusted store first. The
  //   |callback| will be called back when the read is done.
  //   PrepareTrustedValues() should be called again at that point to determine
  //   whether all providers are serving trusted values now.
  CrosSettingsProvider::TrustedStatus PrepareTrustedValues(
      base::OnceClosure callback) const;

  // These are convenience forms of Get().  The value will be retrieved
  // and the return value will be true if the |path| is valid and the value at
  // the end of the path can be returned in the form specified.
  bool GetBoolean(std::string_view path, bool* out_value) const;
  bool GetInteger(std::string_view path, int* out_value) const;
  bool GetDouble(std::string_view path, double* out_value) const;
  bool GetString(std::string_view path, std::string* out_value) const;
  bool GetList(std::string_view path,
               const base::Value::List** out_value) const;
  bool GetDictionary(std::string_view path,
                     const base::Value::Dict** out_value) const;

  // Checks if the given username is on the list of users allowed to sign-in to
  // this device. |wildcard_match| may be nullptr. If it's present, it'll be set
  // to true if the list check was satisfied via a wildcard. In some
  // configurations user can be allowed based on the |user_type|. See
  // |DeviceFamilyLinkAccountsAllowed| policy.
  bool IsUserAllowlisted(
      const std::string& username,
      bool* wildcard_match,
      const std::optional<user_manager::UserType>& user_type) const;

  // Helper function for the allowlist op. Implemented here because we will need
  // this in a few places. The functions searches for |email| in the pref |path|
  // It respects allowlists so [email protected] will match *@bar.baz too. If the
  // match was via a wildcard, |wildcard_match| is set to true.
  bool FindEmailInList(const std::string& path,
                       const std::string& email,
                       bool* wildcard_match) const;

  // Same as above, but receives already populated user list.
  static bool FindEmailInList(const base::Value::List& list,
                              const std::string& email,
                              bool* wildcard_match);

  // Sets a special CrosSettingsProvider for child account handling.
  // This can be called at most once per instance.
  void SetSupervisedUserCrosSettingsProvider(
      std::unique_ptr<CrosSettingsProvider> provider);

  // Adding/removing of providers.
  bool AddSettingsProvider(std::unique_ptr<CrosSettingsProvider> provider);
  std::unique_ptr<CrosSettingsProvider> RemoveSettingsProvider(
      CrosSettingsProvider* provider);

  // Add an observer Callback for changes for the given |path|.
  [[nodiscard]] base::CallbackListSubscription AddSettingsObserver(
      const std::string& path,
      base::RepeatingClosure callback);

  // Returns the provider that handles settings with the |path| or prefix.
  CrosSettingsProvider* GetProvider(std::string_view path) const;

  // TODO(hidehiko): Consider to migrate this into GetProvider().
  const CrosSettingsProvider* supervised_user_cros_settings_provider() const {
    return supervised_user_cros_settings_provider_;
  }

 private:
  friend class CrosSettingsTest;

  // Allows accessing to SetInstance.
  friend class CrosSettingsHolder;
  friend class ScopedTestingCrosSettings;

  // Sets `cros_settings` as a global instance. This does not take ownership,
  // so the caller still has the responsibility to destroy the instance
  // on appropriate timing. Also, the caller has the responsibility to call
  // `SetInstance(nullptr)` before destroying the instance.
  // If this is called while the global instance is already set, this will
  // cause crash.
  static void SetInstance(CrosSettings* cros_settings);

  // Fires system setting change callback.
  void FireObservers(const std::string& path);

  // List of ChromeOS system settings providers.
  std::vector<std::unique_ptr<CrosSettingsProvider>> providers_;

  // Owner unique pointer in |providers_|.
  raw_ptr<CrosSettingsProvider> supervised_user_cros_settings_provider_;

  // A map from settings names to a list of observers. Observers get fired in
  // the order they are added.
  std::map<std::string, std::unique_ptr<base::RepeatingClosureList>>
      settings_observers_;

  SEQUENCE_CHECKER(sequence_checker_);
};

}  // namespace ash

#endif  // CHROMEOS_ASH_COMPONENTS_SETTINGS_CROS_SETTINGS_H_