910e62b5创建于 1月15日历史提交
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_BROWSER_SWITCHER_BROWSER_SWITCHER_PREFS_H_
#define CHROME_BROWSER_BROWSER_SWITCHER_BROWSER_SWITCHER_PREFS_H_

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

#include "base/callback_list.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/policy/core/common/policy_service.h"
#include "components/prefs/pref_change_registrar.h"
#include "url/gurl.h"

namespace user_prefs {
class PrefRegistrySyncable;
}  // namespace user_prefs

class PrefService;
class Profile;

namespace browser_switcher {

// This type pre-computes some strings from the URL's parts, so we don't have
// to pay the cost of constructing those strings multiple times. i.e., the same
// NoCopyUrl can be passed to multiple calls of Rule::Matches().
class NoCopyUrl {
 public:
  explicit NoCopyUrl(const GURL& original);
  NoCopyUrl(const NoCopyUrl&) = delete;

  const GURL& original() const { return *original_; }
  std::string_view host_and_port() const { return host_and_port_; }
  std::string_view spec() const { return original_->spec(); }
  std::string_view spec_without_port() const { return spec_without_port_; }

 private:
  const raw_ref<const GURL> original_;
  // If there is a port number, then this is "<host>:<port>". Otherwise, this is
  // just the host.
  std::string host_and_port_;
  // Same as |original_.spec()|, but with the port removed.
  std::string spec_without_port_;
};

// A named pair type, for rules that haven't been pre-processed and
// canonicalized (e.g., just loaded from prefs or policies).
struct RawRuleSet {
  RawRuleSet();
  RawRuleSet(std::vector<std::string>&& sitelist,
             std::vector<std::string>&& greylist);
  RawRuleSet(RawRuleSet&&);
  ~RawRuleSet();

  RawRuleSet& operator=(RawRuleSet&&);

  std::vector<std::string> sitelist;
  std::vector<std::string> greylist;
};

// A single "rule" from a sitelist or greylist, after pre-processing and
// canonicalization.
class Rule {
 public:
  explicit Rule(std::string_view original_rule);
  virtual ~Rule() = default;

  // Returns true if |no_copy_url| matches this rule. Ignores the value of
  // |inverted_|.
  virtual bool Matches(const NoCopyUrl& no_copy_url) const = 0;

  // Returns true if the rule is valid. If this returns false, the rule will be
  // removed from the final list of canonicalized rules.
  virtual bool IsValid() const = 0;

  // Converts the rule to a human-readable string, for display on
  // chrome://browser-switch/internals and serializing to cache.dat.
  virtual std::string ToString() const = 0;

  int priority() const { return priority_; }

  bool inverted() const { return inverted_; }

 private:
  // The "priority" of this rule for making decisions. This should be the length
  // of the original string this rule was parsed from. When 2 rules conflict,
  // the one with higher priority always wins.
  int priority_;

  // Whether this rule is inverted or not. Inverted rules change the decision
  // from "open in alternative browser" to "don't open in alternative browser".
  bool inverted_;
};

// A named pair type, for pre-processed and canonicalized rules.
struct RuleSet {
  RuleSet();
  RuleSet(RuleSet&&);
  ~RuleSet();

  std::vector<std::unique_ptr<Rule>> sitelist;
  std::vector<std::unique_ptr<Rule>> greylist;
};

// Values for the BrowserSwitcherParsingMode policy. Make sure they match the
// values in policy_templates.json.
enum class ParsingMode {
  kDefault = 0,
  kIESiteListMode = 1,
  kMaxValue = kIESiteListMode,  // Always keep up-to-date.
};

// Contains the current state of the prefs related to LBS. For sensitive prefs,
// only respects managed prefs. Also does some type conversions and
// transformations on the prefs (e.g. expanding preset values for
// AlternativeBrowserPath).
class BrowserSwitcherPrefs : public KeyedService,
                             public policy::PolicyService::Observer {
 private:
  using PrefsChangedSignature = void(BrowserSwitcherPrefs*,
                                     const std::vector<std::string>&);

 public:
  using PrefsChangedCallback = base::RepeatingCallback<PrefsChangedSignature>;

  BrowserSwitcherPrefs() = delete;

  explicit BrowserSwitcherPrefs(Profile* profile);

  BrowserSwitcherPrefs(const BrowserSwitcherPrefs&) = delete;
  BrowserSwitcherPrefs& operator=(const BrowserSwitcherPrefs&) = delete;

  ~BrowserSwitcherPrefs() override;

  // KeyedService:
  void Shutdown() override;

  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);

  // Returns true if the BrowserSwitcher feature is enabled via policy.
  bool IsEnabled() const;

  // Returns the path to the alternative browser to launch, before
  // substitutions. If the pref is not managed, returns the empty string.
  const std::string& GetAlternativeBrowserPath() const;

  // Returns the arguments to pass to the alternative browser, before
  // substitutions. If the pref is not managed, returns the empty string.
  const std::vector<std::string>& GetAlternativeBrowserParameters() const;

  // Returns true if Chrome should keep at least one tab open after switching.
  bool KeepLastTab() const;

  // Returns the delay before switching, in milliseconds.
  int GetDelay() const;

