diff options
author | Anu Aliyas <[email protected]> | 2025-01-23 13:19:25 +0100 |
---|---|---|
committer | Anu Aliyas <[email protected]> | 2025-05-30 10:41:46 +0200 |
commit | 0ce053c22b86c16e82b3fd7c28956481b58500b0 (patch) | |
tree | 04012d05bf76aad0f45412c4b0421d832deeb917 | |
parent | 824eb0f3f81cb754a8d70c2f24ce6387459ae7ea (diff) |
The WebUI can be accessed using the URL chrome://extensions
This will list all the enabled and disable extensions and
also provides a means to load extensions.
Change-Id: Iddd61a858d100f292f7214e53a1ea753228af0b5
Reviewed-by: Allan Sandfeld Jensen <[email protected]>
-rw-r--r-- | src/core/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/core/configure/BUILD.root.gn.in | 6 | ||||
-rw-r--r-- | src/core/content_browser_client_qt.cpp | 6 | ||||
-rw-r--r-- | src/core/extensions/webui/extensions_ui_page_handler_qt.cpp | 70 | ||||
-rw-r--r-- | src/core/extensions/webui/extensions_ui_page_handler_qt.h | 39 | ||||
-rw-r--r-- | src/core/extensions/webui/extensions_ui_qt.cpp | 48 | ||||
-rw-r--r-- | src/core/extensions/webui/extensions_ui_qt.h | 33 | ||||
-rw-r--r-- | src/core/extensions/webui/select_file_dialog.cpp | 51 | ||||
-rw-r--r-- | src/core/extensions/webui/select_file_dialog.h | 38 | ||||
-rw-r--r-- | src/core/net/webui_controller_factory_qt.cpp | 22 | ||||
-rw-r--r-- | tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp | 2 |
11 files changed, 302 insertions, 16 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8dff712b5..b2ca49103 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -295,6 +295,9 @@ foreach(arch ${archs}) renderer/extensions/extensions_renderer_api_provider_qt.cpp renderer/extensions/extensions_renderer_api_provider_qt.h renderer/extensions/extensions_renderer_client_qt.cpp renderer/extensions/extensions_renderer_client_qt.h renderer/extensions/resource_request_policy_qt.cpp renderer/extensions/resource_request_policy_qt.h + extensions/webui/extensions_ui_page_handler_qt.cpp extensions/webui/extensions_ui_page_handler_qt.h + extensions/webui/extensions_ui_qt.cpp extensions/webui/extensions_ui_qt.h + extensions/webui/select_file_dialog.cpp extensions/webui/select_file_dialog.h ) extend_gn_target(${buildGn} CONDITION QT_FEATURE_webengine_extensions AND QT_FEATURE_webengine_printing_and_pdf diff --git a/src/core/configure/BUILD.root.gn.in b/src/core/configure/BUILD.root.gn.in index 9ece7cd56..a17ecbb9c 100644 --- a/src/core/configure/BUILD.root.gn.in +++ b/src/core/configure/BUILD.root.gn.in @@ -439,6 +439,8 @@ source_set("qtwebengine_sources") { "//extensions/strings", "//qtwebengine/browser/extensions/api:api_registration", "//qtwebengine/common/extensions/api:api", + "//qtwebengine/browser/extensions/webui:mojo_bindings", + "//qtwebengine/browser/extensions/resources", ] sources += [ "//chrome/browser/extensions/api/streams_private/streams_private_api.cc", @@ -455,6 +457,8 @@ source_set("qtwebengine_sources") { "//extensions/browser/zipfile_installer.h", "//components/services/unzip/unzipper_impl.cc", "//components/services/unzip/unzipper_impl.h", + "//ui/webui/mojo_web_ui_controller.cc", + "//ui/webui/mojo_web_ui_controller.h", ] } else { sources += [ @@ -656,6 +660,7 @@ repack("qtwebengine_repack_resources") { ] if (enable_extensions) { sources += [ + "$root_gen_dir/qtwebengine/browser/extensions/resources/extensions_ui_qt_resources.pak", "$root_gen_dir/chrome/component_extension_resources.pak", "$root_gen_dir/extensions/extensions_renderer_resources.pak", "$root_gen_dir/extensions/extensions_resources.pak", @@ -664,6 +669,7 @@ repack("qtwebengine_repack_resources") { "//chrome/browser/resources:component_extension_resources_grit", "//extensions:extensions_renderer_resources_grit", "//extensions:extensions_resources_grd_grit", + "//qtwebengine/browser/extensions/resources:resources_grit" ] } if (enable_webrtc) { diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 015532ff9..1bda59a75 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -112,6 +112,7 @@ #endif #if BUILDFLAG(ENABLE_EXTENSIONS) +#include "content/public/browser/web_ui_controller_interface_binder.h" #include "common/extensions/extensions_client_qt.h" #include "components/guest_view/browser/guest_view_base.h" #include "extensions/browser/api/mime_handler_private/mime_handler_private.h" @@ -130,6 +131,8 @@ #include "extensions/extension_web_contents_observer_qt.h" #include "extensions/extensions_browser_client_qt.h" #include "net/plugin_response_interceptor_url_loader_throttle.h" +#include "extensions/webui/extensions_ui_page_handler_qt.h" +#include "extensions/webui/extensions_ui_qt.h" #endif #if QT_CONFIG(webengine_webchannel) @@ -450,6 +453,9 @@ void ContentBrowserClientQt::RegisterBrowserInterfaceBindersForFrame( #endif #if BUILDFLAG(ENABLE_EXTENSIONS) + RegisterWebUIControllerInterfaceBinder<qtwebengine::mojom::ExtensionsUIHandlerFactory, + ExtensionsUIQt>(map); + map->Add<extensions::mime_handler::MimeHandlerService>(base::BindRepeating(&BindMimeHandlerService)); map->Add<extensions::mime_handler::BeforeUnloadControl>(base::BindRepeating(&BindBeforeUnloadControl)); const GURL &site = render_frame_host->GetSiteInstance()->GetSiteURL(); diff --git a/src/core/extensions/webui/extensions_ui_page_handler_qt.cpp b/src/core/extensions/webui/extensions_ui_page_handler_qt.cpp new file mode 100644 index 000000000..2e88c393c --- /dev/null +++ b/src/core/extensions/webui/extensions_ui_page_handler_qt.cpp @@ -0,0 +1,70 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "extensions_ui_page_handler_qt.h" + +#include "extensions/extension_system_qt.h" +#include "extensions/webui/select_file_dialog.h" + +#include "extensions/browser/extension_registry.h" +#include "extensions/extension_manager.h" +#include "api/qwebengineextensionmanager.h" +#include "profile_adapter.h" +#include "profile_qt.h" +#include "type_conversion.h" + +ExtensionsUIPageHandlerQt::ExtensionsUIPageHandlerQt( + content::WebUI *webui, Profile *profile, + mojo::PendingReceiver<qtwebengine::mojom::PageHandler> receiver, + mojo::PendingRemote<qtwebengine::mojom::Page> page) + : receiver_(this, std::move(receiver)), page_(std::move(page)), webui_(webui), profile_(profile) +{ +} + +ExtensionsUIPageHandlerQt::~ExtensionsUIPageHandlerQt() { } + +void ExtensionsUIPageHandlerQt::GetAllExtensionInfo(GetAllExtensionInfoCallback callback) +{ + std::vector<qtwebengine::mojom::ExtensionInfoPtr> extensionsInfo; + + auto add_to_list = [&extensionsInfo](const extensions::ExtensionSet &extensions, + bool is_enabled) { + for (auto extension : extensions) { + auto info = qtwebengine::mojom::ExtensionInfo::New(); + info->name = extension->name(); + info->description = extension->description(); + info->version = extension->VersionString(); + info->id = extension->id(); + info->isEnabled = is_enabled; + extensionsInfo.push_back(std::move(info)); + } + }; + + extensions::ExtensionRegistry *registry = extensions::ExtensionRegistry::Get(profile_); + add_to_list(registry->enabled_extensions(), true); + add_to_list(registry->disabled_extensions(), false); + + std::move(callback).Run(std::move(extensionsInfo)); +} + +void ExtensionsUIPageHandlerQt::LoadExtension() +{ + SelectFileDialog::Show( + base::BindOnce(&ExtensionsUIPageHandlerQt::InnerLoadExtension, base::Unretained(this)), + base::FilePath(), webui_->GetWebContents()); +} + +void ExtensionsUIPageHandlerQt::InnerLoadExtension(const base::FilePath &path) +{ + auto profileAdapter = static_cast<QtWebEngineCore::ProfileQt *>(profile_)->profileAdapter(); + QWebEngineExtensionManager *manager = profileAdapter->extensionManager(); + + QMetaObject::Connection *const connection = new QMetaObject::Connection; + *connection = QObject::connect(manager, &QWebEngineExtensionManager::extensionLoadFinished, + [this, connection]() { + page_->ReloadPage(); + QObject::disconnect(*connection); + delete connection; + }); + manager->loadExtension(QtWebEngineCore::toQt(path)); +} diff --git a/src/core/extensions/webui/extensions_ui_page_handler_qt.h b/src/core/extensions/webui/extensions_ui_page_handler_qt.h new file mode 100644 index 000000000..236c7df1b --- /dev/null +++ b/src/core/extensions/webui/extensions_ui_page_handler_qt.h @@ -0,0 +1,39 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef EXTENSIONSUIPAGEHANDLERQT_H +#define EXTENSIONSUIPAGEHANDLERQT_H + +#include "chrome/browser/profiles/profile.h" +#include "content/public/browser/web_ui.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "qtwebengine/browser/extensions/webui/extensions_ui_qt.mojom.h" + +class ExtensionsUIPageHandlerQt : public qtwebengine::mojom::PageHandler +{ +public: + ExtensionsUIPageHandlerQt(content::WebUI *webui, Profile *profile, + mojo::PendingReceiver<qtwebengine::mojom::PageHandler> receiver, + mojo::PendingRemote<qtwebengine::mojom::Page> page); + + ExtensionsUIPageHandlerQt(const ExtensionsUIPageHandlerQt &) = delete; + ExtensionsUIPageHandlerQt &operator=(const ExtensionsUIPageHandlerQt &) = delete; + + ~ExtensionsUIPageHandlerQt() override; + + void GetAllExtensionInfo(GetAllExtensionInfoCallback callback) override; + void LoadExtension() override; + +private: + void InnerLoadExtension(const base::FilePath &path); + + mojo::Receiver<qtwebengine::mojom::PageHandler> receiver_; + mojo::Remote<qtwebengine::mojom::Page> page_; + content::WebUI *webui_; + Profile *profile_; +}; + +#endif // EXTENSIONSUIPAGEHANDLERQT_H diff --git a/src/core/extensions/webui/extensions_ui_qt.cpp b/src/core/extensions/webui/extensions_ui_qt.cpp new file mode 100644 index 000000000..d72be5164 --- /dev/null +++ b/src/core/extensions/webui/extensions_ui_qt.cpp @@ -0,0 +1,48 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "extensions_ui_qt.h" + +#include "chrome/common/url_constants.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_ui_data_source.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/webui_util.h" +#include "qtwebengine/browser/extensions/resources/grit/extensions_ui_qt_resources.h" +#include "qtwebengine/browser/extensions/resources/grit/extensions_ui_qt_resources_map.h" + +#include "extensions_ui_page_handler_qt.h" + +ExtensionsUIQt::ExtensionsUIQt(content::WebUI *web_ui) : ui::MojoWebUIController(web_ui, true) +{ + content::WebUIDataSource *source = content::WebUIDataSource::CreateAndAdd( + web_ui->GetWebContents()->GetBrowserContext(), chrome::kChromeUIExtensionsHost); + + webui::SetupWebUIDataSource( + source, base::make_span(kExtensionsUiQtResources, kExtensionsUiQtResourcesSize), + IDR_EXTENSIONS_UI_QT_EXTENSIONS_UI_QT_HTML); + + source->OverrideContentSecurityPolicy(network::mojom::CSPDirectiveName::TrustedTypes, + "trusted-types static-types polymer-html-literal " + "polymer-template-event-attribute-policy " + "lit-html-desktop;"); +} + +void ExtensionsUIQt::BindInterface( + mojo::PendingReceiver<qtwebengine::mojom::ExtensionsUIHandlerFactory> receiver) +{ + page_factory_receiver_.reset(); + page_factory_receiver_.Bind(std::move(receiver)); +} + +void ExtensionsUIQt::CreatePageHandler( + mojo::PendingRemote<qtwebengine::mojom::Page> page, + mojo::PendingReceiver<qtwebengine::mojom::PageHandler> receiver) +{ + DCHECK(page); + Profile *profile = Profile::FromWebUI(web_ui()); + page_handler_ = std::make_unique<ExtensionsUIPageHandlerQt>( + web_ui(), profile, std::move(receiver), std::move(page)); +} + +WEB_UI_CONTROLLER_TYPE_IMPL(ExtensionsUIQt) diff --git a/src/core/extensions/webui/extensions_ui_qt.h b/src/core/extensions/webui/extensions_ui_qt.h new file mode 100644 index 000000000..55f4c7505 --- /dev/null +++ b/src/core/extensions/webui/extensions_ui_qt.h @@ -0,0 +1,33 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef EXTENSIONS_UI_QT_H +#define EXTENSIONS_UI_QT_H + +#include "qtwebengine/browser/extensions/webui/extensions_ui_qt.mojom.h" +#include "ui/webui/mojo_web_ui_controller.h" + +class ExtensionsUIPageHandlerQt; + +class ExtensionsUIQt : public ui::MojoWebUIController, + public qtwebengine::mojom::ExtensionsUIHandlerFactory +{ +public: + explicit ExtensionsUIQt(content::WebUI *web_ui); + + ExtensionsUIQt(const ExtensionsUIQt &) = delete; + ExtensionsUIQt &operator=(const ExtensionsUIQt &) = delete; + + void BindInterface(mojo::PendingReceiver<qtwebengine::mojom::ExtensionsUIHandlerFactory> receiver); + +private: + // qtwebengine::mojom::ExtensionsUIHandlerFactory + void CreatePageHandler(mojo::PendingRemote<qtwebengine::mojom::Page> page, + mojo::PendingReceiver<qtwebengine::mojom::PageHandler> receiver) override; + + std::unique_ptr<ExtensionsUIPageHandlerQt> page_handler_; + mojo::Receiver<qtwebengine::mojom::ExtensionsUIHandlerFactory> page_factory_receiver_ { this }; + WEB_UI_CONTROLLER_TYPE_DECL(); +}; + +#endif // EXTENSIONS_UI_QT_H diff --git a/src/core/extensions/webui/select_file_dialog.cpp b/src/core/extensions/webui/select_file_dialog.cpp new file mode 100644 index 000000000..04eabff82 --- /dev/null +++ b/src/core/extensions/webui/select_file_dialog.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "select_file_dialog.h" + +#include "ui/shell_dialogs/selected_file_info.h" +#include "ui/shell_dialogs/select_file_policy.h" +#include "content/public/browser/web_contents.h" + +#include "content/public/browser/content_browser_client.h" +#include "content/public/common/content_client.h" + +namespace content { +extern ContentClient *GetContentClient(); +} + +SelectFileDialog::~SelectFileDialog() +{ + select_file_dialog_->ListenerDestroyed(); +} + +void SelectFileDialog::Show(SelectedCallback selected_callback, const base::FilePath &default_path, + content::WebContents *web_contents) +{ + // Dialog is self-deleting. + auto *dialog = new SelectFileDialog(); + dialog->ShowDialog(std::move(selected_callback), default_path, web_contents); +} + +void SelectFileDialog::FileSelected(const ui::SelectedFileInfo &file, int index) +{ + std::move(selected_callback_).Run(file.path()); + delete this; +} + +void SelectFileDialog::ShowDialog(SelectedCallback selected_callback, + const base::FilePath &default_path, + content::WebContents *web_contents) +{ + selected_callback_ = std::move(selected_callback); + + select_file_dialog_ = ui::SelectFileDialog::Create( + this, + std::unique_ptr<ui::SelectFilePolicy>( + content::GetContentClient()->browser()->CreateSelectFilePolicy(web_contents))); + + base::FilePath::StringType ext; + ui::SelectFileDialog::FileTypeInfo file_type_info; + select_file_dialog_->SelectFile(ui::SelectFileDialog::SELECT_FOLDER, std::u16string(), + default_path, &file_type_info, 0, ext, nullptr, nullptr); +} diff --git a/src/core/extensions/webui/select_file_dialog.h b/src/core/extensions/webui/select_file_dialog.h new file mode 100644 index 000000000..0e2ee353d --- /dev/null +++ b/src/core/extensions/webui/select_file_dialog.h @@ -0,0 +1,38 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef SELECT_FILE_DIALOG_H +#define SELECT_FILE_DIALOG_H + +#include "ui/shell_dialogs/select_file_dialog.h" +#include "base/functional/callback.h" + +typedef base::OnceCallback<void(const base::FilePath &)> SelectedCallback; + +namespace content { +class WebContents; +} +class SelectFileDialog : public ui::SelectFileDialog::Listener +{ +public: + SelectFileDialog(const SelectFileDialog &) = delete; + SelectFileDialog &operator=(const SelectFileDialog &) = delete; + + static void Show(SelectedCallback selected_callback, const base::FilePath &default_path, + content::WebContents *web_contents); + + // ui::SelectFileDialog::Listener + void FileSelected(const ui::SelectedFileInfo &file, int index) override; + void FileSelectionCanceled() override { } + +private: + SelectFileDialog() = default; + ~SelectFileDialog() override; + + void ShowDialog(SelectedCallback selected_callback, const base::FilePath &default_path, + content::WebContents *web_contents); + + scoped_refptr<ui::SelectFileDialog> select_file_dialog_; + SelectedCallback selected_callback_; +}; +#endif // SELECT_FILE_DIALOG_H diff --git a/src/core/net/webui_controller_factory_qt.cpp b/src/core/net/webui_controller_factory_qt.cpp index e35c88408..ac6475f95 100644 --- a/src/core/net/webui_controller_factory_qt.cpp +++ b/src/core/net/webui_controller_factory_qt.cpp @@ -48,17 +48,9 @@ // #include "chrome/browser/ui/webui/certificate_viewer_ui.h" // #endif -// #if BUILDFLAG(ENABLE_EXTENSIONS) -// #include "chrome/browser/extensions/extension_web_ui.h" -// #include "chrome/browser/ui/webui/extensions/extensions_ui.h" -// #include "chrome/common/extensions/extension_constants.h" -// #include "extensions/browser/extension_registry.h" -// #include "extensions/browser/extension_system.h" -// #include "extensions/common/constants.h" -// #include "extensions/common/extension.h" -// #include "extensions/common/feature_switch.h" -// #include "extensions/common/manifest.h" -// #endif +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/webui/extensions_ui_qt.h" +#endif using content::WebUI; using content::WebUIController; @@ -117,10 +109,10 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI *web_ui, Profile *profile, co // if (url.host_piece() == chrome::kChromeUICertificateViewerHost) // return &NewWebUI<CertificateViewerUI>; //#endif // USE_NSS_CERTS && USE_AURA -//#if BUILDFLAG(ENABLE_EXTENSIONS) -// if (url.host_piece() == chrome::kChromeUIExtensionsFrameHost) -// return &NewWebUI<extensions::ExtensionsUI>; -//#endif +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (url.host_piece() == chrome::kChromeUIExtensionsHost) + return &NewWebUI<ExtensionsUIQt>; +#endif //#if BUILDFLAG(ENABLE_PRINT_PREVIEW) // if (url.host_piece() == chrome::kChromeUIPrintHost && // !profile->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled)) { diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index ee754c77a..7dc71dd92 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -3353,7 +3353,7 @@ void tst_QWebEngineView::webUIURLs_data() QTest::newRow("discards") << QUrl("chrome://discards") << false; QTest::newRow("download-internals") << QUrl("chrome://download-internals") << false; QTest::newRow("downloads") << QUrl("chrome://downloads") << false; - QTest::newRow("extensions") << QUrl("chrome://extensions") << false; + QTest::newRow("extensions") << QUrl("chrome://extensions") << true; QTest::newRow("extensions-internals") << QUrl("chrome://extensions-internals") << false; QTest::newRow("flags") << QUrl("chrome://flags") << false; QTest::newRow("gcm-internals") << QUrl("chrome://gcm-internals") << false; |