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 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
|
// 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 "components/content_settings/core/browser/content_settings_utils.h"
#include <stddef.h>
#include <array>
#include <vector>
#include "base/containers/contains.h"
#include "base/notreached.h"
#include "base/strings/string_split.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/content_settings/core/browser/content_settings_registry.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/content_settings/core/common/content_settings_utils.h"
#include "components/content_settings/core/common/features.h"
namespace {
const char kPatternSeparator[] = ",";
struct ContentSettingsStringMapping {
ContentSetting content_setting;
const char* content_setting_str;
};
const auto kContentSettingsStringMapping =
std::to_array<ContentSettingsStringMapping>({
{CONTENT_SETTING_DEFAULT, "default"},
{CONTENT_SETTING_ALLOW, "allow"},
{CONTENT_SETTING_BLOCK, "block"},
{CONTENT_SETTING_ASK, "ask"},
{CONTENT_SETTING_SESSION_ONLY, "session_only"},
{CONTENT_SETTING_DETECT_IMPORTANT_CONTENT, "detect_important_content"},
});
static_assert(std::size(kContentSettingsStringMapping) ==
CONTENT_SETTING_NUM_SETTINGS,
"kContentSettingsToFromString should have "
"CONTENT_SETTING_NUM_SETTINGS elements");
// Content settings sorted from most to least permissive. The order is chosen
// to check if a permission grants more rights than another. This is intuitive
// for ALLOW, ASK and BLOCK. SESSION_ONLY and DETECT_IMPORTANT_CONTENT are never
// used in the same setting so their respective order is not important but both
// belong between ALLOW and ASK. DEFAULT should never be used and is therefore
// not part of this array.
const ContentSetting kContentSettingOrder[] = {
// clang-format off
CONTENT_SETTING_ALLOW,
CONTENT_SETTING_SESSION_ONLY,
CONTENT_SETTING_DETECT_IMPORTANT_CONTENT,
CONTENT_SETTING_ASK,
CONTENT_SETTING_BLOCK
// clang-format on
};
static_assert(std::size(kContentSettingOrder) ==
CONTENT_SETTING_NUM_SETTINGS - 1,
"kContentSettingOrder should have CONTENT_SETTING_NUM_SETTINGS-1"
"entries");
} // namespace
namespace content_settings {
std::string ContentSettingToString(ContentSetting setting) {
if (setting >= CONTENT_SETTING_DEFAULT &&
setting < CONTENT_SETTING_NUM_SETTINGS) {
return kContentSettingsStringMapping[setting].content_setting_str;
}
return std::string();
}
bool ContentSettingFromString(const std::string& name,
ContentSetting* setting) {
for (const auto& string_mapping : kContentSettingsStringMapping) {
if (name == string_mapping.content_setting_str) {
*setting = string_mapping.content_setting;
return true;
}
}
*setting = CONTENT_SETTING_DEFAULT;
return false;
}
std::string CreatePatternString(
const ContentSettingsPattern& item_pattern,
const ContentSettingsPattern& top_level_frame_pattern) {
return item_pattern.ToString() + std::string(kPatternSeparator) +
top_level_frame_pattern.ToString();
}
PatternPair ParsePatternString(const std::string& pattern_str) {
std::vector<std::string> pattern_str_list =
base::SplitString(pattern_str, std::string(1, kPatternSeparator[0]),
base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
// If the |pattern_str| is an empty string then the |pattern_string_list|
// contains a single empty string. In this case the empty string will be
// removed to signal an invalid |pattern_str|. Invalid pattern strings are
// handle by the "if"-statment below. So the order of the if statements here
// must be preserved.
if (pattern_str_list.size() == 1) {
if (pattern_str_list[0].empty()) {
pattern_str_list.pop_back();
} else {
pattern_str_list.push_back("*");
}
}
if (pattern_str_list.size() > 2 || pattern_str_list.size() == 0) {
return PatternPair(ContentSettingsPattern(), ContentSettingsPattern());
}
PatternPair pattern_pair;
pattern_pair.first = ContentSettingsPattern::FromString(pattern_str_list[0]);
pattern_pair.second = ContentSettingsPattern::FromString(pattern_str_list[1]);
return pattern_pair;
}
void GetRendererContentSettingRules(const HostContentSettingsMap* map,
RendererContentSettingRules* rules) {
#if !BUILDFLAG(IS_IOS)
rules->mixed_content_rules =
map->GetSettingsForOneType(ContentSettingsType::MIXEDSCRIPT);
#else
// In Android active mixed content is hard blocked, with no option to allow
// it.
rules->mixed_content_rules.push_back(ContentSettingPatternSource(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
ContentSettingToValue(CONTENT_SETTING_BLOCK), ProviderType::kNone,
map->IsOffTheRecord()));
#endif
}
bool IsMorePermissive(ContentSetting a, ContentSetting b) {
// Check whether |a| or |b| is reached first in kContentSettingOrder.
// If |a| is first, it means that |a| is more permissive than |b|.
for (ContentSetting setting : kContentSettingOrder) {
if (setting == b)
return false;
if (setting == a)
return true;
}
NOTREACHED();
}
// Currently only mojom::SessionModel::DURABLE constraints need to be persistent
// as they are only bounded by time and can persist through multiple browser
// sessions.
bool IsConstraintPersistent(const ContentSettingConstraints& constraints) {
return constraints.session_model() == mojom::SessionModel::DURABLE;
}
bool CanTrackLastVisit(ContentSettingsType type) {
// Last visit is not tracked for notification permission as it shouldn't be
// auto-revoked.
if (type == ContentSettingsType::NOTIFICATIONS) {
return false;
}
// Protocol handler don't actually use their content setting and don't have
// a valid "initial default" value.
if (type == ContentSettingsType::PROTOCOL_HANDLERS) {
return false;
}
// Chooser based content settings will not be tracked by default.
// Only allowlisted ones should be tracked.
if (IsChooserPermissionEligibleForAutoRevocation(type)) {
return true;
}
auto* info =
content_settings::ContentSettingsRegistry::GetInstance()->Get(type);
return info && info->GetInitialDefaultSetting() == CONTENT_SETTING_ASK;
}
base::Time GetCoarseVisitedTime(base::Time time) {
return base::Time::FromDeltaSinceWindowsEpoch(
time.ToDeltaSinceWindowsEpoch().FloorToMultiple(
GetCoarseVisitedTimePrecision()));
}
base::TimeDelta GetCoarseVisitedTimePrecision() {
if (features::kSafetyCheckUnusedSitePermissionsNoDelay.Get() ||
features::kSafetyCheckUnusedSitePermissionsWithDelay.Get()) {
return base::Days(0);
}
return base::Days(7);
}
bool CanBeAutoRevoked(ContentSettingsType type,
ContentSetting setting,
bool is_one_time) {
return CanBeAutoRevoked(type, ContentSettingToValue(setting), is_one_time);
}
bool CanBeAutoRevoked(ContentSettingsType type,
const base::Value& value,
bool is_one_time) {
// The Permissions module in Safety check will revoke permissions after
// a finite amount of time.
// We're only interested in expiring permissions that are either
// A. regular permissions (= ContentSettingsRegistry-based), which
// 1. Are ALLOWed.
// 2. Fall back to ASK.
// 3. Are not already a one-time grant.
// B. chooser permissions (= WebsiteSettingsRegistry-based), which
// 1. Are allowlisted.
// 2. Have a non-empty value.
auto* info =
content_settings::ContentSettingsRegistry::GetInstance()->Get(type);
if (info) {
return !is_one_time &&
ValueToContentSetting(value) == CONTENT_SETTING_ALLOW &&
CanTrackLastVisit(type);
}
// If the value is already empty, no need to revoke the permission.
return IsChooserPermissionEligibleForAutoRevocation(type) && !value.is_none();
}
bool IsChooserPermissionEligibleForAutoRevocation(ContentSettingsType type) {
// Currently, only File System Access is allowlisted for auto-revoking unused
// site permissions among chooser-based permissions.
return type == ContentSettingsType::FILE_SYSTEM_ACCESS_CHOOSER_DATA;
}
const std::vector<ContentSettingsType>& GetTypesWithTemporaryGrants() {
static base::NoDestructor<const std::vector<ContentSettingsType>> types{{
#if !BUILDFLAG(IS_ANDROID)
ContentSettingsType::CAMERA_PAN_TILT_ZOOM,
ContentSettingsType::CAPTURED_SURFACE_CONTROL,
#endif
ContentSettingsType::KEYBOARD_LOCK,
ContentSettingsType::GEOLOCATION,
ContentSettingsType::MEDIASTREAM_MIC,
ContentSettingsType::MEDIASTREAM_CAMERA,
ContentSettingsType::HAND_TRACKING,
ContentSettingsType::SMART_CARD_DATA,
ContentSettingsType::AR,
ContentSettingsType::VR,
}};
return *types;
}
const std::vector<ContentSettingsType>& GetTypesWithTemporaryGrantsInHcsm() {
static base::NoDestructor<const std::vector<ContentSettingsType>> types{{
#if !BUILDFLAG(IS_ANDROID)
ContentSettingsType::CAMERA_PAN_TILT_ZOOM,
ContentSettingsType::CAPTURED_SURFACE_CONTROL,
#endif
ContentSettingsType::KEYBOARD_LOCK,
ContentSettingsType::GEOLOCATION,
ContentSettingsType::MEDIASTREAM_MIC,
ContentSettingsType::MEDIASTREAM_CAMERA,
ContentSettingsType::HAND_TRACKING,
ContentSettingsType::AR,
ContentSettingsType::VR,
}};
return *types;
}
bool ShouldTypeExpireActively(ContentSettingsType type) {
return base::FeatureList::IsEnabled(
content_settings::features::kActiveContentSettingExpiry) &&
base::Contains(GetTypesWithTemporaryGrantsInHcsm(), type);
}
} // namespace content_settings
|