1 // Copyright 2015 The Chromium Embedded Framework Authors.
2 // Portions copyright 2014 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "libcef/browser/extensions/extensions_browser_client.h"
7
8 #include <utility>
9
10 #include "libcef/browser/alloy/alloy_browser_host_impl.h"
11 #include "libcef/browser/browser_context.h"
12 #include "libcef/browser/extensions/component_extension_resource_manager.h"
13 #include "libcef/browser/extensions/extension_system.h"
14 #include "libcef/browser/extensions/extension_system_factory.h"
15 #include "libcef/browser/extensions/extension_web_contents_observer.h"
16 #include "libcef/browser/extensions/extensions_api_client.h"
17 #include "libcef/browser/extensions/extensions_browser_api_provider.h"
18 #include "libcef/browser/request_context_impl.h"
19
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/extensions/chrome_url_request_util.h"
22 #include "chrome/browser/extensions/event_router_forwarder.h"
23 #include "content/public/browser/browser_context.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/render_frame_host.h"
26 #include "extensions/browser/api/extensions_api_client.h"
27 #include "extensions/browser/api/mime_handler_private/mime_handler_private.h"
28 #include "extensions/browser/api/runtime/runtime_api_delegate.h"
29 #include "extensions/browser/app_sorting.h"
30 #include "extensions/browser/core_extensions_browser_api_provider.h"
31 #include "extensions/browser/event_router.h"
32 #include "extensions/browser/extension_host_delegate.h"
33 #include "extensions/browser/extensions_browser_interface_binders.h"
34 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
35 #include "extensions/browser/kiosk/kiosk_delegate.h"
36 #include "extensions/browser/url_request_util.h"
37 #include "extensions/common/api/mime_handler.mojom.h"
38 #include "extensions/common/constants.h"
39
40 using content::BrowserContext;
41 using content::BrowserThread;
42
43 namespace extensions {
44
45 namespace {
46
BindMimeHandlerService(content::RenderFrameHost * frame_host,mojo::PendingReceiver<extensions::mime_handler::MimeHandlerService> receiver)47 void BindMimeHandlerService(
48 content::RenderFrameHost* frame_host,
49 mojo::PendingReceiver<extensions::mime_handler::MimeHandlerService>
50 receiver) {
51 auto* web_contents = content::WebContents::FromRenderFrameHost(frame_host);
52 if (!web_contents)
53 return;
54
55 auto* guest_view =
56 extensions::MimeHandlerViewGuest::FromWebContents(web_contents);
57 if (!guest_view)
58 return;
59 extensions::MimeHandlerServiceImpl::Create(guest_view->GetStreamWeakPtr(),
60 std::move(receiver));
61 }
62
BindBeforeUnloadControl(content::RenderFrameHost * frame_host,mojo::PendingReceiver<extensions::mime_handler::BeforeUnloadControl> receiver)63 void BindBeforeUnloadControl(
64 content::RenderFrameHost* frame_host,
65 mojo::PendingReceiver<extensions::mime_handler::BeforeUnloadControl>
66 receiver) {
67 auto* web_contents = content::WebContents::FromRenderFrameHost(frame_host);
68 if (!web_contents)
69 return;
70
71 auto* guest_view =
72 extensions::MimeHandlerViewGuest::FromWebContents(web_contents);
73 if (!guest_view)
74 return;
75 guest_view->FuseBeforeUnloadControl(std::move(receiver));
76 }
77
78 // Dummy KiosDelegate that always returns false
79 class CefKioskDelegate : public extensions::KioskDelegate {
80 public:
81 CefKioskDelegate() = default;
82 ~CefKioskDelegate() override = default;
83
84 // KioskDelegate overrides:
IsAutoLaunchedKioskApp(const ExtensionId & id) const85 bool IsAutoLaunchedKioskApp(const ExtensionId& id) const override {
86 return false;
87 }
88 };
89
90 } // namespace
91
CefExtensionsBrowserClient()92 CefExtensionsBrowserClient::CefExtensionsBrowserClient()
93 : api_client_(new CefExtensionsAPIClient),
94 resource_manager_(new CefComponentExtensionResourceManager) {
95 AddAPIProvider(std::make_unique<CoreExtensionsBrowserAPIProvider>());
96 AddAPIProvider(std::make_unique<CefExtensionsBrowserAPIProvider>());
97 }
98
~CefExtensionsBrowserClient()99 CefExtensionsBrowserClient::~CefExtensionsBrowserClient() {}
100
101 // static
Get()102 CefExtensionsBrowserClient* CefExtensionsBrowserClient::Get() {
103 return static_cast<CefExtensionsBrowserClient*>(
104 ExtensionsBrowserClient::Get());
105 }
106
IsShuttingDown()107 bool CefExtensionsBrowserClient::IsShuttingDown() {
108 return false;
109 }
110
AreExtensionsDisabled(const base::CommandLine & command_line,BrowserContext * context)111 bool CefExtensionsBrowserClient::AreExtensionsDisabled(
112 const base::CommandLine& command_line,
113 BrowserContext* context) {
114 return false;
115 }
116
IsValidContext(BrowserContext * context)117 bool CefExtensionsBrowserClient::IsValidContext(BrowserContext* context) {
118 return GetOriginalContext(context) != nullptr;
119 }
120
IsSameContext(BrowserContext * first,BrowserContext * second)121 bool CefExtensionsBrowserClient::IsSameContext(BrowserContext* first,
122 BrowserContext* second) {
123 // Returns true if |first| and |second| share the same underlying
124 // CefBrowserContext.
125 return GetOriginalContext(first) == GetOriginalContext(second);
126 }
127
HasOffTheRecordContext(BrowserContext * context)128 bool CefExtensionsBrowserClient::HasOffTheRecordContext(
129 BrowserContext* context) {
130 // CEF doesn't use incognito contexts.
131 return false;
132 }
133
GetOffTheRecordContext(BrowserContext * context)134 BrowserContext* CefExtensionsBrowserClient::GetOffTheRecordContext(
135 BrowserContext* context) {
136 return nullptr;
137 }
138
GetOriginalContext(BrowserContext * context)139 BrowserContext* CefExtensionsBrowserClient::GetOriginalContext(
140 BrowserContext* context) {
141 auto cef_browser_context = CefBrowserContext::FromBrowserContext(context);
142 if (cef_browser_context)
143 return cef_browser_context->AsBrowserContext();
144 return nullptr;
145 }
146
IsGuestSession(BrowserContext * context) const147 bool CefExtensionsBrowserClient::IsGuestSession(BrowserContext* context) const {
148 return false;
149 }
150
IsExtensionIncognitoEnabled(const std::string & extension_id,content::BrowserContext * context) const151 bool CefExtensionsBrowserClient::IsExtensionIncognitoEnabled(
152 const std::string& extension_id,
153 content::BrowserContext* context) const {
154 return false;
155 }
156
CanExtensionCrossIncognito(const Extension * extension,content::BrowserContext * context) const157 bool CefExtensionsBrowserClient::CanExtensionCrossIncognito(
158 const Extension* extension,
159 content::BrowserContext* context) const {
160 return false;
161 }
162
GetBundleResourcePath(const network::ResourceRequest & request,const base::FilePath & extension_resources_path,int * resource_id) const163 base::FilePath CefExtensionsBrowserClient::GetBundleResourcePath(
164 const network::ResourceRequest& request,
165 const base::FilePath& extension_resources_path,
166 int* resource_id) const {
167 return chrome_url_request_util::GetBundleResourcePath(
168 request, extension_resources_path, resource_id);
169 }
170
LoadResourceFromResourceBundle(const network::ResourceRequest & request,mojo::PendingReceiver<network::mojom::URLLoader> loader,const base::FilePath & resource_relative_path,const int resource_id,scoped_refptr<net::HttpResponseHeaders> headers,mojo::PendingRemote<network::mojom::URLLoaderClient> client)171 void CefExtensionsBrowserClient::LoadResourceFromResourceBundle(
172 const network::ResourceRequest& request,
173 mojo::PendingReceiver<network::mojom::URLLoader> loader,
174 const base::FilePath& resource_relative_path,
175 const int resource_id,
176 scoped_refptr<net::HttpResponseHeaders> headers,
177 mojo::PendingRemote<network::mojom::URLLoaderClient> client) {
178 chrome_url_request_util::LoadResourceFromResourceBundle(
179 request, std::move(loader), resource_relative_path, resource_id,
180 std::move(headers), std::move(client));
181 }
182
AllowCrossRendererResourceLoad(const network::ResourceRequest & request,network::mojom::RequestDestination destination,ui::PageTransition page_transition,int child_id,bool is_incognito,const Extension * extension,const ExtensionSet & extensions,const ProcessMap & process_map)183 bool CefExtensionsBrowserClient::AllowCrossRendererResourceLoad(
184 const network::ResourceRequest& request,
185 network::mojom::RequestDestination destination,
186 ui::PageTransition page_transition,
187 int child_id,
188 bool is_incognito,
189 const Extension* extension,
190 const ExtensionSet& extensions,
191 const ProcessMap& process_map) {
192 bool allowed = false;
193 if (url_request_util::AllowCrossRendererResourceLoad(
194 request, destination, page_transition, child_id, is_incognito,
195 extension, extensions, process_map, &allowed)) {
196 return allowed;
197 }
198
199 // Couldn't determine if resource is allowed. Block the load.
200 return false;
201 }
202
GetPrefServiceForContext(BrowserContext * context)203 PrefService* CefExtensionsBrowserClient::GetPrefServiceForContext(
204 BrowserContext* context) {
205 return CefBrowserContext::FromBrowserContext(context)
206 ->AsProfile()
207 ->GetPrefs();
208 }
209
GetEarlyExtensionPrefsObservers(content::BrowserContext * context,std::vector<EarlyExtensionPrefsObserver * > * observers) const210 void CefExtensionsBrowserClient::GetEarlyExtensionPrefsObservers(
211 content::BrowserContext* context,
212 std::vector<EarlyExtensionPrefsObserver*>* observers) const {}
213
GetProcessManagerDelegate() const214 ProcessManagerDelegate* CefExtensionsBrowserClient::GetProcessManagerDelegate()
215 const {
216 return nullptr;
217 }
218
219 std::unique_ptr<ExtensionHostDelegate>
CreateExtensionHostDelegate()220 CefExtensionsBrowserClient::CreateExtensionHostDelegate() {
221 // CEF does not use the ExtensionHost constructor that calls this method.
222 NOTREACHED();
223 return std::unique_ptr<ExtensionHostDelegate>();
224 }
225
CreateBackgroundExtensionHost(const Extension * extension,content::BrowserContext * browser_context,const GURL & url,ExtensionHost ** host)226 bool CefExtensionsBrowserClient::CreateBackgroundExtensionHost(
227 const Extension* extension,
228 content::BrowserContext* browser_context,
229 const GURL& url,
230 ExtensionHost** host) {
231 auto cef_browser_context =
232 CefBrowserContext::FromBrowserContext(browser_context);
233
234 // A CEF representation should always exist.
235 CefRefPtr<CefExtension> cef_extension =
236 cef_browser_context->GetExtension(extension->id());
237 DCHECK(cef_extension);
238 if (!cef_extension) {
239 // Cancel the background host creation.
240 return true;
241 }
242
243 // Always use the same request context that the extension was registered with.
244 // GetLoaderContext() will return NULL for internal extensions.
245 CefRefPtr<CefRequestContext> request_context =
246 cef_extension->GetLoaderContext();
247 if (!request_context) {
248 // Cancel the background host creation.
249 return true;
250 }
251
252 CefBrowserCreateParams create_params;
253 create_params.url = url.spec();
254 create_params.request_context = request_context;
255
256 CefRefPtr<CefExtensionHandler> handler = cef_extension->GetHandler();
257 if (handler.get() && handler->OnBeforeBackgroundBrowser(
258 cef_extension, create_params.url,
259 create_params.client, create_params.settings)) {
260 // Cancel the background host creation.
261 return true;
262 }
263
264 // This triggers creation of the background host.
265 create_params.extension = extension;
266 create_params.extension_host_type = mojom::ViewType::kExtensionBackgroundPage;
267
268 // Browser creation may fail under certain rare circumstances. Fail the
269 // background host creation in that case.
270 CefRefPtr<AlloyBrowserHostImpl> browser =
271 AlloyBrowserHostImpl::Create(create_params);
272 if (browser) {
273 *host = browser->GetExtensionHost();
274 DCHECK(*host);
275 }
276 return true;
277 }
278
DidVersionUpdate(BrowserContext * context)279 bool CefExtensionsBrowserClient::DidVersionUpdate(BrowserContext* context) {
280 // TODO(jamescook): We might want to tell extensions when app_shell updates.
281 return false;
282 }
283
PermitExternalProtocolHandler()284 void CefExtensionsBrowserClient::PermitExternalProtocolHandler() {}
285
IsInDemoMode()286 bool CefExtensionsBrowserClient::IsInDemoMode() {
287 return false;
288 }
289
IsScreensaverInDemoMode(const std::string & app_id)290 bool CefExtensionsBrowserClient::IsScreensaverInDemoMode(
291 const std::string& app_id) {
292 return false;
293 }
294
IsRunningInForcedAppMode()295 bool CefExtensionsBrowserClient::IsRunningInForcedAppMode() {
296 return false;
297 }
298
IsAppModeForcedForApp(const ExtensionId & extension_id)299 bool CefExtensionsBrowserClient::IsAppModeForcedForApp(
300 const ExtensionId& extension_id) {
301 return false;
302 }
303
IsLoggedInAsPublicAccount()304 bool CefExtensionsBrowserClient::IsLoggedInAsPublicAccount() {
305 return false;
306 }
307
308 ExtensionSystemProvider*
GetExtensionSystemFactory()309 CefExtensionsBrowserClient::GetExtensionSystemFactory() {
310 return CefExtensionSystemFactory::GetInstance();
311 }
312
RegisterBrowserInterfaceBindersForFrame(mojo::BinderMapWithContext<content::RenderFrameHost * > * map,content::RenderFrameHost * render_frame_host,const Extension * extension) const313 void CefExtensionsBrowserClient::RegisterBrowserInterfaceBindersForFrame(
314 mojo::BinderMapWithContext<content::RenderFrameHost*>* map,
315 content::RenderFrameHost* render_frame_host,
316 const Extension* extension) const {
317 PopulateExtensionFrameBinders(map, render_frame_host, extension);
318
319 map->Add<extensions::mime_handler::MimeHandlerService>(
320 base::BindRepeating(&BindMimeHandlerService));
321 map->Add<extensions::mime_handler::BeforeUnloadControl>(
322 base::BindRepeating(&BindBeforeUnloadControl));
323 }
324
325 std::unique_ptr<RuntimeAPIDelegate>
CreateRuntimeAPIDelegate(content::BrowserContext * context) const326 CefExtensionsBrowserClient::CreateRuntimeAPIDelegate(
327 content::BrowserContext* context) const {
328 // TODO(extensions): Implement to support Apps.
329 NOTREACHED();
330 return nullptr;
331 }
332
333 const ComponentExtensionResourceManager*
GetComponentExtensionResourceManager()334 CefExtensionsBrowserClient::GetComponentExtensionResourceManager() {
335 return resource_manager_.get();
336 }
337
BroadcastEventToRenderers(events::HistogramValue histogram_value,const std::string & event_name,std::unique_ptr<base::ListValue> args,bool dispatch_to_off_the_record_profiles)338 void CefExtensionsBrowserClient::BroadcastEventToRenderers(
339 events::HistogramValue histogram_value,
340 const std::string& event_name,
341 std::unique_ptr<base::ListValue> args,
342 bool dispatch_to_off_the_record_profiles) {
343 g_browser_process->extension_event_router_forwarder()
344 ->BroadcastEventToRenderers(histogram_value, event_name, std::move(args),
345 GURL(), dispatch_to_off_the_record_profiles);
346 }
347
GetExtensionCache()348 ExtensionCache* CefExtensionsBrowserClient::GetExtensionCache() {
349 // Only used by Chrome via ExtensionService.
350 NOTREACHED();
351 return nullptr;
352 }
353
IsBackgroundUpdateAllowed()354 bool CefExtensionsBrowserClient::IsBackgroundUpdateAllowed() {
355 return true;
356 }
357
IsMinBrowserVersionSupported(const std::string & min_version)358 bool CefExtensionsBrowserClient::IsMinBrowserVersionSupported(
359 const std::string& min_version) {
360 return true;
361 }
362
363 ExtensionWebContentsObserver*
GetExtensionWebContentsObserver(content::WebContents * web_contents)364 CefExtensionsBrowserClient::GetExtensionWebContentsObserver(
365 content::WebContents* web_contents) {
366 return CefExtensionWebContentsObserver::FromWebContents(web_contents);
367 }
368
GetKioskDelegate()369 KioskDelegate* CefExtensionsBrowserClient::GetKioskDelegate() {
370 if (!kiosk_delegate_)
371 kiosk_delegate_.reset(new CefKioskDelegate());
372 return kiosk_delegate_.get();
373 }
374
IsLockScreenContext(content::BrowserContext * context)375 bool CefExtensionsBrowserClient::IsLockScreenContext(
376 content::BrowserContext* context) {
377 return false;
378 }
379
GetApplicationLocale()380 std::string CefExtensionsBrowserClient::GetApplicationLocale() {
381 return g_browser_process->GetApplicationLocale();
382 }
383
384 } // namespace extensions
385