feat: just enough //extensions to load a simple devtools extension (#19515)
This commit is contained in:
parent
9c1310dadc
commit
55368e4d97
14 changed files with 250 additions and 14 deletions
|
@ -1034,6 +1034,13 @@ void AtomBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
|
|||
content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
|
||||
api::Protocol* protocol = api::Protocol::FromWrappedClass(
|
||||
v8::Isolate::GetCurrent(), web_contents->GetBrowserContext());
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
factories->emplace(
|
||||
extensions::kExtensionScheme,
|
||||
extensions::CreateExtensionNavigationURLLoaderFactory(
|
||||
web_contents->GetBrowserContext(),
|
||||
false /* we don't support extensions::WebViewGuest */));
|
||||
#endif
|
||||
if (protocol)
|
||||
protocol->RegisterURLLoaderFactories(factories);
|
||||
}
|
||||
|
@ -1042,6 +1049,13 @@ void AtomBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
|
|||
int render_process_id,
|
||||
int render_frame_id,
|
||||
NonNetworkURLLoaderFactoryMap* factories) {
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id,
|
||||
render_frame_id);
|
||||
if (factory)
|
||||
factories->emplace(extensions::kExtensionScheme, std::move(factory));
|
||||
#endif
|
||||
|
||||
// Chromium may call this even when NetworkService is not enabled.
|
||||
content::RenderFrameHost* frame_host =
|
||||
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
|
||||
|
|
|
@ -226,9 +226,6 @@ AtomBrowserMainParts::AtomBrowserMainParts(
|
|||
electron_bindings_(new ElectronBindings(uv_default_loop())) {
|
||||
DCHECK(!self_) << "Cannot have two AtomBrowserMainParts";
|
||||
self_ = this;
|
||||
// Register extension scheme as web safe scheme.
|
||||
content::ChildProcessSecurityPolicy::GetInstance()->RegisterWebSafeScheme(
|
||||
"chrome-extension");
|
||||
}
|
||||
|
||||
AtomBrowserMainParts::~AtomBrowserMainParts() {
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
|
||||
#include "components/proxy_config/proxy_config_dictionary.h"
|
||||
#include "components/proxy_config/proxy_config_pref_names.h"
|
||||
#include "content/public/browser/child_process_security_policy.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "extensions/common/constants.h"
|
||||
#include "net/proxy_resolution/proxy_config.h"
|
||||
#include "net/proxy_resolution/proxy_config_service.h"
|
||||
#include "net/proxy_resolution/proxy_config_with_annotation.h"
|
||||
|
@ -89,6 +91,10 @@ void BrowserProcessImpl::PostEarlyInitialization() {
|
|||
}
|
||||
|
||||
void BrowserProcessImpl::PreCreateThreads() {
|
||||
// chrome-extension:// URLs are safe to request anywhere, but may only
|
||||
// commit (including in iframes) in extension processes.
|
||||
content::ChildProcessSecurityPolicy::GetInstance()
|
||||
->RegisterWebSafeIsolatedScheme(extensions::kExtensionScheme, true);
|
||||
// Must be created before the IOThread.
|
||||
// Once IOThread class is no longer needed,
|
||||
// this can be created on first use.
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
#include "extensions/browser/updater/null_extension_cache.h"
|
||||
#include "extensions/browser/url_request_util.h"
|
||||
#include "extensions/common/features/feature_channel.h"
|
||||
#include "extensions/common/manifest_constants.h"
|
||||
#include "extensions/common/manifest_url_handlers.h"
|
||||
#include "services/network/public/mojom/url_loader.mojom.h"
|
||||
#include "shell/browser/atom_browser_client.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#include "shell/browser/browser.h"
|
||||
|
@ -31,9 +34,6 @@
|
|||
#include "shell/browser/extensions/atom_extension_host_delegate.h"
|
||||
#include "shell/browser/extensions/atom_extension_system_factory.h"
|
||||
#include "shell/browser/extensions/atom_extension_web_contents_observer.h"
|
||||
// #include "shell/browser/extensions/atom_extensions_api_client.h"
|
||||
// #include "shell/browser/extensions/atom_extensions_browser_api_provider.h"
|
||||
#include "services/network/public/mojom/url_loader.mojom.h"
|
||||
#include "shell/browser/extensions/atom_navigation_ui_data.h"
|
||||
#include "shell/browser/extensions/electron_extensions_api_client.h"
|
||||
#include "shell/browser/extensions/electron_process_manager_delegate.h"
|
||||
|
@ -139,6 +139,37 @@ void AtomExtensionsBrowserClient::LoadResourceFromResourceBundle(
|
|||
NOTREACHED() << "Load resources from bundles not supported.";
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool AllowCrossRendererResourceLoad(const GURL& url,
|
||||
content::ResourceType resource_type,
|
||||
ui::PageTransition page_transition,
|
||||
int child_id,
|
||||
bool is_incognito,
|
||||
const extensions::Extension* extension,
|
||||
const extensions::ExtensionSet& extensions,
|
||||
const extensions::ProcessMap& process_map,
|
||||
bool* allowed) {
|
||||
if (extensions::url_request_util::AllowCrossRendererResourceLoad(
|
||||
url, resource_type, page_transition, child_id, is_incognito,
|
||||
extension, extensions, process_map, allowed)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there aren't any explicitly marked web accessible resources, the
|
||||
// load should be allowed only if it is by DevTools. A close approximation is
|
||||
// checking if the extension contains a DevTools page.
|
||||
if (extension && !extensions::ManifestURL::Get(
|
||||
extension, extensions::manifest_keys::kDevToolsPage)
|
||||
.is_empty()) {
|
||||
*allowed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Couldn't determine if the resource is allowed or not.
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool AtomExtensionsBrowserClient::AllowCrossRendererResourceLoad(
|
||||
const GURL& url,
|
||||
content::ResourceType resource_type,
|
||||
|
@ -149,7 +180,7 @@ bool AtomExtensionsBrowserClient::AllowCrossRendererResourceLoad(
|
|||
const extensions::ExtensionSet& extensions,
|
||||
const extensions::ProcessMap& process_map) {
|
||||
bool allowed = false;
|
||||
if (extensions::url_request_util::AllowCrossRendererResourceLoad(
|
||||
if (::electron::AllowCrossRendererResourceLoad(
|
||||
url, resource_type, page_transition, child_id, is_incognito,
|
||||
extension, extensions, process_map, &allowed)) {
|
||||
return allowed;
|
||||
|
|
|
@ -48,6 +48,16 @@
|
|||
#include "ui/display/display.h"
|
||||
#include "ui/display/screen.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
#include "content/public/browser/child_process_security_policy.h"
|
||||
#include "content/public/browser/render_process_host.h"
|
||||
#include "extensions/browser/extension_registry.h"
|
||||
#include "extensions/common/manifest_constants.h"
|
||||
#include "extensions/common/manifest_url_handlers.h"
|
||||
#include "extensions/common/permissions/permissions_data.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#endif
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
|
@ -571,10 +581,51 @@ void InspectableWebContentsImpl::LoadCompleted() {
|
|||
javascript, base::NullCallback());
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
AddDevToolsExtensionsToClient();
|
||||
#endif
|
||||
|
||||
if (view_->GetDelegate())
|
||||
view_->GetDelegate()->DevToolsOpened();
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
void InspectableWebContentsImpl::AddDevToolsExtensionsToClient() {
|
||||
// get main browser context
|
||||
auto* browser_context = web_contents_->GetBrowserContext();
|
||||
const extensions::ExtensionRegistry* registry =
|
||||
extensions::ExtensionRegistry::Get(browser_context);
|
||||
if (!registry)
|
||||
return;
|
||||
|
||||
base::ListValue results;
|
||||
for (auto& extension : registry->enabled_extensions()) {
|
||||
auto devtools_page_url = extensions::ManifestURL::Get(
|
||||
extension.get(), extensions::manifest_keys::kDevToolsPage);
|
||||
if (devtools_page_url.is_empty())
|
||||
continue;
|
||||
|
||||
// Each devtools extension will need to be able to run in the devtools
|
||||
// process. Grant the devtools process the ability to request URLs from the
|
||||
// extension.
|
||||
content::ChildProcessSecurityPolicy::GetInstance()->GrantRequestOrigin(
|
||||
web_contents_->GetMainFrame()->GetProcess()->GetID(),
|
||||
url::Origin::Create(extension->url()));
|
||||
|
||||
std::unique_ptr<base::DictionaryValue> extension_info(
|
||||
new base::DictionaryValue());
|
||||
extension_info->SetString("startPage", devtools_page_url.spec());
|
||||
extension_info->SetString("name", extension->name());
|
||||
extension_info->SetBoolean("exposeExperimentalAPIs",
|
||||
extension->permissions_data()->HasAPIPermission(
|
||||
extensions::APIPermission::kExperimental));
|
||||
results.Append(std::move(extension_info));
|
||||
}
|
||||
|
||||
CallClientFunction("DevToolsAPI.addExtensions", &results, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
void InspectableWebContentsImpl::SetInspectedPageBounds(const gfx::Rect& rect) {
|
||||
DevToolsContentsResizingStrategy strategy(rect);
|
||||
if (contents_resizing_strategy_.Equals(strategy))
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "content/public/browser/devtools_frontend_host.h"
|
||||
#include "content/public/browser/web_contents_delegate.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "shell/browser/ui/inspectable_web_contents.h"
|
||||
#include "ui/gfx/geometry/rect.h"
|
||||
|
||||
|
@ -193,6 +194,10 @@ class InspectableWebContentsImpl
|
|||
|
||||
void SendMessageAck(int request_id, const base::Value* arg1);
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
void AddDevToolsExtensionsToClient();
|
||||
#endif
|
||||
|
||||
bool frontend_loaded_;
|
||||
scoped_refptr<content::DevToolsAgentHost> agent_host_;
|
||||
std::unique_ptr<content::DevToolsFrontendHost> frontend_host_;
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
{
|
||||
"content_scripts": {
|
||||
"channel": "stable",
|
||||
"extension_types": ["extension", "legacy_packaged_app"]
|
||||
"extension_types": ["extension"]
|
||||
},
|
||||
"devtools_page": {
|
||||
"channel": "stable",
|
||||
"extension_types": ["extension"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,69 @@
|
|||
|
||||
#include "shell/common/extensions/atom_extensions_api_provider.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "extensions/common/alias.h"
|
||||
#include "extensions/common/features/json_feature_provider_source.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
#include "extensions/common/manifest_constants.h"
|
||||
#include "extensions/common/manifest_handler.h"
|
||||
#include "extensions/common/manifest_handlers/permissions_parser.h"
|
||||
#include "extensions/common/manifest_url_handlers.h"
|
||||
#include "extensions/common/permissions/permissions_info.h"
|
||||
#include "shell/common/extensions/api/manifest_features.h"
|
||||
#endif
|
||||
|
||||
namespace extensions {
|
||||
|
||||
namespace keys = manifest_keys;
|
||||
namespace errors = manifest_errors;
|
||||
|
||||
// Parses the "devtools_page" manifest key.
|
||||
class DevToolsPageHandler : public ManifestHandler {
|
||||
public:
|
||||
DevToolsPageHandler() = default;
|
||||
~DevToolsPageHandler() override = default;
|
||||
|
||||
bool Parse(Extension* extension, base::string16* error) override {
|
||||
std::unique_ptr<ManifestURL> manifest_url(new ManifestURL);
|
||||
std::string devtools_str;
|
||||
if (!extension->manifest()->GetString(keys::kDevToolsPage, &devtools_str)) {
|
||||
*error = base::ASCIIToUTF16(errors::kInvalidDevToolsPage);
|
||||
return false;
|
||||
}
|
||||
manifest_url->url_ = extension->GetResourceURL(devtools_str);
|
||||
extension->SetManifestData(keys::kDevToolsPage, std::move(manifest_url));
|
||||
PermissionsParser::AddAPIPermission(extension, APIPermission::kDevtools);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
base::span<const char* const> Keys() const override {
|
||||
static constexpr const char* kKeys[] = {keys::kDevToolsPage};
|
||||
return kKeys;
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DevToolsPageHandler);
|
||||
};
|
||||
|
||||
constexpr APIPermissionInfo::InitInfo permissions_to_register[] = {
|
||||
{APIPermission::kDevtools, "devtools",
|
||||
APIPermissionInfo::kFlagImpliesFullURLAccess |
|
||||
APIPermissionInfo::kFlagCannotBeOptional |
|
||||
APIPermissionInfo::kFlagInternal},
|
||||
};
|
||||
base::span<const APIPermissionInfo::InitInfo> GetPermissionInfos() {
|
||||
return base::make_span(permissions_to_register);
|
||||
}
|
||||
base::span<const Alias> GetPermissionAliases() {
|
||||
return base::span<const Alias>();
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
|
||||
namespace electron {
|
||||
|
||||
|
@ -60,8 +115,16 @@ base::StringPiece AtomExtensionsAPIProvider::GetAPISchema(
|
|||
}
|
||||
|
||||
void AtomExtensionsAPIProvider::RegisterPermissions(
|
||||
extensions::PermissionsInfo* permissions_info) {}
|
||||
extensions::PermissionsInfo* permissions_info) {
|
||||
permissions_info->RegisterPermissions(extensions::GetPermissionInfos(),
|
||||
extensions::GetPermissionAliases());
|
||||
}
|
||||
|
||||
void AtomExtensionsAPIProvider::RegisterManifestHandlers() {}
|
||||
void AtomExtensionsAPIProvider::RegisterManifestHandlers() {
|
||||
extensions::ManifestHandlerRegistry* registry =
|
||||
extensions::ManifestHandlerRegistry::Get();
|
||||
registry->RegisterHandler(
|
||||
std::make_unique<extensions::DevToolsPageHandler>());
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue