Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement per-origin noscript #97

Merged
merged 3 commits into from
May 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ deps = {
"vendor/tracking-protection": "https://github.com/brave/tracking-protection.git@051177425a14121a22087d754ad8eb1c0ce8fb24",
"vendor/hashset-cpp": "https://github.com/brave/hashset-cpp.git@67ffffa69b56e330bab9d08f050727f891c916a1",
"vendor/bloom-filter-cpp": "https://github.com/brave/bloom-filter-cpp.git@d511cf872ea1d650ab8dc4662f6036dac012d197",
"vendor/brave-extension": "https://github.com/brave/brave-extension.git@af3a95d08868741c179707b6839e564f9d95d4dc",
"vendor/brave-extension": "https://github.com/brave/brave-extension.git@2751cf40937d1a3893f44d0d4fd32952ab4df194",
"vendor/requests": "https://github.com/kennethreitz/requests@e4d59bedfd3c7f4f254f4f5d036587bcd8152458",
"vendor/boto": "https://github.com/boto/boto@f7574aa6cc2c819430c1f05e9a1a1a666ef8169b",
"vendor/python-patch": "https://github.com/svn2github/python-patch@a336a458016ced89aba90dfc3f4c8222ae3b1403",
Expand Down
3 changes: 2 additions & 1 deletion browser/extensions/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ source_set("extensions") {
]
deps = [
"//brave/browser/resources:brave_extension_grit",
"//chrome/browser"
"//chrome/browser",
"//content/public/browser",
]
}
33 changes: 31 additions & 2 deletions browser/extensions/api/brave_shields_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,42 @@

#include "brave/browser/extensions/api/brave_shields_api.h"

#include "brave/common/extensions/api/brave_shields.h"
#include "brave/components/brave_shields/browser/brave_shields_web_contents_observer.h"
#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/web_contents.h"

using brave_shields::BraveShieldsWebContentsObserver;

