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
|
// 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 "extensions/common/manifest_handlers/content_capabilities_handler.h"
#include <memory>
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/common/content_switches.h"
#include "extensions/common/api/extensions_manifest_types.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/install_warning.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/permissions/permissions_info.h"
#include "extensions/common/url_pattern.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
namespace extensions {
namespace keys = manifest_keys;
namespace errors = manifest_errors;
using api::extensions_manifest_types::ContentCapabilities;
ContentCapabilitiesInfo::ContentCapabilitiesInfo() = default;
ContentCapabilitiesInfo::~ContentCapabilitiesInfo() = default;
static base::LazyInstance<ContentCapabilitiesInfo>::DestructorAtExit
g_empty_content_capabilities_info = LAZY_INSTANCE_INITIALIZER;
// static
const ContentCapabilitiesInfo& ContentCapabilitiesInfo::Get(
const Extension* extension) {
ContentCapabilitiesInfo* info = static_cast<ContentCapabilitiesInfo*>(
extension->GetManifestData(keys::kContentCapabilities));
return info ? *info : g_empty_content_capabilities_info.Get();
}
ContentCapabilitiesHandler::ContentCapabilitiesHandler() = default;
ContentCapabilitiesHandler::~ContentCapabilitiesHandler() = default;
bool ContentCapabilitiesHandler::Parse(Extension* extension,
std::u16string* error) {
std::unique_ptr<ContentCapabilitiesInfo> info(new ContentCapabilitiesInfo);
const base::Value* value =
extension->manifest()->FindPath(keys::kContentCapabilities);
if (value == nullptr) {
*error = errors::kInvalidContentCapabilities;
return false;
}
auto capabilities = ContentCapabilities::FromValue(*value);
if (!capabilities.has_value()) {
*error = base::StrCat(
{errors::kInvalidContentCapabilitiesParsedValue, capabilities.error()});
return false;
}
int supported_schemes = URLPattern::SCHEME_HTTPS;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
::switches::kTestType)) {
// We don't have a suitable HTTPS test server, so this will have to do.
supported_schemes |= URLPattern::SCHEME_HTTP;
}
std::string url_error;
URLPatternSet potential_url_patterns;
if (!potential_url_patterns.Populate(capabilities->matches, supported_schemes,
false /* allow_file_access */,
&url_error)) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidContentCapabilitiesMatch, url_error);
return false;
}
// Filter URL patterns that imply all hosts or match every host under an
// eTLD and emit warnings for them.
// Note: we include private registries because content_capabilities should
// only be used for a single entity (though possibly multiple domains), rather
// than blanket-granted.
const net::registry_controlled_domains::PrivateRegistryFilter private_filter =
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES;
std::set<URLPattern> valid_url_patterns;
for (const URLPattern& pattern : potential_url_patterns) {
if (pattern.MatchesEffectiveTld(private_filter)) {
extension->AddInstallWarning(InstallWarning(
errors::kInvalidContentCapabilitiesMatchOrigin));
} else {
valid_url_patterns.insert(pattern);
}
}
info->url_patterns = URLPatternSet(valid_url_patterns);
// Filter invalid permissions and emit warnings for them.
for (const std::string& permission_name : capabilities->permissions) {
const APIPermissionInfo* permission_info = PermissionsInfo::GetInstance()
->GetByName(permission_name);
if (!permission_info || !permission_info->supports_content_capabilities()) {
extension->AddInstallWarning(InstallWarning(
errors::kInvalidContentCapabilitiesPermission,
keys::kContentCapabilities,
permission_name));
} else {
info->permissions.insert(permission_info->CreateAPIPermission());
}
}
extension->SetManifestData(keys::kContentCapabilities, std::move(info));
return true;
}
base::span<const char* const> ContentCapabilitiesHandler::Keys() const {
static constexpr const char* kKeys[] = {keys::kContentCapabilities};
return kKeys;
}
} // namespace extensions
|