Skip to content

Commit 6d12cf3

Browse files
committed
Inject braveRequestAdsEnabled() js function.
fix brave/brave-browser#16964
1 parent 26dff20 commit 6d12cf3

9 files changed

+359
-0
lines changed
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
source_set("renderer") {
2+
sources = [
3+
"brave_ads_js_handler.cc",
4+
"brave_ads_js_handler.h",
5+
"brave_ads_render_frame_observer.cc",
6+
"brave_ads_render_frame_observer.h",
7+
]
8+
9+
deps = [
10+
"//base",
11+
"//brave/components/brave_ads/common:mojom",
12+
"//content/public/renderer",
13+
"//gin",
14+
"//mojo/public/cpp/bindings",
15+
"//third_party/blink/public:blink",
16+
"//third_party/blink/public/common",
17+
"//v8",
18+
]
19+
}

components/brave_ads/renderer/DEPS

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
include_rules = [
2+
"+brave/components/brave_ads/common",
3+
"+content/public/renderer",
4+
"+gin",
5+
"+mojo/public/cpp/bindings",
6+
"+third_party/blink/public",
7+
"+v8/include",
8+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/* Copyright (c) 2021 The Brave Authors. All rights reserved.
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
* You can obtain one at http://mozilla.org/MPL/2.0/. */
5+
6+
#include "brave/components/brave_ads/renderer/brave_ads_js_handler.h"
7+
8+
#include <utility>
9+
10+
#include "base/no_destructor.h"
11+
#include "content/public/renderer/render_frame.h"
12+
#include "gin/arguments.h"
13+
#include "gin/function_template.h"
14+
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
15+
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
16+
#include "third_party/blink/public/platform/web_string.h"
17+
#include "third_party/blink/public/web/blink.h"
18+
#include "third_party/blink/public/web/web_console_message.h"
19+
#include "third_party/blink/public/web/web_local_frame.h"
20+
#include "third_party/blink/public/web/web_script_source.h"
21+
22+
namespace brave_ads {
23+
24+
namespace {
25+
26+
constexpr char kUserGestureRejectReason[] =
27+
"braveRequestAdsEnabled: API can only be initiated by a user gesture.";
28+
29+
} // namespace
30+
31+
BraveAdsJSHandler::BraveAdsJSHandler(content::RenderFrame* render_frame)
32+
: render_frame_(render_frame) {}
33+
34+
BraveAdsJSHandler::~BraveAdsJSHandler() = default;
35+
36+
void BraveAdsJSHandler::AddJavaScriptObjectToFrame(
37+
v8::Local<v8::Context> context) {
38+
v8::Isolate* isolate = blink::MainThreadIsolate();
39+
v8::HandleScope handle_scope(isolate);
40+
if (context.IsEmpty()) {
41+
return;
42+
}
43+
44+
v8::Context::Scope context_scope(context);
45+
46+
BindFunctionsToObject(isolate, context);
47+
}
48+
49+
void BraveAdsJSHandler::BindFunctionsToObject(v8::Isolate* isolate,
50+
v8::Local<v8::Context> context) {
51+
v8::Local<v8::Object> global = context->Global();
52+
v8::Local<v8::Object> chrome_obj;
53+
v8::Local<v8::Value> chrome_value;
54+
if (!global->Get(context, gin::StringToV8(isolate, "chrome"))
55+
.ToLocal(&chrome_value) ||
56+
!chrome_value->IsObject()) {
57+
chrome_obj = v8::Object::New(isolate);
58+
global->Set(context, gin::StringToSymbol(isolate, "chrome"), chrome_obj)
59+
.Check();
60+
} else {
61+
chrome_obj = chrome_value->ToObject(context).ToLocalChecked();
62+
}
63+
64+
BindFunctionToObject(
65+
isolate, chrome_obj, "braveRequestAdsEnabled",
66+
base::BindRepeating(&BraveAdsJSHandler::RequestAdsEnabled,
67+
base::Unretained(this)));
68+
}
69+
70+
template <typename Sig>
71+
void BraveAdsJSHandler::BindFunctionToObject(
72+
v8::Isolate* isolate,
73+
v8::Local<v8::Object> javascript_object,
74+
const std::string& name,
75+
const base::RepeatingCallback<Sig>& callback) {
76+
v8::Local<v8::Context> context = isolate->GetCurrentContext();
77+
javascript_object
78+
->Set(context, gin::StringToSymbol(isolate, name),
79+
gin::CreateFunctionTemplate(isolate, callback)
80+
->GetFunction(context)
81+
.ToLocalChecked())
82+
.Check();
83+
}
84+
85+
bool BraveAdsJSHandler::EnsureConnected() {
86+
if (!brave_ads_.is_bound()) {
87+
render_frame_->GetBrowserInterfaceBroker()->GetInterface(
88+
brave_ads_.BindNewPipeAndPassReceiver());
89+
brave_ads_.set_disconnect_handler(base::BindOnce(
90+
&BraveAdsJSHandler::OnRemoteDisconnect, base::Unretained(this)));
91+
}
92+
93+
return brave_ads_.is_bound();
94+
}
95+
96+
void BraveAdsJSHandler::OnRemoteDisconnect() {
97+
brave_ads_.reset();
98+
EnsureConnected();
99+
}
100+
101+
v8::Local<v8::Promise> BraveAdsJSHandler::RequestAdsEnabled(
102+
v8::Isolate* isolate) {
103+
if (!EnsureConnected()) {
104+
return v8::Local<v8::Promise>();
105+
}
106+
107+
v8::MaybeLocal<v8::Promise::Resolver> maybe_resolver =
108+
v8::Promise::Resolver::New(isolate->GetCurrentContext());
109+
if (maybe_resolver.IsEmpty()) {
110+
return v8::Local<v8::Promise>();
111+
}
112+
113+
v8::Local<v8::Promise::Resolver> resolver = maybe_resolver.ToLocalChecked();
114+
115+
auto* web_frame = render_frame_->GetWebFrame();
116+
DCHECK(web_frame);
117+
if (!web_frame->HasTransientUserActivation()) {
118+
v8::Local<v8::String> result =
119+
v8::String::NewFromUtf8(isolate, kUserGestureRejectReason)
120+
.ToLocalChecked();
121+
ALLOW_UNUSED_LOCAL(resolver->Reject(isolate->GetCurrentContext(), result));
122+
return resolver->GetPromise();
123+
}
124+
125+
auto promise_resolver = std::make_unique<v8::Global<v8::Promise::Resolver>>();
126+
promise_resolver->Reset(isolate, resolver);
127+
auto context_old = std::make_unique<v8::Global<v8::Context>>(
128+
isolate, isolate->GetCurrentContext());
129+
brave_ads_->RequestAdsEnabled(base::BindOnce(
130+
&BraveAdsJSHandler::OnRequestAdsEnabled, base::Unretained(this),
131+
std::move(promise_resolver), isolate, std::move(context_old)));
132+
133+
return resolver->GetPromise();
134+
}
135+
136+
void BraveAdsJSHandler::OnRequestAdsEnabled(
137+
std::unique_ptr<v8::Global<v8::Promise::Resolver>> promise_resolver,
138+
v8::Isolate* isolate,
139+
std::unique_ptr<v8::Global<v8::Context>> context_old,
140+
bool response) {
141+
v8::HandleScope handle_scope(isolate);
142+
v8::Local<v8::Context> context = context_old->Get(isolate);
143+
v8::Context::Scope context_scope(context);
144+
v8::MicrotasksScope microtasks(isolate,
145+
v8::MicrotasksScope::kDoNotRunMicrotasks);
146+
147+
v8::Local<v8::Promise::Resolver> resolver = promise_resolver->Get(isolate);
148+
v8::Local<v8::Boolean> result = v8::Boolean::New(isolate, response);
149+
150+
ALLOW_UNUSED_LOCAL(resolver->Resolve(context, result));
151+
}
152+
153+
} // namespace brave_ads
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/* Copyright (c) 2021 The Brave Authors. All rights reserved.
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
* You can obtain one at http://mozilla.org/MPL/2.0/. */
5+
6+
#ifndef BRAVE_COMPONENTS_BRAVE_ADS_RENDERER_BRAVE_ADS_JS_HANDLER_H_
7+
#define BRAVE_COMPONENTS_BRAVE_ADS_RENDERER_BRAVE_ADS_JS_HANDLER_H_
8+
9+
#include <memory>
10+
#include <string>
11+
12+
#include "base/callback.h"
13+
#include "brave/components/brave_ads/common/brave_ads_host.mojom.h"
14+
#include "mojo/public/cpp/bindings/remote.h"
15+
#include "v8/include/v8.h"
16+
17+
namespace content {
18+
class RenderFrame;
19+
}
20+
21+
namespace brave_ads {
22+
23+
class BraveAdsJSHandler final {
24+
public:
25+
explicit BraveAdsJSHandler(content::RenderFrame* render_frame);
26+
BraveAdsJSHandler(const BraveAdsJSHandler&) = delete;
27+
BraveAdsJSHandler& operator=(const BraveAdsJSHandler&) = delete;
28+
~BraveAdsJSHandler();
29+
30+
void AddJavaScriptObjectToFrame(v8::Local<v8::Context> context);
31+
32+
private:
33+
// Adds a function to the provided object.
34+
template <typename Sig>
35+
void BindFunctionToObject(v8::Isolate* isolate,
36+
v8::Local<v8::Object> javascript_object,
37+
const std::string& name,
38+
const base::RepeatingCallback<Sig>& callback);
39+
void BindFunctionsToObject(v8::Isolate* isolate,
40+
v8::Local<v8::Context> context);
41+
bool EnsureConnected();
42+
void OnRemoteDisconnect();
43+
44+
// A function to be called from JS
45+
v8::Local<v8::Promise> RequestAdsEnabled(v8::Isolate* isolate);
46+
void OnRequestAdsEnabled(
47+
std::unique_ptr<v8::Global<v8::Promise::Resolver>> promise_resolver,
48+
v8::Isolate* isolate,
49+
std::unique_ptr<v8::Global<v8::Context>> context_old,
50+
bool response);
51+
52+
content::RenderFrame* render_frame_;
53+
mojo::Remote<brave_ads::mojom::BraveAdsHost> brave_ads_;
54+
};
55+
56+
} // namespace brave_ads
57+
58+
#endif // BRAVE_COMPONENTS_BRAVE_ADS_RENDERER_BRAVE_ADS_JS_HANDLER_H_
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) 2021 The Brave Authors. All rights reserved.
2+
// This Source Code Form is subject to the terms of the Mozilla Public
3+
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
// you can obtain one at http://mozilla.org/MPL/2.0/.
5+
6+
#include "brave/components/brave_ads/renderer/brave_ads_render_frame_observer.h"
7+
8+
#include <string>
9+
#include <vector>
10+
11+
#include "base/containers/contains.h"
12+
#include "base/containers/fixed_flat_set.h"
13+
#include "brave/components/brave_ads/renderer/brave_ads_js_handler.h"
14+
#include "content/public/renderer/render_frame.h"
15+
#include "third_party/blink/public/web/web_local_frame.h"
16+
#include "url/gurl.h"
17+
18+
namespace brave_ads {
19+
20+
namespace {
21+
22+
constexpr auto kVettedHosts = base::MakeFixedFlatSet<base::StringPiece>(
23+
{"talk.brave.com", "talk.bravesoftware.com", "dev.talk.brave.software",
24+
"beta.talk.brave.com", "beta.talk.bravesoftware.com",
25+
"beta.talk.brave.software"});
26+
27+
bool IsAllowedHost(const GURL& url) {
28+
if (!url.is_valid() || !url.SchemeIs(url::kHttpsScheme)) {
29+
return false;
30+
}
31+
const std::string host = url.host();
32+
return base::Contains(kVettedHosts, host);
33+
}
34+
35+
} // namespace
36+
37+
BraveAdsRenderFrameObserver::BraveAdsRenderFrameObserver(
38+
content::RenderFrame* render_frame,
39+
int32_t world_id)
40+
: RenderFrameObserver(render_frame), world_id_(world_id) {
41+
native_javascript_handle_ = std::make_unique<BraveAdsJSHandler>(render_frame);
42+
}
43+
44+
BraveAdsRenderFrameObserver::~BraveAdsRenderFrameObserver() {}
45+
46+
void BraveAdsRenderFrameObserver::DidCreateScriptContext(
47+
v8::Local<v8::Context> context,
48+
int32_t world_id) {
49+
if (!render_frame()->IsMainFrame() || world_id_ != world_id)
50+
return;
51+
52+
const GURL url =
53+
url::Origin(render_frame()->GetWebFrame()->GetSecurityOrigin()).GetURL();
54+
55+
if (!IsAllowedHost(url))
56+
return;
57+
58+
native_javascript_handle_->AddJavaScriptObjectToFrame(context);
59+
}
60+
61+
void BraveAdsRenderFrameObserver::OnDestruct() {
62+
delete this;
63+
}
64+
65+
} // namespace brave_ads
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) 2021 The Brave Authors. All rights reserved.
2+
// This Source Code Form is subject to the terms of the Mozilla Public
3+
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
// you can obtain one at http://mozilla.org/MPL/2.0/.
5+
6+
#ifndef BRAVE_COMPONENTS_BRAVE_ADS_RENDERER_BRAVE_ADS_RENDER_FRAME_OBSERVER_H_
7+
#define BRAVE_COMPONENTS_BRAVE_ADS_RENDERER_BRAVE_ADS_RENDER_FRAME_OBSERVER_H_
8+
9+
#include <memory>
10+
11+
#include "content/public/renderer/render_frame_observer.h"
12+
#include "v8/include/v8.h"
13+
14+
namespace content {
15+
class RenderFrame;
16+
} // namespace content
17+
18+
namespace brave_ads {
19+
20+
class BraveAdsJSHandler;
21+
22+
class BraveAdsRenderFrameObserver : public content::RenderFrameObserver {
23+
public:
24+
BraveAdsRenderFrameObserver(content::RenderFrame* render_frame,
25+
int32_t world_id);
26+
BraveAdsRenderFrameObserver(const BraveAdsRenderFrameObserver&) = delete;
27+
BraveAdsRenderFrameObserver& operator=(const BraveAdsRenderFrameObserver&) =
28+
delete;
29+
~BraveAdsRenderFrameObserver() override;
30+
31+
// RenderFrameObserver implementation.
32+
void DidCreateScriptContext(v8::Local<v8::Context> context,
33+
int32_t world_id) override;
34+
35+
private:
36+
// RenderFrameObserver implementation.
37+
void OnDestruct() override;
38+
39+
// Handle to "handler" JavaScript object functionality.
40+
std::unique_ptr<BraveAdsJSHandler> native_javascript_handle_;
41+
int32_t world_id_;
42+
};
43+
44+
} // namespace brave_ads
45+
46+
#endif // BRAVE_COMPONENTS_BRAVE_ADS_RENDERER_BRAVE_ADS_RENDER_FRAME_OBSERVER_H_