namespace extensions {
namespace api {

BraveShieldsDummyFunction::~BraveShieldsDummyFunction() {
BraveShieldsAllowScriptsOnceFunction::~BraveShieldsAllowScriptsOnceFunction() {
}

ExtensionFunction::ResponseAction BraveShieldsDummyFunction::Run() {
ExtensionFunction::ResponseAction BraveShieldsAllowScriptsOnceFunction::Run() {
std::unique_ptr<brave_shields::AllowScriptsOnce::Params> params(
brave_shields::AllowScriptsOnce::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());

// Get web contents for this tab
content::WebContents* contents = nullptr;
if (!ExtensionTabUtil::GetTabById(
params->tab_id,
Profile::FromBrowserContext(browser_context()),
include_incognito(),
nullptr,
nullptr,
&contents,
nullptr)) {
return RespondNow(Error(tabs_constants::kTabNotFoundError,
base::IntToString(params->tab_id)));
}

BraveShieldsWebContentsObserver::FromWebContents(
contents)->AllowScriptsOnce(params->origins, contents);
return RespondNow(NoArguments());
}

Expand Down
12 changes: 6 additions & 6 deletions browser/extensions/api/brave_shields_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef BRAVE_COMMON_EXTENSIONS_API_BRAVE_SHIELDS_API_H_
#define BRAVE_COMMON_EXTENSIONS_API_BRAVE_SHIELDS_API_H_
#ifndef BRAVE_BROWSER_EXTENSIONS_API_BRAVE_SHIELDS_API_H_
#define BRAVE_BROWSER_EXTENSIONS_API_BRAVE_SHIELDS_API_H_

#include "extensions/browser/extension_function.h"

namespace extensions {
namespace api {

class BraveShieldsDummyFunction : public UIThreadExtensionFunction {
class BraveShieldsAllowScriptsOnceFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("braveShields.dummy", UNKNOWN)
DECLARE_EXTENSION_FUNCTION("braveShields.allowScriptsOnce", UNKNOWN)

protected:
~BraveShieldsDummyFunction() override;
~BraveShieldsAllowScriptsOnceFunction() override;

ResponseAction Run() override;
};

} // namespace api
} // namespace extensions

#endif // BRAVE_COMMON_EXTENSIONS_API_BRAVE_SHIELDS_API_H_
#endif // BRAVE_BROWSER_EXTENSIONS_API_BRAVE_SHIELDS_API_H_
122 changes: 122 additions & 0 deletions browser/extensions/api/brave_shields_api_browsertest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "base/path_service.h"
#include "brave/browser/extensions/api/brave_shields_api.h"
#include "brave/common/brave_paths.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test_utils.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 "extensions/common/extension_builder.h"
#include "net/dns/mock_host_resolver.h"

using extensions::api::BraveShieldsAllowScriptsOnceFunction;
using extension_function_test_utils::RunFunctionAndReturnError;
using extension_function_test_utils::RunFunctionAndReturnSingleResult;

class BraveShieldsAPIBrowserTest : public InProcessBrowserTest {
public:
void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
content::SetupCrossSiteRedirector(embedded_test_server());

brave::RegisterPathProvider();
base::FilePath test_data_dir;
PathService::Get(brave::DIR_TEST_DATA, &test_data_dir);
embedded_test_server()->ServeFilesFromDirectory(test_data_dir);

ASSERT_TRUE(embedded_test_server()->Start());
extension_ = extensions::ExtensionBuilder("Test").Build();
}

content::WebContents* active_contents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}

scoped_refptr<extensions::Extension> extension() {
return extension_;
}

void BlockScripts() {
HostContentSettingsMap* content_settings =
HostContentSettingsMapFactory::GetForProfile(browser()->profile());
content_settings->SetContentSettingCustomScope(
ContentSettingsPattern::Wildcard(), ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_JAVASCRIPT, "", CONTENT_SETTING_BLOCK);
}

bool NavigateToURLUntilLoadStop(
const std::string& origin, const std::string& path) {
ui_test_utils::NavigateToURL(
browser(),
embedded_test_server()->GetURL(origin, path));

return WaitForLoadStop(active_contents());
}

private:
scoped_refptr<extensions::Extension> extension_;
};

IN_PROC_BROWSER_TEST_F(BraveShieldsAPIBrowserTest, AllowScriptsOnce) {
BlockScripts();

EXPECT_TRUE(
NavigateToURLUntilLoadStop("a.com", "/load_js_from_origins.html"));
EXPECT_EQ(active_contents()->GetAllFrames().size(), 1u) <<
"All script loadings should be blocked.";

// run extension function to temporarily allow a.com
scoped_refptr<BraveShieldsAllowScriptsOnceFunction> function(
new BraveShieldsAllowScriptsOnceFunction());
function->set_extension(extension().get());
function->set_has_callback(true);

const GURL url(embedded_test_server()->GetURL("a.com", "/simple.js"));
const std::string allow_origin = url.GetOrigin().spec();
int tabId = extensions::ExtensionTabUtil::GetTabId(active_contents());

RunFunctionAndReturnSingleResult(
function.get(),
"[[\"" + allow_origin + "\"], " + std::to_string(tabId) + "]",
browser());

// reload page with a.com temporarily allowed
active_contents()->GetController().Reload(content::ReloadType::NORMAL,
true);
EXPECT_TRUE(WaitForLoadStop(active_contents()));
EXPECT_EQ(active_contents()->GetAllFrames().size(), 2u) <<
"Scripts from a.com should be temporarily allowed.";

// reload page again
active_contents()->GetController().Reload(content::ReloadType::NORMAL,
true);
EXPECT_TRUE(WaitForLoadStop(active_contents()));
EXPECT_EQ(active_contents()->GetAllFrames().size(), 2u) <<
"Scripts from a.com should be temporarily allowed after reload.";

// same doc navigation
ui_test_utils::NavigateToURL(
browser(),
embedded_test_server()->GetURL("a.com", "/load_js_from_origins.html#foo"));
EXPECT_TRUE(WaitForLoadStop(active_contents()));
EXPECT_EQ(active_contents()->GetAllFrames().size(), 2u) <<
"Scripts from a.com should be temporarily allowed for same doc navigation.";

// navigate to a different origin
ui_test_utils::NavigateToURL(
browser(),
embedded_test_server()->GetURL("b.com", "/load_js_from_origins.html"));
EXPECT_TRUE(WaitForLoadStop(active_contents()));
EXPECT_EQ(active_contents()->GetAllFrames().size(), 1u) <<
"All script loadings should be blocked after navigating away.";
}
21 changes: 16 additions & 5 deletions common/extensions/api/brave_shields.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,24 @@
],
"functions": [
{
"name": "dummy",
"name": "allowScriptsOnce",
"type": "function",
"description": "Remove me when there were actual fucntions implemented",
"properties": [
"description": "Allow scripts from a list of origins until next reload",
"parameters": [
{
"type": "integer",
"name": "dummyArg"
"name": "origins",
"type": "array",
"items": {"type": "string"}
},
{
"name": "tabID",
"type": "integer"
},
{
"type": "function",
"name": "callback",
"optional": true,
"parameters": []
}
]
}
Expand Down
1 change: 1 addition & 0 deletions components/brave_shields/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ source_set("brave_shields") {
"//brave/vendor/tracking-protection/brave:tracking-protection",
]
public_deps = [
"//brave/content:common",
"//chrome/common",
"//third_party/leveldatabase",
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "brave/common/render_messages.h"
#include "brave/components/brave_shields/browser/brave_shields_util.h"
#include "brave/components/brave_shields/common/brave_shield_constants.h"
#include "brave/content/common/frame_messages.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/profiles/profile.h"
Expand Down Expand Up @@ -306,6 +307,22 @@ void BraveShieldsWebContentsObserver::ReadyToCommitNavigation(
original_referrer.policy, &new_referrer)) {
navigation_entry->SetReferrer(new_referrer);
}

// when the main frame navigate away
if (navigation_handle->IsInMainFrame() &&
!navigation_handle->IsSameDocument() &&
navigation_handle->GetReloadType() == content::ReloadType::NONE) {
allowed_script_origins_.clear();
}

navigation_handle->GetWebContents()->SendToAllFrames(
new BraveFrameMsg_AllowScriptsOnce(
MSG_ROUTING_NONE, allowed_script_origins_));
}

void BraveShieldsWebContentsObserver::AllowScriptsOnce(
const std::vector<std::string>& origins, WebContents* contents) {
allowed_script_origins_ = std::move(origins);
}

} // namespace brave_shields
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class BraveShieldsWebContentsObserver : public content::WebContentsObserver,
int render_process_id,
int render_frame_id, int frame_tree_node_id);
static GURL GetTabURLFromRenderFrameInfo(int render_process_id, int render_frame_id);
void AllowScriptsOnce(const std::vector<std::string>& origins,
content::WebContents* web_contents);

