// Copyright 2015 The Chromium Embedded Framework Authors. // Portions copyright 2014 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 "libcef/browser/extensions/extensions_browser_client.h" #include #include "libcef/browser/alloy/alloy_browser_host_impl.h" #include "libcef/browser/browser_context.h" #include "libcef/browser/extensions/component_extension_resource_manager.h" #include "libcef/browser/extensions/extension_system.h" #include "libcef/browser/extensions/extension_system_factory.h" #include "libcef/browser/extensions/extension_web_contents_observer.h" #include "libcef/browser/extensions/extensions_api_client.h" #include "libcef/browser/extensions/extensions_browser_api_provider.h" #include "libcef/browser/request_context_impl.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/chrome_url_request_util.h" #include "chrome/browser/extensions/event_router_forwarder.h" #include "chrome/browser/media/webrtc/media_device_salt_service_factory.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "extensions/browser/api/core_extensions_browser_api_provider.h" #include "extensions/browser/api/extensions_api_client.h" #include "extensions/browser/api/mime_handler_private/mime_handler_private.h" #include "extensions/browser/api/runtime/runtime_api_delegate.h" #include "extensions/browser/app_sorting.h" #include "extensions/browser/event_router.h" #include "extensions/browser/extension_host_delegate.h" #include "extensions/browser/extensions_browser_interface_binders.h" #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" #include "extensions/browser/kiosk/kiosk_delegate.h" #include "extensions/browser/url_request_util.h" #include "extensions/common/api/mime_handler.mojom.h" #include "extensions/common/constants.h" using content::BrowserContext; using content::BrowserThread; namespace extensions { namespace { void BindMimeHandlerService( content::RenderFrameHost* frame_host, mojo::PendingReceiver receiver) { auto* web_contents = content::WebContents::FromRenderFrameHost(frame_host); if (!web_contents) { return; } auto* guest_view = extensions::MimeHandlerViewGuest::FromWebContents(web_contents); if (!guest_view) { return; } extensions::MimeHandlerServiceImpl::Create(guest_view->GetStreamWeakPtr(), std::move(receiver)); } void BindBeforeUnloadControl( content::RenderFrameHost* frame_host, mojo::PendingReceiver receiver) { auto* web_contents = content::WebContents::FromRenderFrameHost(frame_host); if (!web_contents) { return; } auto* guest_view = extensions::MimeHandlerViewGuest::FromWebContents(web_contents); if (!guest_view) { return; } guest_view->FuseBeforeUnloadControl(std::move(receiver)); } // Dummy KiosDelegate that always returns false class CefKioskDelegate : public extensions::KioskDelegate { public: CefKioskDelegate() = default; ~CefKioskDelegate() override = default; // KioskDelegate overrides: bool IsAutoLaunchedKioskApp(const ExtensionId& id) const override { return false; } }; } // namespace CefExtensionsBrowserClient::CefExtensionsBrowserClient() : api_client_(new CefExtensionsAPIClient) { AddAPIProvider(std::make_unique()); AddAPIProvider(std::make_unique()); } CefExtensionsBrowserClient::~CefExtensionsBrowserClient() {} // static CefExtensionsBrowserClient* CefExtensionsBrowserClient::Get() { return static_cast( ExtensionsBrowserClient::Get()); } bool CefExtensionsBrowserClient::IsShuttingDown() { return false; } bool CefExtensionsBrowserClient::AreExtensionsDisabled( const base::CommandLine& command_line, BrowserContext* context) { return false; } bool CefExtensionsBrowserClient::IsValidContext(void* context) { return GetOriginalContext(static_cast(context)) != nullptr; } bool CefExtensionsBrowserClient::IsSameContext(BrowserContext* first, BrowserContext* second) { // Returns true if |first| and |second| share the same underlying // CefBrowserContext. return GetOriginalContext(first) == GetOriginalContext(second); } bool CefExtensionsBrowserClient::HasOffTheRecordContext( BrowserContext* context) { // CEF doesn't use incognito contexts. return false; } BrowserContext* CefExtensionsBrowserClient::GetOffTheRecordContext( BrowserContext* context) { return nullptr; } BrowserContext* CefExtensionsBrowserClient::GetOriginalContext( BrowserContext* context) { auto cef_browser_context = CefBrowserContext::FromBrowserContext(context); if (cef_browser_context) { return cef_browser_context->AsBrowserContext(); } return nullptr; } content::BrowserContext* CefExtensionsBrowserClient::GetContextRedirectedToOriginal( content::BrowserContext* context, bool force_guest_profile) { return context; } content::BrowserContext* CefExtensionsBrowserClient::GetContextOwnInstance( content::BrowserContext* context, bool force_guest_profile) { return context; } content::BrowserContext* CefExtensionsBrowserClient::GetContextForOriginalOnly( content::BrowserContext* context, bool force_guest_profile) { return context; } bool CefExtensionsBrowserClient::AreExtensionsDisabledForContext( content::BrowserContext* context) { return false; } bool CefExtensionsBrowserClient::IsGuestSession(BrowserContext* context) const { return false; } bool CefExtensionsBrowserClient::IsExtensionIncognitoEnabled( const std::string& extension_id, content::BrowserContext* context) const { return false; } bool CefExtensionsBrowserClient::CanExtensionCrossIncognito( const Extension* extension, content::BrowserContext* context) const { return false; } base::FilePath CefExtensionsBrowserClient::GetBundleResourcePath( const network::ResourceRequest& request, const base::FilePath& extension_resources_path, int* resource_id) const { return chrome_url_request_util::GetBundleResourcePath( request, extension_resources_path, resource_id); } void CefExtensionsBrowserClient::LoadResourceFromResourceBundle( const network::ResourceRequest& request, mojo::PendingReceiver loader, const base::FilePath& resource_relative_path, const int resource_id, scoped_refptr headers, mojo::PendingRemote client) { chrome_url_request_util::LoadResourceFromResourceBundle( request, std::move(loader), resource_relative_path, resource_id, std::move(headers), std::move(client)); } bool CefExtensionsBrowserClient::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) { bool allowed = false; if (url_request_util::AllowCrossRendererResourceLoad( request, destination, page_transition, child_id, is_incognito, extension, extensions, process_map, &allowed)) { return allowed; } // Couldn't determine if resource is allowed. Block the load. return false; } PrefService* CefExtensionsBrowserClient::GetPrefServiceForContext( BrowserContext* context) { return CefBrowserContext::FromBrowserContext(context) ->AsProfile() ->GetPrefs(); } void CefExtensionsBrowserClient::GetEarlyExtensionPrefsObservers( content::BrowserContext* context, std::vector* observers) const {} ProcessManagerDelegate* CefExtensionsBrowserClient::GetProcessManagerDelegate() const { return nullptr; } std::unique_ptr CefExtensionsBrowserClient::CreateExtensionHostDelegate() { // CEF does not use the ExtensionHost constructor that calls this method. DCHECK(false); return std::unique_ptr(); } bool CefExtensionsBrowserClient::CreateBackgroundExtensionHost( const Extension* extension, content::BrowserContext* browser_context, const GURL& url, ExtensionHost** host) { auto cef_browser_context = CefBrowserContext::FromBrowserContext(browser_context); // A CEF representation should always exist. CefRefPtr cef_extension = cef_browser_context->GetExtension(extension->id()); DCHECK(cef_extension); if (!cef_extension) { // Cancel the background host creation. return true; } // Always use the same request context that the extension was registered with. // GetLoaderContext() will return NULL for internal extensions. CefRefPtr request_context = cef_extension->GetLoaderContext(); if (!request_context) { // Cancel the background host creation. return true; } CefBrowserCreateParams create_params; create_params.url = url.spec(); create_params.request_context = request_context; CefRefPtr handler = cef_extension->GetHandler(); if (handler.get() && handler->OnBeforeBackgroundBrowser( cef_extension, create_params.url, create_params.client, create_params.settings)) { // Cancel the background host creation. return true; } // This triggers creation of the background host. create_params.extension = extension; create_params.extension_host_type = mojom::ViewType::kExtensionBackgroundPage; // Browser creation may fail under certain rare circumstances. Fail the // background host creation in that case. CefRefPtr browser = AlloyBrowserHostImpl::Create(create_params); if (browser) { *host = browser->GetExtensionHost(); DCHECK(*host); } return true; } bool CefExtensionsBrowserClient::DidVersionUpdate(BrowserContext* context) { // TODO(jamescook): We might want to tell extensions when app_shell updates. return false; } void CefExtensionsBrowserClient::PermitExternalProtocolHandler() {} bool CefExtensionsBrowserClient::IsInDemoMode() { return false; } bool CefExtensionsBrowserClient::IsScreensaverInDemoMode( const std::string& app_id) { return false; } bool CefExtensionsBrowserClient::IsRunningInForcedAppMode() { return false; } bool CefExtensionsBrowserClient::IsAppModeForcedForApp( const ExtensionId& extension_id) { return false; } bool CefExtensionsBrowserClient::IsLoggedInAsPublicAccount() { return false; } ExtensionSystemProvider* CefExtensionsBrowserClient::GetExtensionSystemFactory() { return CefExtensionSystemFactory::GetInstance(); } void CefExtensionsBrowserClient::RegisterBrowserInterfaceBindersForFrame( mojo::BinderMapWithContext* map, content::RenderFrameHost* render_frame_host, const Extension* extension) const { PopulateExtensionFrameBinders(map, render_frame_host, extension); map->Add( base::BindRepeating(&BindMimeHandlerService)); map->Add( base::BindRepeating(&BindBeforeUnloadControl)); } std::unique_ptr CefExtensionsBrowserClient::CreateRuntimeAPIDelegate( content::BrowserContext* context) const { // TODO(extensions): Implement to support Apps. DCHECK(false); return nullptr; } const ComponentExtensionResourceManager* CefExtensionsBrowserClient::GetComponentExtensionResourceManager() { if (!resource_manager_) { resource_manager_ = std::make_unique(); } return resource_manager_.get(); } void CefExtensionsBrowserClient::BroadcastEventToRenderers( events::HistogramValue histogram_value, const std::string& event_name, base::Value::List args, bool dispatch_to_off_the_record_profiles) { g_browser_process->extension_event_router_forwarder() ->BroadcastEventToRenderers(histogram_value, event_name, std::move(args), GURL(), dispatch_to_off_the_record_profiles); } ExtensionCache* CefExtensionsBrowserClient::GetExtensionCache() { // Only used by Chrome via ExtensionService. DCHECK(false); return nullptr; } bool CefExtensionsBrowserClient::IsBackgroundUpdateAllowed() { return true; } bool CefExtensionsBrowserClient::IsMinBrowserVersionSupported( const std::string& min_version) { return true; } ExtensionWebContentsObserver* CefExtensionsBrowserClient::GetExtensionWebContentsObserver( content::WebContents* web_contents) { return CefExtensionWebContentsObserver::FromWebContents(web_contents); } KioskDelegate* CefExtensionsBrowserClient::GetKioskDelegate() { if (!kiosk_delegate_) { kiosk_delegate_.reset(new CefKioskDelegate()); } return kiosk_delegate_.get(); } bool CefExtensionsBrowserClient::IsLockScreenContext( content::BrowserContext* context) { return false; } std::string CefExtensionsBrowserClient::GetApplicationLocale() { return g_browser_process->GetApplicationLocale(); } media_device_salt::MediaDeviceSaltService* CefExtensionsBrowserClient::GetMediaDeviceSaltService( content::BrowserContext* context) { return MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext( context); } } // namespace extensions