[go: nahoru, domu]

blob: 5662eb9cdd38d3a73812e1bb2cb778ee93d3e58b [file] [log] [blame]
// Copyright 2020 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/web_app_file_handler.h"
#include <stddef.h>
#include <memory>
#include "base/containers/flat_set.h"
#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/install_warning.h"
#include "extensions/common/manifest_constants.h"
namespace extensions {
namespace keys = manifest_keys;
namespace errors = manifest_errors;
namespace {
base::Optional<base::flat_set<std::string>> LoadFileExtensions(
const base::Value& entry,
int* error_index) {
auto extract_file_extension =
[](const base::Value& entry) -> base::Optional<std::string> {
if (!entry.is_string())
return base::nullopt;
std::string file_extension = entry.GetString();
if (file_extension.empty() || file_extension[0] != '.')
return base::nullopt;
return file_extension;
};
// An accept entry can validly map from a MIME type to either a single file
// extension (a string), or alist of file extensions.
if (entry.is_string()) {
base::Optional<std::string> file_extension = extract_file_extension(entry);
if (!file_extension) {
*error_index = 0;
return base::nullopt;
}
return base::flat_set<std::string>{*file_extension};
}
DCHECK(entry.is_list());
base::flat_set<std::string> file_extensions;
base::Value::ConstListView entry_list = entry.GetList();
for (size_t i = 0; i < entry_list.size(); i++) {
base::Optional<std::string> file_extension =
extract_file_extension(entry_list[i]);
if (!file_extension) {
*error_index = i;
return base::nullopt;
}
file_extensions.insert(*file_extension);
}
return file_extensions;
}
bool LoadWebAppFileHandler(const std::string& manifest_entry_index,
const base::Value& manifest_entry,
apps::FileHandlers* file_handlers,
std::u16string* error,
std::vector<InstallWarning>* install_warnings) {
DCHECK(error);
const base::Value* action = manifest_entry.FindKeyOfType(
keys::kWebAppFileHandlerAction, base::Value::Type::STRING);
if (!action) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidWebAppFileHandlerAction, manifest_entry_index);
return false;
}
apps::FileHandler file_handler;
file_handler.action = GURL(action->GetString());
if (!file_handler.action.is_valid()) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidWebAppFileHandlerAction, manifest_entry_index);
return false;
}
const base::Value* accept = manifest_entry.FindKeyOfType(
keys::kWebAppFileHandlerAccept, base::Value::Type::DICTIONARY);
if (!accept) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidWebAppFileHandlerAccept, manifest_entry_index);
return false;
}
if (accept->DictEmpty()) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidWebAppFileHandlerEmptyAccept, manifest_entry_index);
return false;
}
for (const auto& manifest_accept_entry : accept->DictItems()) {
apps::FileHandler::AcceptEntry accept_entry;
accept_entry.mime_type = manifest_accept_entry.first;
if (!manifest_accept_entry.second.is_string() &&
!manifest_accept_entry.second.is_list()) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidWebAppFileHandlerFileExtensions, manifest_entry_index,
accept_entry.mime_type);
return false;
}
int error_index = -1;
base::Optional<base::flat_set<std::string>> file_extensions =
LoadFileExtensions(manifest_accept_entry.second, &error_index);
if (!file_extensions) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidWebAppFileHandlerFileExtension, manifest_entry_index,
accept_entry.mime_type, base::NumberToString(error_index));
return false;
}
accept_entry.file_extensions = std::move(*file_extensions);
file_handler.accept.push_back(std::move(accept_entry));
}
file_handlers->push_back(std::move(file_handler));
return true;
}
} // namespace
WebAppFileHandlers::WebAppFileHandlers() = default;
WebAppFileHandlers::~WebAppFileHandlers() = default;
// static
const apps::FileHandlers* WebAppFileHandlers::GetWebAppFileHandlers(
const Extension* extension) {
if (!extension)
return nullptr;
WebAppFileHandlers* manifest_data = static_cast<WebAppFileHandlers*>(
extension->GetManifestData(keys::kWebAppFileHandlers));
return manifest_data ? &manifest_data->file_handlers : nullptr;
}
WebAppFileHandlersParser::WebAppFileHandlersParser() = default;
WebAppFileHandlersParser::~WebAppFileHandlersParser() = default;
bool WebAppFileHandlersParser::Parse(Extension* extension,
std::u16string* error) {
// The "web_app_file_handlers" key is only available for Bookmark Apps.
// Including it elsewhere results in an install warning, and the file handlers
// are not parsed.
if (!extension->from_bookmark()) {
extension->AddInstallWarning(
InstallWarning(errors::kInvalidWebAppFileHandlersNotBookmarkApp));
return true;
}
std::unique_ptr<WebAppFileHandlers> manifest_data =
std::make_unique<WebAppFileHandlers>();
const base::Value* file_handlers = nullptr;
if (!extension->manifest()->GetList(keys::kWebAppFileHandlers,
&file_handlers)) {
*error = base::ASCIIToUTF16(errors::kInvalidWebAppFileHandlers);
return false;
}
std::vector<InstallWarning> install_warnings;
base::Value::ConstListView file_handlers_list = file_handlers->GetList();
for (size_t i = 0; i < file_handlers_list.size(); i++) {
std::string manifest_entry_index = base::NumberToString(i);
if (!file_handlers_list[i].is_dict()) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidWebAppFileHandler, manifest_entry_index);
return false;
}
if (!LoadWebAppFileHandler(manifest_entry_index, file_handlers_list[i],
&manifest_data->file_handlers, error,
&install_warnings)) {
return false;
}
}
extension->SetManifestData(keys::kWebAppFileHandlers,
std::move(manifest_data));
extension->AddInstallWarnings(std::move(install_warnings));
return true;
}
base::span<const char* const> WebAppFileHandlersParser::Keys() const {
static constexpr const char* kKeys[] = {keys::kWebAppFileHandlers};
return kKeys;
}
} // namespace extensions