protected:
// A set of identifiers that uniquely identifies a RenderFrame.
Expand Down Expand Up @@ -75,6 +77,11 @@ class BraveShieldsWebContentsObserver : public content::WebContentsObserver,
// This lock protects |frame_data_map_| from being concurrently written on the
// UI thread and read on the IO thread.
static base::Lock frame_data_map_lock_;

private:
friend class content::WebContentsUserData<BraveShieldsWebContentsObserver>;
std::vector<std::string> allowed_script_origins_;

DISALLOW_COPY_AND_ASSIGN(BraveShieldsWebContentsObserver);
};

Expand Down
10 changes: 10 additions & 0 deletions content/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
source_set("common") {
sources = [
"common/content_message_generator.cc",
"common/content_message_generator.h",
]

deps = [
"//ipc"
]
}
30 changes: 30 additions & 0 deletions content/common/content_message_generator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Get basic type definitions.
#define IPC_MESSAGE_IMPL

#include "brave/content/common/content_message_generator.h"

// Generate constructors.
#include "ipc/struct_constructor_macros.h"
#include "brave/content/common/content_message_generator.h"

// Generate destructors.
#include "ipc/struct_destructor_macros.h"
#include "brave/content/common/content_message_generator.h"

// Generate param traits write methods.
#include "ipc/param_traits_write_macros.h"
namespace IPC {
#include "brave/content/common/content_message_generator.h"
} // namespace IPC

// Generate param traits read methods.
#include "ipc/param_traits_read_macros.h"
namespace IPC {
#include "brave/content/common/content_message_generator.h"
} // namespace IPC

// Generate param traits log methods.
#include "ipc/param_traits_log_macros.h"
namespace IPC {
#include "brave/content/common/content_message_generator.h"
} // namespace IPC
2 changes: 2 additions & 0 deletions content/common/content_message_generator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Multiply-included file, no traditional include guard.
#include "brave/content/common/frame_messages.h"
17 changes: 17 additions & 0 deletions content/common/frame_messages.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

// Multiply-included file, no traditional include guard.
#include <vector>

#include "ipc/ipc_message_macros.h"

// The message starter should be declared in ipc/ipc_message_start.h. Since
// we don't want to patch Chromium, we just pretend to be Content Shell.

#define IPC_MESSAGE_START ShellMsgStart

// Tell RenderFrame(s) to temporary allow scripts from a list of origins once.
IPC_MESSAGE_ROUTED1(BraveFrameMsg_AllowScriptsOnce,
std::vector<std::string> /* origins to allow scripts once */)
1 change: 1 addition & 0 deletions renderer/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ source_set("renderer") {
"//skia",
"//third_party/WebKit/public:blink",
"//brave/chromium_src:renderer",
"//brave/content:common",
]
}
Loading