  ParsingMode GetParsingMode() const;

  // Returns the sitelist + greylist configured directly through Chrome
  // policies. If the pref is not managed, returns an empty vector.
  const RuleSet& GetRules() const;

  // Retrieves or stores the locally cached external sitelist from the
  // PrefStore.
  RawRuleSet GetCachedExternalSitelist() const;
  void SetCachedExternalSitelist(const RawRuleSet& sitelist);

  // Retrieves or stores the locally cached external greylist from the
  // PrefStore.
  RawRuleSet GetCachedExternalGreylist() const;
  void SetCachedExternalGreylist(const RawRuleSet& greylist);

#if BUILDFLAG(IS_WIN)
  // Retrieves or stores the locally cached IEEM sitelist from the PrefStore.
  RawRuleSet GetCachedIeemSitelist() const;
  void SetCachedIeemSitelist(const RawRuleSet& sitelist);
#endif

  // Returns the URL to download for an external XML sitelist. If the pref is
  // not managed, returns an invalid URL.
  GURL GetExternalSitelistUrl() const;

  // Returns the URL to download for an external XML greylist. If the pref is
  // not managed, returns an invalid URL.
  GURL GetExternalGreylistUrl() const;

#if BUILDFLAG(IS_WIN)
  // Returns true if Chrome should download and apply the XML sitelist from
  // IEEM's SiteList policy. If the pref is not managed, returns false.
  bool UseIeSitelist() const;

  // Returns the path to the Chrome executable to launch when switching from IE,
  // before substitutions.
  const base::FilePath& GetChromePath() const;

  // Returns the arguments to pass to Chrome when switching from IE, before
  // substitutions.
  const std::vector<std::string>& GetChromeParameters() const;
#endif

  // policy::PolicyService::Observer
  void OnPolicyUpdated(const policy::PolicyNamespace& ns,
                       const policy::PolicyMap& previous,
                       const policy::PolicyMap& current) override;

  base::CallbackListSubscription RegisterPrefsChangedCallback(
      PrefsChangedCallback cb);

 protected:
  // For internal use and testing.
  BrowserSwitcherPrefs(PrefService* prefs,
                       policy::PolicyService* policy_service);

 private:
  void RunCallbacksIfDirty();
  void MarkDirty(const std::string& pref_name);

  // Hooks for PrefChangeRegistrar.
  void AlternativeBrowserPathChanged();
  void AlternativeBrowserParametersChanged();
  void ParsingModeChanged();
  void UrlListChanged();
  void GreylistChanged();
#if BUILDFLAG(IS_WIN)
  void ChromePathChanged();
  void ChromeParametersChanged();
#endif

  const raw_ptr<policy::PolicyService> policy_service_;
  const raw_ptr<PrefService> prefs_;

  // We need 2 change registrars because we can't bind 2 observers to the same
  // pref on the same registrar.

  // Listens on *some* prefs, to apply a filter to them
  // (e.g. convert Value::List => vector<string>).
  PrefChangeRegistrar filtering_change_registrar_;

  // Listens on *all* BrowserSwitcher prefs, to notify observers when prefs
  // change as a result of a policy refresh.
  PrefChangeRegistrar notifying_change_registrar_;

  // Type-converted and/or expanded pref values, updated by the
  // PrefChangeRegistrar hooks.
  std::string alt_browser_path_;
  std::vector<std::string> alt_browser_params_;
  ParsingMode parsing_mode_ = ParsingMode::kDefault;
#if BUILDFLAG(IS_WIN)
  base::FilePath chrome_path_;
  std::vector<std::string> chrome_params_;
#endif

  // Rules from the BrowserSwitcherUrlList and BrowserSwitcherGreylist policies.
  //
  // Other rules are parsed from XML, and stored in BrowserSwitcherSitelist
  // instead of here.
  RuleSet rules_;

  // List of prefs (pref names) that changed since the last policy refresh.
  std::vector<std::string> dirty_prefs_;

  base::RepeatingCallbackList<PrefsChangedSignature> callback_list_;

  base::WeakPtrFactory<BrowserSwitcherPrefs> weak_ptr_factory_{this};
};

namespace prefs {

extern const char kEnabled[];
extern const char kDelay[];
extern const char kAlternativeBrowserPath[];
extern const char kAlternativeBrowserParameters[];
extern const char kKeepLastTab[];
extern const char kParsingMode[];
extern const char kUrlList[];
extern const char kUrlGreylist[];
extern const char kExternalSitelistUrl[];
extern const char kCachedExternalSitelist[];
extern const char kCachedExternalSitelistGreylist[];
extern const char kExternalGreylistUrl[];
extern const char kCachedExternalGreylist[];

#if BUILDFLAG(IS_WIN)
extern const char kUseIeSitelist[];
extern const char kCachedIeSitelist[];
extern const char kCachedIeSitelistGreylist[];
extern const char kChromePath[];
extern const char kChromeParameters[];
#endif

}  // namespace prefs

}  // namespace browser_switcher

#endif  // CHROME_BROWSER_BROWSER_SWITCHER_BROWSER_SWITCHER_PREFS_H_