renderer/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ source_set("renderer") {
1212
public_deps = [ "//chrome/renderer" ]
1313

1414
deps = [
15+
"//brave/components/brave_ads/common",
16+
"//brave/components/brave_ads/renderer",
1517
"//brave/components/brave_search/common",
1618
"//brave/components/brave_search/renderer",
1719
"//brave/components/brave_shields/common",

renderer/brave_content_renderer_client.cc

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include "brave/renderer/brave_content_renderer_client.h"
77

88
#include "base/feature_list.h"
9+
#include "brave/components/brave_ads/common/features.h"
10+
#include "brave/components/brave_ads/renderer/brave_ads_render_frame_observer.h"
911
#include "brave/components/brave_search/common/brave_search_utils.h"
1012
#include "brave/components/brave_search/renderer/brave_search_render_frame_observer.h"
1113
#include "brave/components/brave_shields/common/features.h"
@@ -74,6 +76,11 @@ void BraveContentRendererClient::RenderFrameCreated(
7476
new brave_search::BraveSearchRenderFrameObserver(
7577
render_frame, content::ISOLATED_WORLD_ID_GLOBAL);
7678
}
79+
80+
if (brave_ads::features::IsRequestAdsEnabledApiEnabled()) {
81+
new brave_ads::BraveAdsRenderFrameObserver(
82+
render_frame, content::ISOLATED_WORLD_ID_GLOBAL);
83+
}
7784
}
7885

7986
void BraveContentRendererClient::RunScriptsAtDocumentStart(

renderer/sources.gni

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ brave_chrome_renderer_sources = [
1313
]
1414

1515
brave_chrome_renderer_public_deps = [
16+
"//brave/components/brave_ads/renderer",
1617
"//brave/components/brave_search/renderer",
1718
"//brave/components/brave_wallet/common/buildflags",
1819
"//brave/components/content_settings/renderer",

0 commit comments

Comments
 (0)