blob: 524e7ae1a66037edb1001b798e2d8dfc1f1fa35a [file] [log] [blame]
// Copyright 2018 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/browser/api/declarative_net_request/declarative_net_request_api.h"
#include <utility>
#include "base/bind.h"
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/api/declarative_net_request/rules_monitor_service.h"
#include "extensions/browser/api/declarative_net_request/ruleset_manager.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/info_map.h"
#include "extensions/common/api/declarative_net_request.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/url_pattern.h"
#include "extensions/common/url_pattern_set.h"
namespace extensions {
namespace {
// Returns true if the given |extension| has a registered ruleset. If it
// doesn't, returns false and populates |error|.
bool HasRegisteredRuleset(content::BrowserContext* context,
const ExtensionId& extension_id,
std::string* error) {
const auto* rules_monitor_service = BrowserContextKeyedAPIFactory<
declarative_net_request::RulesMonitorService>::Get(context);
DCHECK(rules_monitor_service);
if (rules_monitor_service->HasRegisteredRuleset(extension_id))
return true;
*error = "The extension must have a ruleset in order to call this function.";
return false;
}
void UpdateAllowPagesOnIOThread(const ExtensionId& extension_id,
URLPatternSet allowed_pages,
InfoMap* info_map) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(info_map);
info_map->GetRulesetManager()->UpdateAllowedPages(extension_id,
std::move(allowed_pages));
}
} // namespace
DeclarativeNetRequestUpdateAllowedPagesFunction::
DeclarativeNetRequestUpdateAllowedPagesFunction() = default;
DeclarativeNetRequestUpdateAllowedPagesFunction::
~DeclarativeNetRequestUpdateAllowedPagesFunction() = default;
ExtensionFunction::ResponseAction
DeclarativeNetRequestUpdateAllowedPagesFunction::UpdateAllowedPages(
const std::vector<std::string>& patterns,
Action action) {
if (patterns.empty())
return RespondNow(NoArguments());
// It's ok to allow file access and to use SCHEME_ALL since this is not
// actually granting any permissions to the extension. This will only be used
// to allow requests.
URLPatternSet delta;
std::string error;
if (!delta.Populate(patterns, URLPattern::SCHEME_ALL,
true /*allow_file_access*/, &error)) {
return RespondNow(Error(error));
}
ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
URLPatternSet current_set = prefs->GetDNRAllowedPages(extension_id());
URLPatternSet new_set;
switch (action) {
case Action::ADD:
new_set = URLPatternSet::CreateUnion(current_set, delta);
break;
case Action::REMOVE:
new_set = URLPatternSet::CreateDifference(current_set, delta);
break;
}
if (static_cast<int>(new_set.size()) >
api::declarative_net_request::MAX_NUMBER_OF_ALLOWED_PAGES) {
return RespondNow(Error(base::StringPrintf(
"The number of allowed page patterns can't exceed %d",
api::declarative_net_request::MAX_NUMBER_OF_ALLOWED_PAGES)));
}
// Persist |new_set| as part of preferences.
prefs->SetDNRAllowedPages(extension_id(), new_set.Clone());
// Update the new allowed set on the IO thread.
base::OnceClosure updated_allow_pages_io_task = base::BindOnce(
&UpdateAllowPagesOnIOThread, extension_id(), std::move(new_set),
base::RetainedRef(ExtensionSystem::Get(browser_context())->info_map()));
base::OnceClosure updated_allowed_pages_ui_reply = base::BindOnce(
&DeclarativeNetRequestUpdateAllowedPagesFunction::OnAllowedPagesUpdated,
this);
base::PostTaskWithTraitsAndReply(FROM_HERE, {content::BrowserThread::IO},
std::move(updated_allow_pages_io_task),
std::move(updated_allowed_pages_ui_reply));
return RespondLater();
}
void DeclarativeNetRequestUpdateAllowedPagesFunction::OnAllowedPagesUpdated() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
Respond(NoArguments());
}
bool DeclarativeNetRequestUpdateAllowedPagesFunction::PreRunValidation(
std::string* error) {
return UIThreadExtensionFunction::PreRunValidation(error) &&
HasRegisteredRuleset(browser_context(), extension_id(), error);
}
DeclarativeNetRequestAddAllowedPagesFunction::
DeclarativeNetRequestAddAllowedPagesFunction() = default;
DeclarativeNetRequestAddAllowedPagesFunction::
~DeclarativeNetRequestAddAllowedPagesFunction() = default;
ExtensionFunction::ResponseAction
DeclarativeNetRequestAddAllowedPagesFunction::Run() {
using Params = api::declarative_net_request::AddAllowedPages::Params;
base::string16 error;
std::unique_ptr<Params> params(Params::Create(*args_, &error));
EXTENSION_FUNCTION_VALIDATE(params);
// EXTENSION_FUNCTION_VALIDATE should validate that the arguments are in the
// correct format. Ignore |error|.
return UpdateAllowedPages(params->page_patterns, Action::ADD);
}
DeclarativeNetRequestRemoveAllowedPagesFunction::
DeclarativeNetRequestRemoveAllowedPagesFunction() = default;
DeclarativeNetRequestRemoveAllowedPagesFunction::
~DeclarativeNetRequestRemoveAllowedPagesFunction() = default;
ExtensionFunction::ResponseAction
DeclarativeNetRequestRemoveAllowedPagesFunction::Run() {
using Params = api::declarative_net_request::AddAllowedPages::Params;
base::string16 error;
std::unique_ptr<Params> params(Params::Create(*args_, &error));
EXTENSION_FUNCTION_VALIDATE(params);
// EXTENSION_FUNCTION_VALIDATE should validate that the arguments are in the
// correct format. Ignore |error|.
return UpdateAllowedPages(params->page_patterns, Action::REMOVE);
}
DeclarativeNetRequestGetAllowedPagesFunction::
DeclarativeNetRequestGetAllowedPagesFunction() = default;
DeclarativeNetRequestGetAllowedPagesFunction::
~DeclarativeNetRequestGetAllowedPagesFunction() = default;
bool DeclarativeNetRequestGetAllowedPagesFunction::PreRunValidation(
std::string* error) {
return UIThreadExtensionFunction::PreRunValidation(error) &&
HasRegisteredRuleset(browser_context(), extension_id(), error);
}
ExtensionFunction::ResponseAction
DeclarativeNetRequestGetAllowedPagesFunction::Run() {
const ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
URLPatternSet current_set = prefs->GetDNRAllowedPages(extension_id());
return RespondNow(ArgumentList(
api::declarative_net_request::GetAllowedPages::Results::Create(
*current_set.ToStringVector())));
}
} // namespace extensions