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
|
// 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.
#include "chrome/browser/extensions/preference/preference_helpers.h"
#include <memory>
#include <utility>
#include "base/json/json_writer.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "components/prefs/pref_service.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_prefs_helper.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_util.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/manifest_handlers/incognito_info.h"
#include "extensions/common/permissions/permissions_data.h"
namespace extensions {
namespace preference_helpers {
namespace {
constexpr char kNotControllable[] = "not_controllable";
constexpr char kControlledByOtherExtensions[] =
"controlled_by_other_extensions";
constexpr char kControllableByThisExtension[] =
"controllable_by_this_extension";
constexpr char kControlledByThisExtension[] = "controlled_by_this_extension";
constexpr char kLevelOfControlKey[] = "levelOfControl";
} // namespace
using LevelOfControlGetter =
base::RepeatingCallback<const char*(Profile*,
const ExtensionId& extension_id,
const std::string& browser_pref,
bool incognito)>;
PrefService* GetProfilePrefService(Profile* profile, bool incognito) {
if (incognito) {
if (profile->HasPrimaryOTRProfile()) {
return profile->GetPrimaryOTRProfile(/*create_if_needed=*/false)
->GetPrefs();
}
return profile->GetReadOnlyOffTheRecordPrefs();
}
return profile->GetPrefs();
}
const char* GetLevelOfControl(Profile* profile,
const ExtensionId& extension_id,
const std::string& browser_pref,
bool incognito) {
PrefService* prefs = GetProfilePrefService(profile, incognito);
bool from_incognito = false;
bool* from_incognito_ptr = incognito ? &from_incognito : nullptr;
const PrefService::Preference* pref = prefs->FindPreference(browser_pref);
if (!pref->IsExtensionModifiable())
return kNotControllable;
if (ExtensionPrefsHelper::Get(profile)->DoesExtensionControlPref(
extension_id, browser_pref, from_incognito_ptr)) {
return kControlledByThisExtension;
}
if (ExtensionPrefsHelper::Get(profile)->CanExtensionControlPref(
extension_id, browser_pref, incognito)) {
return kControllableByThisExtension;
}
return kControlledByOtherExtensions;
}
void DispatchEventToExtensionsImpl(Profile* profile,
events::HistogramValue histogram_value,
const std::string& event_name,
base::Value::List args,
mojom::APIPermissionID permission,
bool incognito,
const std::string& browser_pref,
const LevelOfControlGetter level_getter) {
EventRouter* router = EventRouter::Get(profile);
if (!router || !router->HasEventListener(event_name))
return;
for (const scoped_refptr<const extensions::Extension>& extension :
ExtensionRegistry::Get(profile)->enabled_extensions()) {
// TODO(bauerb): Only iterate over registered event listeners.
if (router->ExtensionHasEventListener(extension->id(), event_name) &&
extension->permissions_data()->HasAPIPermission(permission) &&
(!incognito || util::IsIncognitoEnabled(extension->id(), profile))) {
// Inject level of control key-value.
DCHECK(!args.empty());
DCHECK(args[0].is_dict());
std::string level_of_control =
level_getter.Run(profile, extension->id(), browser_pref, incognito);
args[0].GetDict().Set(kLevelOfControlKey, level_of_control);
// If the extension is in incognito split mode,
// a) incognito pref changes are visible only to the incognito tabs
// b) regular pref changes are visible only to the incognito tabs if the
// incognito pref has not already been set
Profile* restrict_to_profile = nullptr;
if (IncognitoInfo::IsSplitMode(extension.get())) {
if (incognito) { // Handle case a).
// If off the record profile does not exist, there should be no
// extensions running in incognito at this time, and consequentially
// no need to dispatch an event restricted to an incognito extension.
// Furthermore, avoid calling GetPrimaryOTRProfile() if the profile
// does not exist. Unnecessarily creating off the record profile is
// undesirable, and can lead to a crash if incognito is disallowed for
// the current profile (see https://crbug.com/796814).
if (!profile->HasPrimaryOTRProfile())
continue;
restrict_to_profile =
profile->GetPrimaryOTRProfile(/*create_if_needed=*/true);
} else { // Handle case b).
bool controlled_from_incognito = false;
bool controlled_by_extension =
ExtensionPrefsHelper::Get(profile)->DoesExtensionControlPref(
extension->id(), browser_pref, &controlled_from_incognito);
if (controlled_by_extension && controlled_from_incognito)
restrict_to_profile = profile;
}
}
base::Value::List args_copy = args.Clone();
auto event =
std::make_unique<Event>(histogram_value, event_name,
std::move(args_copy), restrict_to_profile);
router->DispatchEventToExtension(extension->id(), std::move(event));
}
}
}
void DispatchEventToExtensions(Profile* profile,
events::HistogramValue histogram_value,
const std::string& event_name,
base::Value::List args,
mojom::APIPermissionID permission,
bool incognito,
const std::string& browser_pref) {
DispatchEventToExtensionsImpl(
profile, histogram_value, event_name, std::move(args), permission,
incognito, browser_pref, base::BindRepeating(GetLevelOfControl));
}
} // namespace preference_helpers
} // namespace extensions
|