blob: f3cc32d266c4ef96afc17ac60c2e1be5c412d225 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// 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/webview_info.h"
#include <stddef.h>
#include <memory>
#include <utility>
#include "base/strings/pattern.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
namespace extensions {
namespace keys = extensions::manifest_keys;
namespace errors = extensions::manifest_errors;
// A PartitionItem represents a set of accessible resources given a partition
// ID pattern.
class PartitionItem {
public:
explicit PartitionItem(const std::string& partition_pattern)
: partition_pattern_(partition_pattern) {
}
virtual ~PartitionItem() {
}
bool Matches(const std::string& partition_id) const {
return base::MatchPattern(partition_id, partition_pattern_);
}
// Adds a pattern to the set. Returns true if a new pattern was inserted,
// false if the pattern was already in the set.
bool AddPattern(const URLPattern& pattern) {
return accessible_resources_.AddPattern(pattern);
}
const URLPatternSet& accessible_resources() const {
return accessible_resources_;
}
private:
// A pattern string that matches partition IDs.
const std::string partition_pattern_;
// A URL pattern set of resources accessible to the given
// |partition_pattern_|.
URLPatternSet accessible_resources_;
};
WebviewInfo::WebviewInfo(const std::string& extension_id)
: extension_id_(extension_id) {
}
WebviewInfo::~WebviewInfo() {
}
// static
bool WebviewInfo::IsResourceWebviewAccessible(
const Extension* extension,
const std::string& partition_id,
const std::string& relative_path) {
if (!extension)
return false;
const WebviewInfo* webview_info = static_cast<const WebviewInfo*>(
extension->GetManifestData(keys::kWebviewAccessibleResources));
if (!webview_info)
return false;
for (const auto& item : webview_info->partition_items_) {
if (item->Matches(partition_id) &&
extension->ResourceMatches(item->accessible_resources(),
relative_path)) {
return true;
}
}
return false;
}
// static
bool WebviewInfo::HasWebviewAccessibleResources(
const Extension& extension,
const std::string& partition_id) {
const WebviewInfo* webview_info = static_cast<const WebviewInfo*>(
extension.GetManifestData(keys::kWebviewAccessibleResources));
if (!webview_info)
return false;
for (const auto& item : webview_info->partition_items_) {
if (item->Matches(partition_id))
return true;
}
return false;
}
void WebviewInfo::AddPartitionItem(std::unique_ptr<PartitionItem> item) {
partition_items_.push_back(std::move(item));
}
WebviewHandler::WebviewHandler() {
}
WebviewHandler::~WebviewHandler() {
}
bool WebviewHandler::Parse(Extension* extension, base::string16* error) {
std::unique_ptr<WebviewInfo> info(new WebviewInfo(extension->id()));
const base::Value* dict_value = nullptr;
if (!extension->manifest()->GetDictionary(keys::kWebview,
&dict_value)) {
*error = base::ASCIIToUTF16(errors::kInvalidWebview);
return false;
}
const base::Value* partition_list = dict_value->FindKeyOfType(
keys::kWebviewPartitions, base::Value::Type::LIST);
if (partition_list == nullptr) {
*error = base::ASCIIToUTF16(errors::kInvalidWebviewPartitionsList);
return false;
}
// The partition list must have at least one entry.
const base::Value::ListStorage& partition_list_storage =
partition_list->GetList();
if (partition_list_storage.empty()) {
*error = base::ASCIIToUTF16(errors::kInvalidWebviewPartitionsList);
return false;
}
for (size_t i = 0; i < partition_list_storage.size(); ++i) {
if (!partition_list_storage[i].is_dict()) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidWebviewPartition, base::NumberToString(i));
return false;
}
const base::Value* webview_name = partition_list_storage[i].FindKeyOfType(
keys::kWebviewName, base::Value::Type::STRING);
if (webview_name == nullptr) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidWebviewPartitionName, base::NumberToString(i));
return false;
}
const std::string& partition_pattern = webview_name->GetString();
const base::Value* url_list = partition_list_storage[i].FindKeyOfType(
keys::kWebviewAccessibleResources, base::Value::Type::LIST);
if (url_list == nullptr) {
*error = base::ASCIIToUTF16(
errors::kInvalidWebviewAccessibleResourcesList);
return false;
}
// The URL list should have at least one entry.
const base::Value::ListStorage& url_list_storage = url_list->GetList();
if (url_list_storage.empty()) {
*error = base::ASCIIToUTF16(
errors::kInvalidWebviewAccessibleResourcesList);
return false;
}
auto partition_item = std::make_unique<PartitionItem>(partition_pattern);
for (size_t i = 0; i < url_list_storage.size(); ++i) {
if (!url_list_storage[i].is_string()) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidWebviewAccessibleResource, base::NumberToString(i));
return false;
}
partition_item->AddPattern(
URLPattern(URLPattern::SCHEME_EXTENSION,
Extension::GetResourceURL(extension->url(),
url_list_storage[i].GetString())
.spec()));
}
info->AddPartitionItem(std::move(partition_item));
}
extension->SetManifestData(keys::kWebviewAccessibleResources,
std::move(info));
return true;
}
base::span<const char* const> WebviewHandler::Keys() const {
static constexpr const char* kKeys[] = {keys::kWebview};
return kKeys;
}
} // namespace extensions