This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. Copyright (c) 2019, The Brave Authors Copyright (c) 2025, The Helium Authors Alternatively, the contents of this file may be used under the terms of the GNU General Public License Version 3, as described below: Copyright (C) 2025 The Helium Authors This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . --- a/chrome/browser/importer/importer_list.cc +++ b/chrome/browser/importer/importer_list.cc @@ -27,6 +27,8 @@ #include "chrome/common/importer/edge_importer_utils_win.h" #endif +#include "chrome/browser/importer/chrome_importer_list.cc" + namespace { #if BUILDFLAG(IS_WIN) @@ -171,20 +173,30 @@ std::vector + --- a/components/user_data_importer/common/importer_data_types.h +++ b/components/user_data_importer/common/importer_data_types.h @@ -29,7 +29,8 @@ enum ImportItem { SEARCH_ENGINES = 1 << 4, HOME_PAGE = 1 << 5, AUTOFILL_FORM_DATA = 1 << 6, - ALL = (1 << 7) - 1 // All the bits should be 1, hence the -1. + EXTENSIONS = 1 << 7, + ALL = (1 << 8) - 1 // All the bits should be 1, hence the -1. }; // Information about a profile needed by an importer to do import work. @@ -111,6 +112,7 @@ enum VisitSource { VISIT_SOURCE_FIREFOX_IMPORTED = 1, VISIT_SOURCE_IE_IMPORTED = 2, VISIT_SOURCE_SAFARI_IMPORTED = 3, + VISIT_SOURCE_CHROME_IMPORTED = 4, }; } // namespace user_data_importer --- a/chrome/common/importer/profile_import_process_param_traits_macros.h +++ b/chrome/common/importer/profile_import_process_param_traits_macros.h @@ -23,11 +23,11 @@ #if BUILDFLAG(IS_WIN) IPC_ENUM_TRAITS_MIN_MAX_VALUE(user_data_importer::ImporterType, user_data_importer::TYPE_UNKNOWN, - user_data_importer::TYPE_EDGE) + user_data_importer::TYPE_PERPLEXITY_COMET) #else IPC_ENUM_TRAITS_MIN_MAX_VALUE(user_data_importer::ImporterType, user_data_importer::TYPE_UNKNOWN, - user_data_importer::TYPE_BOOKMARKS_FILE) + user_data_importer::TYPE_PERPLEXITY_COMET) #endif IPC_ENUM_TRAITS_MIN_MAX_VALUE(user_data_importer::ImportItem, --- a/chrome/browser/ui/webui/settings/import_data_handler.cc +++ b/chrome/browser/ui/webui/settings/import_data_handler.cc @@ -150,6 +150,9 @@ void ImportDataHandler::HandleImportData if (*type_dict.FindBool(prefs::kImportDialogSearchEngine)) { selected_items |= user_data_importer::SEARCH_ENGINES; } + if (*type_dict.FindBool(prefs::kImportDialogExtensions)) { + selected_items |= user_data_importer::EXTENSIONS; + } const user_data_importer::SourceProfile& source_profile = importer_list_->GetSourceProfileAt(browser_index); @@ -231,6 +234,8 @@ void ImportDataHandler::SendBrowserProfi browser_profile.Set( "autofillFormData", (browser_services & user_data_importer::AUTOFILL_FORM_DATA) != 0); + browser_profile.Set("extensions", + (browser_services & user_data_importer::EXTENSIONS) != 0); browser_profiles.Append(std::move(browser_profile)); } --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -3266,6 +3266,9 @@ inline constexpr char kDataUrlInWebWorke inline constexpr char kSharedWorkerExtendedLifetimeEnabled[] = "worker.shared_worker_extended_lifetime_enabled"; +inline constexpr char kImportDialogExtensions[] = + "import_dialog_extensions"; + // Boolean indicating whether clearing window.name when the navigation is // top-level, cross-site and swaps BrowsingContextGroup is allowed or not. inline constexpr char kClearWindowNameForNewBrowsingContextGroup[] = --- a/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc @@ -1236,6 +1236,8 @@ const PrefsUtil::TypedPrefMap& PrefsUtil settings_api::PrefType::kBoolean; (*s_allowlist)[::prefs::kImportDialogSearchEngine] = settings_api::PrefType::kBoolean; + (*s_allowlist)[::prefs::kImportDialogExtensions] = + settings_api::PrefType::kBoolean; #endif // BUILDFLAG(IS_CHROMEOS) // Supervised Users. This setting is queried in our Tast tests (b/241943380). --- a/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chrome/browser/ui/webui/settings/settings_ui.cc @@ -64,6 +64,7 @@ #include "chrome/browser/ui/webui/settings/about_handler.h" #include "chrome/browser/ui/webui/settings/accessibility_main_handler.h" #include "chrome/browser/ui/webui/settings/appearance_handler.h" +#include "chrome/browser/ui/webui/settings/brave_import_data_handler.h" #include "chrome/browser/ui/webui/settings/browser_lifetime_handler.h" #include "chrome/browser/ui/webui/settings/device_tab_visibility_handler.h" #include "chrome/browser/ui/webui/settings/dictation_handler.h" @@ -233,6 +234,7 @@ void SettingsUI::RegisterProfilePrefs( registry->RegisterBooleanPref(prefs::kImportDialogHistory, true); registry->RegisterBooleanPref(prefs::kImportDialogSavedPasswords, true); registry->RegisterBooleanPref(prefs::kImportDialogSearchEngine, true); + registry->RegisterBooleanPref(prefs::kImportDialogExtensions, true); registry->RegisterDictionaryPref(prefs::kDeviceTabVisibilityHiddenSessions); } @@ -268,7 +270,7 @@ SettingsUI::SettingsUI(content::WebUI* w AddSettingsPageUIHandler(std::make_unique(profile)); AddSettingsPageUIHandler(std::make_unique()); AddSettingsPageUIHandler(std::make_unique(profile)); - AddSettingsPageUIHandler(std::make_unique()); + AddSettingsPageUIHandler(std::make_unique()); AddSettingsPageUIHandler(std::make_unique()); #if BUILDFLAG(IS_WIN) --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc @@ -1253,6 +1253,8 @@ void AddImportDataStrings(content::WebUI {"importHistory", IDS_SETTINGS_IMPORT_HISTORY_CHECKBOX}, {"importFavorites", IDS_SETTINGS_IMPORT_FAVORITES_CHECKBOX}, {"importPasswords", IDS_SETTINGS_IMPORT_PASSWORDS_CHECKBOX}, + // abusing some strings here so _we_ don't have to localize them + {"importExtensions", IDS_EXTENSIONS_TOOLBAR_TITLE}, {"importSearch", IDS_SETTINGS_IMPORT_SEARCH_ENGINES_CHECKBOX}, {"importAutofillFormData", IDS_SETTINGS_IMPORT_AUTOFILL_FORM_DATA_CHECKBOX}, --- a/chrome/browser/resources/settings/people_page/import_data_dialog.html.ts +++ b/chrome/browser/resources/settings/people_page/import_data_dialog.html.ts @@ -70,6 +70,11 @@ export function getHtml(this: SettingsIm pref-key="import_dialog_autofill_form_data" label="$i18n{importAutofillFormData}" no-set-pref> + + --- a/chrome/browser/resources/settings/people_page/import_data_browser_proxy.ts +++ b/chrome/browser/resources/settings/people_page/import_data_browser_proxy.ts @@ -19,6 +19,7 @@ export interface BrowserProfile { passwords: boolean; search: boolean; autofillFormData: boolean; + extensions: boolean; } /** --- a/chrome/browser/resources/settings/people_page/import_data_dialog.ts +++ b/chrome/browser/resources/settings/people_page/import_data_dialog.ts @@ -78,6 +78,7 @@ export class SettingsImportDataDialogEle passwords: false, search: false, autofillFormData: false, + extensions: false, }; protected accessor noImportDataTypeSelected_: boolean = false; protected accessor importStatus_: ImportDataStatus = ImportDataStatus.INITIAL; --- a/chrome/browser/ui/webui/settings/BUILD.gn +++ b/chrome/browser/ui/webui/settings/BUILD.gn @@ -13,6 +13,8 @@ source_set("settings") { "about_handler.h", "accessibility_main_handler.h", "appearance_handler.h", + "brave_import_data_handler.h", + "brave_importer_observer.h", "browser_lifetime_handler.h", "captions_handler.h", "custom_home_pages_table_model.h", @@ -127,6 +129,7 @@ source_set("settings") { if (is_mac) { sources += [ "mac_system_settings_handler.h" ] + sources += [ "brave_full_disk_access_confirm_dialog_delegate.h" ] } if (is_chromeos) { @@ -144,6 +147,8 @@ source_set("impl") { "about_handler.cc", "accessibility_main_handler.cc", "appearance_handler.cc", + "brave_import_data_handler.cc", + "brave_importer_observer.cc", "browser_lifetime_handler.cc", "captions_handler.cc", "custom_home_pages_table_model.cc", @@ -375,6 +380,7 @@ source_set("impl") { sources += [ "mac_system_settings_handler.cc", "settings_utils_mac.mm", + "brave_full_disk_access_confirm_dialog_delegate_mac.mm", ] } --- a/chrome/browser/ui/webui/settings/import_data_handler.h +++ b/chrome/browser/ui/webui/settings/import_data_handler.h @@ -36,9 +36,9 @@ class ImportDataHandler : public Setting void RegisterMessages() override; void OnJavascriptAllowed() override {} void OnJavascriptDisallowed() override; - + friend class BraveImportDataHandler; private: - void StartImport(const user_data_importer::SourceProfile& source_profile, + virtual void StartImport(const user_data_importer::SourceProfile& source_profile, uint16_t imported_items); // Handler for the "importData" message. First argument is the selected --- a/chrome/browser/importer/BUILD.gn +++ b/chrome/browser/importer/BUILD.gn @@ -6,6 +6,10 @@ assert(is_win || is_mac || is_linux || i source_set("importer") { sources = [ + "brave_external_process_importer_client.h", + "brave_external_process_importer_host.h", + "brave_in_process_importer_bridge.h", + "extensions_import_helpers.h", "external_process_importer_client.h", "external_process_importer_host.h", "firefox_profile_lock.h", @@ -35,6 +39,10 @@ source_set("importer") { source_set("impl") { sources = [ + "brave_external_process_importer_client.cc", + "brave_external_process_importer_host.cc", + "brave_in_process_importer_bridge.cc", + "extensions_import_helpers.cc", "external_process_importer_client.cc", "external_process_importer_host.cc", "firefox_profile_lock.cc", --- a/chrome/browser/importer/external_process_importer_host.h +++ b/chrome/browser/importer/external_process_importer_host.h @@ -79,8 +79,13 @@ class ExternalProcessImporterHost void NotifyImportStarted(); void NotifyImportItemStarted(user_data_importer::ImportItem item); void NotifyImportItemEnded(user_data_importer::ImportItem item); - void NotifyImportEnded(); + void virtual NotifyImportEnded(); + friend class BraveExternalProcessImporterHost; + void set_parent_view(gfx::NativeView parent_view) { + parent_view_ = parent_view; + } + gfx::NativeView parent_view_ = gfx::NativeView(); private: // ExternalProcessImporterHost deletes itself in OnImportEnded(). ~ExternalProcessImporterHost() override; --- a/components/history/core/browser/history_types.h +++ b/components/history/core/browser/history_types.h @@ -56,6 +56,8 @@ enum VisitSource { SOURCE_SAFARI_IMPORTED = 5, SOURCE_ACTOR = 6, // Added by the GLIC actor. SOURCE_OS_MIGRATION_IMPORTED = 7, + SOURCE_CHROME_IMPORTED = 8, + SOURCE_BRAVE_IMPORTED = 9, }; // Corresponds to the "id" column of the "visited_links" SQL table. --- a/components/history/core/browser/visit_database.cc +++ b/components/history/core/browser/visit_database.cc @@ -123,6 +123,8 @@ VisitSource VisitSourceFromInt(int value case SOURCE_SAFARI_IMPORTED: case SOURCE_ACTOR: case SOURCE_OS_MIGRATION_IMPORTED: + case SOURCE_CHROME_IMPORTED: + case SOURCE_BRAVE_IMPORTED: return converted; } // In cases of database corruption, SOURCE_BROWSED is a safe default value. --- a/chrome/browser/importer/in_process_importer_bridge.cc +++ b/chrome/browser/importer/in_process_importer_bridge.cc @@ -53,6 +53,8 @@ history::VisitSource ConvertImporterVisi return history::SOURCE_IE_IMPORTED; case user_data_importer::VISIT_SOURCE_SAFARI_IMPORTED: return history::SOURCE_SAFARI_IMPORTED; + case user_data_importer::VISIT_SOURCE_CHROME_IMPORTED: + return history::SOURCE_CHROME_IMPORTED; } NOTREACHED(); } --- a/chrome/utility/BUILD.gn +++ b/chrome/utility/BUILD.gn @@ -96,6 +96,12 @@ static_library("utility") { sources += [ "importer/bookmarks_file_importer.cc", "importer/bookmarks_file_importer.h", + "importer/brave_external_process_importer_bridge.cc", + "importer/brave_external_process_importer_bridge.h", + "importer/brave_profile_import_impl.cc", + "importer/brave_profile_import_impl.h", + "importer/chrome_importer.cc", + "importer/chrome_importer.h", "importer/external_process_importer_bridge.cc", "importer/external_process_importer_bridge.h", "importer/importer.cc", --- a/chrome/utility/services.cc +++ b/chrome/utility/services.cc @@ -64,8 +64,10 @@ #endif // BUILDFLAG(IS_LINUX) #if !BUILDFLAG(IS_ANDROID) +#include "chrome/common/importer/chrome_profile_import.mojom.h" #include "chrome/common/importer/profile_import.mojom.h" #include "chrome/services/reading_mode_metrics/reading_mode_metrics_service.h" +#include "chrome/utility/importer/brave_profile_import_impl.h" #include "chrome/utility/importer/profile_import_impl.h" #include "components/mirroring/service/mirroring_service.h" #include "services/proxy_resolver/proxy_resolver_factory_impl.h" // nogncheck @@ -156,6 +158,13 @@ static_assert(BUILDFLAG(ENABLE_PRINTING) namespace { +#if !BUILDFLAG(IS_ANDROID) +auto RunBraveProfileImporter( + mojo::PendingReceiver receiver) { + return std::make_unique(std::move(receiver)); +} +#endif + auto RunFilePatcher(mojo::PendingReceiver receiver) { return std::make_unique(std::move(receiver)); } @@ -503,6 +512,7 @@ void RegisterMainThreadServices(mojo::Se #endif // BUILDFLAG(IS_ANDROID) #if !BUILDFLAG(IS_ANDROID) + services.Add(RunBraveProfileImporter); services.Add(RunProfileImporter); services.Add(RunMirroringService); services.Add(RunReadingModeMetricsService); --- a/chrome/utility/importer/external_process_importer_bridge.h +++ b/chrome/utility/importer/external_process_importer_bridge.h @@ -72,7 +72,7 @@ class ExternalProcessImporterBridge : pu std::u16string GetLocalizedString(int message_id) override; // End ImporterBridge implementation. - + friend class BraveExternalProcessImporterBridge; private: ~ExternalProcessImporterBridge() override; --- a/chrome/browser/importer/external_process_importer_host.cc +++ b/chrome/browser/importer/external_process_importer_host.cc @@ -8,6 +8,8 @@ #include "base/functional/bind.h" #include "chrome/browser/bookmarks/bookmark_model_factory.h" +#include "chrome/browser/importer/brave_external_process_importer_client.h" +#include "chrome/browser/importer/brave_in_process_importer_bridge.h" #include "chrome/browser/importer/external_process_importer_client.h" #include "chrome/browser/importer/firefox_profile_lock.h" #include "chrome/browser/importer/importer_lock_dialog.h" @@ -102,10 +104,10 @@ void ExternalProcessImporterHost::Launch // bridge lives in the external process (see ProfileImportThread). // The ExternalProcessImporterClient created in the next line owns the bridge, // and will delete it. - InProcessImporterBridge* bridge = - new InProcessImporterBridge(writer_.get(), + BraveInProcessImporterBridge* bridge = + new BraveInProcessImporterBridge(writer_.get(), weak_ptr_factory_.GetWeakPtr()); - client_ = new ExternalProcessImporterClient( + client_ = new BraveExternalProcessImporterClient( weak_ptr_factory_.GetWeakPtr(), source_profile_, items_, bridge); client_->Start(); } --- a/chrome/browser/importer/in_process_importer_bridge.h +++ b/chrome/browser/importer/in_process_importer_bridge.h @@ -59,7 +59,7 @@ class InProcessImporterBridge : public I std::u16string GetLocalizedString(int message_id) override; // End ImporterBridge implementation. - + friend class BraveInProcessImporterBridge; private: ~InProcessImporterBridge() override; --- a/chrome/browser/importer/importer_uma.cc +++ b/chrome/browser/importer/importer_uma.cc @@ -59,6 +59,9 @@ void LogImporterUseToMetrics(const std:: case user_data_importer::TYPE_BOOKMARKS_FILE: metrics_type = IMPORTER_METRICS_BOOKMARKS_FILE; break; + default: + metrics_type = IMPORTER_METRICS_UNKNOWN; + break; } // Note: This leaks memory, which is the expected behavior as the factory --- a/chrome/browser/importer/external_process_importer_client.h +++ b/chrome/browser/importer/external_process_importer_client.h @@ -48,10 +48,10 @@ class ExternalProcessImporterClient const ExternalProcessImporterClient&) = delete; // Launches the task to start the external process. - void Start(); + virtual void Start(); // Called by the ExternalProcessImporterHost on import cancel. - void Cancel(); + virtual void Cancel(); // chrome::mojom::ProfileImportObserver: void OnImportStart() override; @@ -82,6 +82,8 @@ class ExternalProcessImporterClient const std::vector& autofill_form_data_entry_group) override; + friend class BraveExternalProcessImporterClient; + protected: ~ExternalProcessImporterClient() override; @@ -97,7 +99,7 @@ class ExternalProcessImporterClient // The Mojo connections need to be torn down on the same thread that created // them, but the destructor is not guaranteed to be run on that thread so we // tear down the connections explicitly. - void CloseMojoHandles(); + virtual void CloseMojoHandles(); // These variables store data being collected from the importer until the // entire group has been collected and is ready to be written to the profile. --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -11833,6 +11833,15 @@ Check your passwords anytime in + + Imported from $1Chrome + + + Import profile still in use + + + To continue importing data, first close the browser you're importing from. + Mozilla Firefox --- a/chrome/browser/importer/importer_lock_dialog.h +++ b/chrome/browser/importer/importer_lock_dialog.h @@ -21,6 +21,11 @@ void ShowImportLockDialog(gfx::NativeWin base::OnceCallback callback, int importer_lock_title_id = IDS_IMPORTER_LOCK_TITLE, int importer_lock_text_id = IDS_IMPORTER_LOCK_TEXT); +void ShowImportLockDialog(gfx::NativeView parent_view, + gfx::NativeWindow parent, + base::OnceCallback callback, + int importer_lock_title_id = IDS_IMPORTER_LOCK_TITLE, + int importer_lock_text_id = IDS_IMPORTER_LOCK_TEXT); } // namespace importer --- a/chrome/browser/ui/views/importer/import_lock_dialog_view.cc +++ b/chrome/browser/ui/views/importer/import_lock_dialog_view.cc @@ -28,8 +28,36 @@ void ShowImportLockDialog(gfx::NativeWin importer_lock_title_id, importer_lock_text_id); } +void ShowImportLockDialog(gfx::NativeView parent_view, + gfx::NativeWindow parent, + base::OnceCallback callback, + int importer_lock_title_id, + int importer_lock_text_id) { + ImportLockDialogView::Show(parent_view, parent, std::move(callback), + importer_lock_title_id, importer_lock_text_id); +} + } // namespace importer + +// static +void ImportLockDialogView::Show(gfx::NativeView parent_view, + gfx::NativeWindow parent, + base::OnceCallback callback, + int importer_lock_title_id, + int importer_lock_text_id) { + views::DialogDelegate::CreateDialogWidget( + new ImportLockDialogView(std::move(callback), importer_lock_title_id, + importer_lock_text_id), + parent, parent_view) + ->Show(); + base::RecordAction(UserMetricsAction("ImportLockDialogView_Shown")); +} + +ui::mojom::ModalType ImportLockDialogView::GetModalType() const { + return ui::mojom::ModalType::kChild; +} + // static void ImportLockDialogView::Show(gfx::NativeWindow parent, base::OnceCallback callback, --- a/chrome/browser/ui/views/importer/import_lock_dialog_view.h +++ b/chrome/browser/ui/views/importer/import_lock_dialog_view.h @@ -23,6 +23,12 @@ class ImportLockDialogView : public view base::OnceCallback callback, int importer_lock_title_id = IDS_IMPORTER_LOCK_TITLE, int importer_lock_text_id = IDS_IMPORTER_LOCK_TEXT); + static void Show(gfx::NativeView parent_view, + gfx::NativeWindow parent, + base::OnceCallback callback, + int importer_lock_title_id = IDS_IMPORTER_LOCK_TITLE, + int importer_lock_text_id = IDS_IMPORTER_LOCK_TEXT); + ui::mojom::ModalType GetModalType() const override; private: ImportLockDialogView(base::OnceCallback callback,