summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/extensions
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2023-10-27 17:02:53 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2023-10-27 17:04:08 +0200
commit3dce9b5818576f04ce21cec4b3686eda012e5b65 (patch)
treefe3d59c6da3e62c74563710ba63996585293c743 /chromium/chrome/browser/extensions
parent5a424f4a7b188b75da63eb697f63558af0b17f6f (diff)
BASELINE: Update Chromium to 118.0.5993.24
Diffstat (limited to 'chromium/chrome/browser/extensions')
-rw-r--r--chromium/chrome/browser/extensions/BUILD.gn32
-rw-r--r--chromium/chrome/browser/extensions/api/alarms/alarms_apitest.cc19
-rw-r--r--chromium/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc405
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api.h52
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api_unittest.cc140
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc39
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h6
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h2
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_util.cc72
-rw-r--r--chromium/chrome/browser/extensions/api/automation/automation_apitest.cc152
-rw-r--r--chromium/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc1
-rw-r--r--chromium/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest_chromeos.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_api.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc66
-rw-r--r--chromium/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc13
-rw-r--r--chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc12
-rw-r--r--chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc49
-rw-r--r--chromium/chrome/browser/extensions/api/chrome_extensions_api_client.h5
-rw-r--r--chromium/chrome/browser/extensions/api/commands/command_service.cc1
-rw-r--r--chromium/chrome/browser/extensions/api/content_settings/content_settings_api.cc24
-rw-r--r--chromium/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/context_menus/extension_context_menu_browsertest.cc95
-rw-r--r--chromium/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/debugger/debugger_api.cc72
-rw-r--r--chromium/chrome/browser/extensions/api/debugger/debugger_apitest.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/debugger/extension_dev_tools_infobar_delegate.h3
-rw-r--r--chromium/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc71
-rw-r--r--chromium/chrome/browser/extensions/api/declarative_net_request/ruleset_manager_unittest.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/developer_private_api.cc206
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/developer_private_api.h59
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc299
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc20
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.cc68
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.h11
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc161
-rw-r--r--chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc13
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash_unittest.cc17
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_lacros_apitest.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc9
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.cc16
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc18
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc72
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/file_entry_picker.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/font_settings/font_settings_api.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc192
-rw-r--r--chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h48
-rw-r--r--chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_browsertest.cc58
-rw-r--r--chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc96
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_api.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_api.h11
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_apitest.cc277
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.cc43
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.h4
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_constants.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_constants.h2
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_error.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_error.h2
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc34
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.cc64
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.h10
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_private_api.cc28
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_private_api.h29
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_private_apitest.cc69
-rw-r--r--chromium/chrome/browser/extensions/api/identity/test_scoped_should_animate_web_auth_flow_info_bar.h30
-rw-r--r--chromium/chrome/browser/extensions/api/identity/web_auth_flow.cc260
-rw-r--r--chromium/chrome/browser/extensions/api/identity/web_auth_flow.h62
-rw-r--r--chromium/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc317
-rw-r--r--chromium/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.cc11
-rw-r--r--chromium/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h9
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/operation_manager.cc1
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos_unittest.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_mac.cc20
-rw-r--r--chromium/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/input_ime/input_ime_apitest_chromeos.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc13
-rw-r--r--chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc120
-rw-r--r--chromium/chrome/browser/extensions/api/management/chrome_management_api_delegate.h12
-rw-r--r--chromium/chrome/browser/extensions/api/management/management_api_browsertest.cc1
-rw-r--r--chromium/chrome/browser/extensions/api/management/management_api_unittest.cc14
-rw-r--r--chromium/chrome/browser/extensions/api/management/management_apitest.cc64
-rw-r--r--chromium/chrome/browser/extensions/api/mdns/mdns_api.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc20
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/messaging_apitest.cc25
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc37
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc11
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/native_messaging_test_util.h6
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/native_process_launcher_win.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc80
-rw-r--r--chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.h2
-rw-r--r--chromium/chrome/browser/extensions/api/notifications/extension_notification_handler_unittest.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/page_capture/page_capture_api.cc31
-rw-r--r--chromium/chrome/browser/extensions/api/page_capture/page_capture_api.h6
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc56
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.h16
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc216
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc128
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.h79
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc89
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h32
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.cc30
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h5
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc193
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h30
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc696
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils.h6
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils_chromeos.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc79
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h35
-rw-r--r--chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.h3
-rw-r--r--chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.h2
-rw-r--r--chromium/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc1
-rw-r--r--chromium/chrome/browser/extensions/api/preference/preference_api.cc105
-rw-r--r--chromium/chrome/browser/extensions/api/preference/preference_api.h2
-rw-r--r--chromium/chrome/browser/extensions/api/preference/preference_api_lacros_browsertest.cc298
-rw-r--r--chromium/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/preference/preference_apitest.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/preference/preference_helpers.h1
-rw-r--r--chromium/chrome/browser/extensions/api/printer_provider/printer_provider_apitest.cc16
-rw-r--r--chromium/chrome/browser/extensions/api/printing/fake_print_job_controller_ash.h5
-rw-r--r--chromium/chrome/browser/extensions/api/printing/printing_api_handler_unittest.cc13
-rw-r--r--chromium/chrome/browser/extensions/api/printing/printing_api_utils.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/printing/printing_api_utils_unittest.cc57
-rw-r--r--chromium/chrome/browser/extensions/api/printing/printing_apitest.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/proxy/proxy_api.cc9
-rw-r--r--chromium/chrome/browser/extensions/api/proxy/proxy_apitest.cc29
-rw-r--r--chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.cc56
-rw-r--r--chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api_unittest.cc29
-rw-r--r--chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.cc43
-rw-r--r--chromium/chrome/browser/extensions/api/reading_list/OWNERS2
-rw-r--r--chromium/chrome/browser/extensions/api/reading_list/reading_list_api.cc266
-rw-r--r--chromium/chrome/browser/extensions/api/reading_list/reading_list_api.h133
-rw-r--r--chromium/chrome/browser/extensions/api/reading_list/reading_list_api_constants.cc17
-rw-r--r--chromium/chrome/browser/extensions/api/reading_list/reading_list_api_constants.h20
-rw-r--r--chromium/chrome/browser/extensions/api/reading_list/reading_list_api_unittest.cc538
-rw-r--r--chromium/chrome/browser/extensions/api/reading_list/reading_list_apitest.cc67
-rw-r--r--chromium/chrome/browser/extensions/api/reading_list/reading_list_event_router.cc143
-rw-r--r--chromium/chrome/browser/extensions/api/reading_list/reading_list_event_router.h67
-rw-r--r--chromium/chrome/browser/extensions/api/reading_list/reading_list_util.cc24
-rw-r--r--chromium/chrome/browser/extensions/api/reading_list/reading_list_util.h18
-rw-r--r--chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h2
-rw-r--r--chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_util.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/scripting/scripting_api.cc195
-rw-r--r--chromium/chrome/browser/extensions/api/scripting/scripting_api.h8
-rw-r--r--chromium/chrome/browser/extensions/api/scripting/scripting_apitest.cc27
-rw-r--r--chromium/chrome/browser/extensions/api/settings_overrides/settings_overrides_api.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/generated_prefs.h12
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/generated_prefs_factory.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/generated_prefs_factory.h2
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc31
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.h2
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc11
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.h5
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.h2
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_unittest.cc160
-rw-r--r--chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.h6
-rw-r--r--chromium/chrome/browser/extensions/api/storage/policy_value_store.h3
-rw-r--r--chromium/chrome/browser/extensions/api/storage/setting_sync_data.h5
-rw-r--r--chromium/chrome/browser/extensions/api/storage/settings_sync_processor.h3
-rw-r--r--chromium/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h2
-rw-r--r--chromium/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_api.cc70
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_apitest.cc17
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_constants.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_constants.h3
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/windows_event_router.h2
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/terminal_private_api.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/user_scripts/user_scripts_apitest.cc52
-rw-r--r--chromium/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc11
-rw-r--r--chromium/chrome/browser/extensions/api/virtual_keyboard_private/virtual_keyboard_private_apitest.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc17
-rw-r--r--chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc17
-rw-r--r--chromium/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc39
-rw-r--r--chromium/chrome/browser/extensions/api/web_request/web_request_apitest.cc83
-rw-r--r--chromium/chrome/browser/extensions/api/web_view/chrome_web_view_internal_api.cc24
-rw-r--r--chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc93
-rw-r--r--chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h46
-rw-r--r--chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc28
-rw-r--r--chromium/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc15
-rw-r--r--chromium/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc50
-rw-r--r--chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.h2
210 files changed, 5445 insertions, 3959 deletions
diff --git a/chromium/chrome/browser/extensions/BUILD.gn b/chromium/chrome/browser/extensions/BUILD.gn
index 51ffd40dbf0..690a5ddf57d 100644
--- a/chromium/chrome/browser/extensions/BUILD.gn
+++ b/chromium/chrome/browser/extensions/BUILD.gn
@@ -185,8 +185,6 @@ static_library("extensions") {
"api/identity/identity_launch_web_auth_flow_function.h",
"api/identity/identity_mint_queue.cc",
"api/identity/identity_mint_queue.h",
- "api/identity/identity_private_api.cc",
- "api/identity/identity_private_api.h",
"api/identity/identity_remove_cached_auth_token_function.cc",
"api/identity/identity_remove_cached_auth_token_function.h",
"api/identity/identity_token_cache.cc",
@@ -290,6 +288,14 @@ static_library("extensions") {
"api/proxy/proxy_api_constants.h",
"api/proxy/proxy_api_helpers.cc",
"api/proxy/proxy_api_helpers.h",
+ "api/reading_list/reading_list_api.cc",
+ "api/reading_list/reading_list_api.h",
+ "api/reading_list/reading_list_api_constants.cc",
+ "api/reading_list/reading_list_api_constants.h",
+ "api/reading_list/reading_list_event_router.cc",
+ "api/reading_list/reading_list_event_router.h",
+ "api/reading_list/reading_list_util.cc",
+ "api/reading_list/reading_list_util.h",
"api/resources_private/resources_private_api.cc",
"api/resources_private/resources_private_api.h",
"api/runtime/chrome_runtime_api_delegate.cc",
@@ -566,6 +572,8 @@ static_library("extensions") {
"extension_system_impl.h",
"extension_tab_util.cc",
"extension_tab_util.h",
+ "extension_telemetry_service_verdict_handler.cc",
+ "extension_telemetry_service_verdict_handler.h",
"extension_ui_util.cc",
"extension_ui_util.h",
"extension_uninstall_dialog.cc",
@@ -735,6 +743,13 @@ static_library("extensions") {
]
}
+ if (is_chromeos_ash) {
+ sources += [
+ "file_handlers/web_file_handlers_permission_handler.cc",
+ "file_handlers/web_file_handlers_permission_handler.h",
+ ]
+ }
+
configs += [
"//build/config:precompiled_headers",
"//build/config/compiler:wexit_time_destructors",
@@ -811,7 +826,6 @@ static_library("extensions") {
"//chrome/browser/safe_browsing:metrics_collector",
"//chrome/browser/ui/tabs:tab_enums",
"//chrome/browser/web_applications",
- "//chromeos/components/kiosk",
"//components/cbor:cbor",
"//components/commerce/core:pref_names",
"//components/device_reauth",
@@ -865,6 +879,7 @@ static_library("extensions") {
"//components/language/core/common",
"//components/language/core/language_model",
"//components/live_caption:constants",
+ "//components/media_device_salt",
"//components/nacl/common:buildflags",
"//components/navigation_interception",
"//components/net_log",
@@ -875,6 +890,8 @@ static_library("extensions") {
"//components/password_manager/core/browser",
"//components/password_manager/core/browser:affiliation",
"//components/password_manager/core/browser:import_results",
+ "//components/password_manager/core/browser/features:password_features",
+ "//components/password_manager/core/browser/import:importer",
"//components/password_manager/core/browser/leak_detection",
"//components/payments/core",
"//components/performance_manager",
@@ -883,7 +900,9 @@ static_library("extensions") {
"//components/policy/core/browser",
"//components/pref_registry",
"//components/privacy_sandbox:privacy_sandbox_prefs",
+ "//components/privacy_sandbox:tracking_protection_prefs",
"//components/proxy_config",
+ "//components/reading_list/core",
"//components/resources",
"//components/safe_browsing:buildflags",
"//components/safe_browsing/content/browser/web_ui:web_ui",
@@ -892,7 +911,7 @@ static_library("extensions") {
"//components/safe_browsing/core/common:safe_browsing_prefs",
"//components/safe_browsing/core/common/proto:csd_proto",
"//components/search_engines",
- "//components/services/app_service/public/cpp:app_types",
+ "//components/services/app_service",
"//components/services/patch/content",
"//components/services/unzip/content",
"//components/services/unzip/public/cpp",
@@ -1170,11 +1189,11 @@ static_library("extensions") {
"//ash/webui/camera_app_ui:mojo_bindings",
"//ash/webui/file_manager/untrusted_resources:file_manager_untrusted_resources",
"//ash/webui/resources:media_app_bundle_resources_grit",
+ "//ash/webui/settings/public/constants:mojom",
"//chrome/browser/ash/crosapi",
"//chrome/browser/ash/crostini:crostini_installer_types_mojom",
"//chrome/browser/devtools",
"//chrome/browser/nearby_sharing/common",
- "//chrome/browser/ui/webui/settings/chromeos/constants:mojom",
"//chromeos/ash/components/attestation",
"//chromeos/ash/components/cryptohome",
"//chromeos/ash/components/dbus",
@@ -1193,6 +1212,7 @@ static_library("extensions") {
"//chromeos/ash/components/login/auth",
"//chromeos/ash/components/login/login_state",
"//chromeos/ash/components/network",
+ "//chromeos/ash/components/osauth/public",
"//chromeos/ash/components/proximity_auth",
"//chromeos/ash/components/settings",
"//chromeos/ash/components/system",
@@ -1286,7 +1306,6 @@ static_library("extensions") {
"system_display/display_info_provider_mac.cc",
"system_display/display_info_provider_mac.h",
]
- configs += [ "//build/config/compiler:enable_arc" ]
}
if (is_linux || is_chromeos_lacros) {
@@ -1407,7 +1426,6 @@ static_library("test_support") {
testonly = true
sources = [
- "api/identity/test_scoped_should_animate_web_auth_flow_info_bar.h",
"api/passwords_private/test_passwords_private_delegate.cc",
"api/passwords_private/test_passwords_private_delegate.h",
"chrome_extension_test_notification_observer.cc",
diff --git a/chromium/chrome/browser/extensions/api/alarms/alarms_apitest.cc b/chromium/chrome/browser/extensions/api/alarms/alarms_apitest.cc
index 6fb95362c99..807a958ebbb 100644
--- a/chromium/chrome/browser/extensions/api/alarms/alarms_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/alarms/alarms_apitest.cc
@@ -112,25 +112,8 @@ IN_PROC_BROWSER_TEST_P(AlarmsApiTest, IncognitoSpanning) {
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
-// Test that the histogram for counting the number of alarms for an extension
-// is working properly. The PRE step installs the alarms and we'll check the
-// histogram in the main part of the test.
-IN_PROC_BROWSER_TEST_P(AlarmsApiTest, PRE_Count) {
+IN_PROC_BROWSER_TEST_P(AlarmsApiTest, Count) {
EXPECT_TRUE(RunExtensionTest("alarms/count")) << message_;
}
-// TODO(crbug.com/1405713): Fix failing test on Mac builders.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_Count DISABLED_Count
-#else
-#define MAYBE_Count Count
-#endif
-IN_PROC_BROWSER_TEST_P(AlarmsApiTest, MAYBE_Count) {
- // The histogram will be updated when the extension is loaded during
- // startup. This will happen before we enter the test, so just check
- // that the update is present.
- histogram_tester_->ExpectUniqueSample(
- "Extensions.AlarmManager.AlarmsLoadedCount", 100, 1);
-}
-
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc b/chromium/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc
index c10ee262684..6aec2a92208 100644
--- a/chromium/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc
+++ b/chromium/chrome/browser/extensions/api/api_browser_context_keyed_service_factories.cc
@@ -25,6 +25,7 @@
#include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h"
#include "chrome/browser/extensions/api/preference/preference_api.h"
#include "chrome/browser/extensions/api/processes/processes_api.h"
+#include "chrome/browser/extensions/api/reading_list/reading_list_event_router.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
#include "chrome/browser/extensions/api/sessions/sessions_api.h"
#include "chrome/browser/extensions/api/settings_overrides/settings_overrides_api.h"
@@ -101,6 +102,7 @@ void EnsureApiBrowserContextKeyedServiceFactoriesBuilt() {
#endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
extensions::PreferenceAPI::GetFactoryInstance();
extensions::ProcessesAPI::GetFactoryInstance();
+ extensions::ReadingListEventRouter::GetFactoryInstance();
extensions::SafeBrowsingPrivateEventRouterFactory::GetInstance();
extensions::SessionsAPI::GetFactoryInstance();
extensions::SettingsPrivateEventRouterFactory::GetInstance();
diff --git a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
index a956d2e7f5d..b619e9a0bde 100644
--- a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
+#include <algorithm>
#include <utility>
#include "base/functional/bind.h"
@@ -22,12 +23,15 @@
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/core/browser/autofill_address_util.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/browser_autofill_manager.h"
#include "components/autofill/core/browser/data_model/autofill_profile.h"
#include "components/autofill/core/browser/data_model/credit_card.h"
#include "components/autofill/core/browser/data_model/iban.h"
#include "components/autofill/core/browser/form_data_importer.h"
+#include "components/autofill/core/browser/metrics/payments/mandatory_reauth_metrics.h"
#include "components/autofill/core/browser/payments/local_card_migration_manager.h"
+#include "components/autofill/core/browser/payments/mandatory_reauth_manager.h"
#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
#include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
#include "components/autofill/core/browser/personal_data_manager.h"
@@ -36,7 +40,6 @@
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/strings/grit/components_chromium_strings.h"
-#include "components/strings/grit/components_google_chrome_strings.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_function.h"
@@ -50,6 +53,11 @@
namespace autofill_private = extensions::api::autofill_private;
namespace addressinput = i18n::addressinput;
+using autofill::autofill_metrics::LogMandatoryReauthOptInOrOutUpdateEvent;
+using autofill::autofill_metrics::LogMandatoryReauthSettingsPageEditCardEvent;
+using autofill::autofill_metrics::MandatoryReauthAuthenticationFlowEvent;
+using autofill::autofill_metrics::MandatoryReauthOptInOrOutSource;
+
namespace {
static const char kSettingsOrigin[] = "Chrome settings";
@@ -67,89 +75,19 @@ constexpr char kFieldLengthKey[] = "isLongField";
constexpr char kFieldNameKey[] = "fieldName";
constexpr char kFieldRequired[] = "isRequired";
-// Field names for the address components.
-constexpr char kFullNameField[] = "FULL_NAME";
-constexpr char kCompanyNameField[] = "COMPANY_NAME";
-constexpr char kAddressLineField[] = "ADDRESS_LINES";
-constexpr char kDependentLocalityField[] = "ADDRESS_LEVEL_3";
-constexpr char kCityField[] = "ADDRESS_LEVEL_2";
-constexpr char kStateField[] = "ADDRESS_LEVEL_1";
-constexpr char kPostalCodeField[] = "POSTAL_CODE";
-constexpr char kSortingCodeField[] = "SORTING_CODE";
-constexpr char kCountryField[] = "COUNTY_CODE";
-
-// Converts an autofill::ServerFieldType to string format. Used in serilization
-// of field type info to be used in JavaScript code, and hence those values
-// shouldn't be modified.
-const char* GetStringFromAddressField(i18n::addressinput::AddressField type) {
- switch (type) {
- case i18n::addressinput::RECIPIENT:
- return kFullNameField;
- case i18n::addressinput::ORGANIZATION:
- return kCompanyNameField;
- case i18n::addressinput::STREET_ADDRESS:
- return kAddressLineField;
- case i18n::addressinput::DEPENDENT_LOCALITY:
- return kDependentLocalityField;
- case i18n::addressinput::LOCALITY:
- return kCityField;
- case i18n::addressinput::ADMIN_AREA:
- return kStateField;
- case i18n::addressinput::POSTAL_CODE:
- return kPostalCodeField;
- case i18n::addressinput::SORTING_CODE:
- return kSortingCodeField;
- case i18n::addressinput::COUNTRY:
- return kCountryField;
- default:
- NOTREACHED();
- return "";
- }
-}
-
// Serializes the AddressUiComponent a map from string to base::Value().
base::Value::Dict AddressUiComponentAsValueMap(
- const autofill::ExtendedAddressUiComponent& address_ui_component) {
+ const autofill::AutofillAddressUIComponent& address_ui_component) {
base::Value::Dict info;
info.Set(kFieldNameKey, address_ui_component.name);
- info.Set(kFieldTypeKey,
- GetStringFromAddressField(address_ui_component.field));
+ info.Set(kFieldTypeKey, FieldTypeToStringPiece(address_ui_component.field));
info.Set(kFieldLengthKey,
address_ui_component.length_hint ==
- i18n::addressinput::AddressUiComponent::HINT_LONG);
+ autofill::AutofillAddressUIComponent::HINT_LONG);
info.Set(kFieldRequired, address_ui_component.is_required);
return info;
}
-// Searches the |list| for the value at |index|. If this value is present in
-// any of the rest of the list, then the item (at |index|) is removed. The
-// comparison of phone number values is done on normalized versions of the phone
-// number values.
-void RemoveDuplicatePhoneNumberAtIndex(size_t index,
- const std::string& country_code,
- base::Value::List& list) {
- if (list.size() <= index) {
- NOTREACHED() << "List should have a value at index " << index;
- return;
- }
- const std::string& new_value = list[index].GetString();
-
- bool is_duplicate = false;
- std::string app_locale = g_browser_process->GetApplicationLocale();
- for (size_t i = 0; i < list.size() && !is_duplicate; ++i) {
- if (i == index)
- continue;
-
- const std::string& existing_value = list[i].GetString();
- is_duplicate = autofill::i18n::PhoneNumbersMatch(
- base::UTF8ToUTF16(new_value), base::UTF8ToUTF16(existing_value),
- country_code, app_locale);
- }
-
- if (is_duplicate)
- list.erase(list.begin() + index);
-}
-
autofill::AutofillManager* GetAutofillManager(
content::WebContents* web_contents) {
if (!web_contents) {
@@ -160,7 +98,7 @@ autofill::AutofillManager* GetAutofillManager(
->DriverForFrame(web_contents->GetPrimaryMainFrame());
if (!autofill_driver)
return nullptr;
- return autofill_driver->autofill_manager();
+ return &autofill_driver->GetAutofillManager();
}
autofill::AutofillProfile CreateNewAutofillProfile(
@@ -238,90 +176,33 @@ ExtensionFunction::ResponseAction AutofillPrivateSaveAddressFunction::Run() {
if (!existing_profile)
return RespondNow(Error(kErrorDataUnavailable));
}
- autofill::AutofillProfile profile =
- existing_profile
- ? *existing_profile
- : CreateNewAutofillProfile(personal_data, address->country_code);
-
- if (address->full_names) {
- std::string full_name;
- if (!address->full_names->empty())
- full_name = address->full_names->at(0);
- profile.SetInfoWithVerificationStatus(
- autofill::AutofillType(autofill::NAME_FULL),
- base::UTF8ToUTF16(full_name), g_browser_process->GetApplicationLocale(),
- kUserVerified);
- }
-
- if (address->honorific) {
- profile.SetRawInfoWithVerificationStatus(
- autofill::NAME_HONORIFIC_PREFIX, base::UTF8ToUTF16(*address->honorific),
- kUserVerified);
- }
-
- if (address->company_name) {
- profile.SetRawInfoWithVerificationStatus(
- autofill::COMPANY_NAME, base::UTF8ToUTF16(*address->company_name),
- kUserVerified);
- }
-
- if (address->address_lines) {
- profile.SetRawInfoWithVerificationStatus(
- autofill::ADDRESS_HOME_STREET_ADDRESS,
- base::UTF8ToUTF16(*address->address_lines), kUserVerified);
- }
-
- if (address->address_level1) {
- profile.SetRawInfoWithVerificationStatus(
- autofill::ADDRESS_HOME_STATE,
- base::UTF8ToUTF16(*address->address_level1), kUserVerified);
- }
-
- if (address->address_level2) {
- profile.SetRawInfoWithVerificationStatus(
- autofill::ADDRESS_HOME_CITY,
- base::UTF8ToUTF16(*address->address_level2), kUserVerified);
- }
-
- if (address->address_level3) {
- profile.SetRawInfoWithVerificationStatus(
- autofill::ADDRESS_HOME_DEPENDENT_LOCALITY,
- base::UTF8ToUTF16(*address->address_level3), kUserVerified);
- }
-
- if (address->postal_code) {
- profile.SetRawInfoWithVerificationStatus(
- autofill::ADDRESS_HOME_ZIP, base::UTF8ToUTF16(*address->postal_code),
- kUserVerified);
- }
-
- if (address->sorting_code) {
- profile.SetRawInfoWithVerificationStatus(
- autofill::ADDRESS_HOME_SORTING_CODE,
- base::UTF8ToUTF16(*address->sorting_code), kUserVerified);
- }
-
- if (address->country_code) {
- profile.SetRawInfoWithVerificationStatus(
- autofill::ADDRESS_HOME_COUNTRY,
- base::UTF8ToUTF16(*address->country_code), kUserVerified);
+ absl::optional<base::StringPiece> country_code;
+ if (auto it = std::find_if(
+ address->fields.begin(), address->fields.end(),
+ [](const auto& field) {
+ return field.type ==
+ autofill_private::ServerFieldType::kAddressHomeCountry;
+ });
+ it != address->fields.end()) {
+ country_code = it->value;
}
-
- if (address->phone_numbers) {
- std::string phone;
- if (!address->phone_numbers->empty())
- phone = address->phone_numbers->at(0);
- profile.SetRawInfoWithVerificationStatus(autofill::PHONE_HOME_WHOLE_NUMBER,
- base::UTF8ToUTF16(phone),
- kUserVerified);
- }
-
- if (address->email_addresses) {
- std::string email;
- if (!address->email_addresses->empty())
- email = address->email_addresses->at(0);
- profile.SetRawInfoWithVerificationStatus(
- autofill::EMAIL_ADDRESS, base::UTF8ToUTF16(email), kUserVerified);
+ autofill::AutofillProfile profile =
+ existing_profile ? *existing_profile
+ : CreateNewAutofillProfile(personal_data, country_code);
+
+ // TODO(crbug.com/1441904): Fields not visible for the autofill profile's
+ // country must be reset.
+ for (const api::autofill_private::AddressField& field : address->fields) {
+ if (field.type == autofill_private::ServerFieldType::kNameFull) {
+ profile.SetInfoWithVerificationStatus(
+ autofill::AutofillType(autofill::NAME_FULL),
+ base::UTF8ToUTF16(field.value),
+ g_browser_process->GetApplicationLocale(), kUserVerified);
+ } else {
+ profile.SetRawInfoWithVerificationStatus(
+ autofill::TypeNameToFieldType(autofill_private::ToString(field.type)),
+ base::UTF8ToUTF16(field.value), kUserVerified);
+ }
}
if (address->language_code)
@@ -369,7 +250,7 @@ AutofillPrivateGetAddressComponentsFunction::Run() {
api::autofill_private::GetAddressComponents::Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(parameters);
- std::vector<std::vector<autofill::ExtendedAddressUiComponent>> lines;
+ std::vector<std::vector<autofill::AutofillAddressUIComponent>> lines;
std::string language_code;
autofill::GetAddressComponents(
@@ -382,7 +263,7 @@ AutofillPrivateGetAddressComponentsFunction::Run() {
for (auto& line : lines) {
base::Value::List row_values;
- for (const autofill::ExtendedAddressUiComponent& component : line) {
+ for (const autofill::AutofillAddressUIComponent& component : line) {
row_values.Append(AddressUiComponentAsValueMap(component));
}
base::Value::Dict row;
@@ -508,7 +389,7 @@ ExtensionFunction::ResponseAction AutofillPrivateRemoveEntryFunction::Run() {
if (!personal_data || !personal_data->IsDataLoaded())
return RespondNow(Error(kErrorDataUnavailable));
- if (personal_data->GetIBANByGUID(parameters->guid)) {
+ if (personal_data->GetIbanByGUID(parameters->guid)) {
base::RecordAction(base::UserMetricsAction("AutofillIbanDeleted"));
}
@@ -518,30 +399,6 @@ ExtensionFunction::ResponseAction AutofillPrivateRemoveEntryFunction::Run() {
}
////////////////////////////////////////////////////////////////////////////////
-// AutofillPrivateValidatePhoneNumbersFunction
-
-ExtensionFunction::ResponseAction
-AutofillPrivateValidatePhoneNumbersFunction::Run() {
- absl::optional<api::autofill_private::ValidatePhoneNumbers::Params>
- parameters =
- api::autofill_private::ValidatePhoneNumbers::Params::Create(args());
- EXTENSION_FUNCTION_VALIDATE(parameters);
-
- api::autofill_private::ValidatePhoneParams& params = parameters->params;
-
- // Extract the phone numbers into a base::Value::List.
- base::Value::List phone_numbers;
- for (auto phone_number : params.phone_numbers) {
- phone_numbers.Append(phone_number);
- }
-
- RemoveDuplicatePhoneNumberAtIndex(params.index_of_new_number,
- params.country_code, phone_numbers);
-
- return RespondNow(WithArguments(std::move(phone_numbers)));
-}
-
-////////////////////////////////////////////////////////////////////////////////
// AutofillPrivateMaskCreditCardFunction
ExtensionFunction::ResponseAction AutofillPrivateMaskCreditCardFunction::Run() {
@@ -594,13 +451,14 @@ AutofillPrivateMigrateCreditCardsFunction::Run() {
// FormDataImporter.
autofill::AutofillManager* autofill_manager =
GetAutofillManager(GetSenderWebContents());
- if (!autofill_manager || !autofill_manager->client())
+ if (!autofill_manager) {
return RespondNow(Error(kErrorDataUnavailable));
+ }
// Get the FormDataImporter from AutofillClient. FormDataImporter owns
// LocalCardMigrationManager.
autofill::FormDataImporter* form_data_importer =
- autofill_manager->client()->GetFormDataImporter();
+ autofill_manager->client().GetFormDataImporter();
if (!form_data_importer)
return RespondNow(Error(kErrorDataUnavailable));
@@ -681,16 +539,16 @@ ExtensionFunction::ResponseAction AutofillPrivateSaveIbanFunction::Run() {
// the Chrome payment settings page. Otherwise, leaving it blank creates a new
// IBAN.
std::string guid = iban_entry->guid ? *iban_entry->guid : "";
- const autofill::IBAN* existing_iban = nullptr;
+ const autofill::Iban* existing_iban = nullptr;
if (!guid.empty()) {
- existing_iban = personal_data->GetIBANByGUID(guid);
+ existing_iban = personal_data->GetIbanByGUID(guid);
if (!existing_iban)
return RespondNow(Error(kErrorDataUnavailable));
}
- autofill::IBAN iban =
+ autofill::Iban iban =
existing_iban
? *existing_iban
- : autofill::IBAN(base::Uuid::GenerateRandomV4().AsLowercaseString());
+ : autofill::Iban(base::Uuid::GenerateRandomV4().AsLowercaseString());
iban.SetRawInfo(autofill::IBAN_VALUE, base::UTF8ToUTF16(*iban_entry->value));
@@ -698,7 +556,7 @@ ExtensionFunction::ResponseAction AutofillPrivateSaveIbanFunction::Run() {
iban.set_nickname(base::UTF8ToUTF16(*iban_entry->nickname));
if (guid.empty()) {
- personal_data->AddIBAN(iban);
+ personal_data->AddIban(iban);
base::RecordAction(base::UserMetricsAction("AutofillIbanAdded"));
if (!iban.nickname().empty()) {
base::RecordAction(
@@ -708,7 +566,7 @@ ExtensionFunction::ResponseAction AutofillPrivateSaveIbanFunction::Run() {
}
if (existing_iban->Compare(iban) != 0) {
- personal_data->UpdateIBAN(iban);
+ personal_data->UpdateIban(iban);
base::RecordAction(base::UserMetricsAction("AutofillIbanEdited"));
// Record when nickname is updated.
if (existing_iban->nickname() != iban.nickname()) {
@@ -744,21 +602,7 @@ ExtensionFunction::ResponseAction AutofillPrivateIsValidIbanFunction::Run() {
api::autofill_private::IsValidIban::Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(parameters);
return RespondNow(WithArguments(
- autofill::IBAN::IsValid(base::UTF8ToUTF16(parameters->iban_value))));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// AutofillPrivateGetUpiIdListFunction
-
-ExtensionFunction::ResponseAction AutofillPrivateGetUpiIdListFunction::Run() {
- autofill::PersonalDataManager* personal_data =
- autofill::PersonalDataManagerFactory::GetForProfile(
- Profile::FromBrowserContext(browser_context()));
- DCHECK(personal_data && personal_data->IsDataLoaded());
-
- return RespondNow(
- ArgumentList(api::autofill_private::GetUpiIdList::Results::Create(
- personal_data->GetUpiIds())));
+ autofill::Iban::IsValid(base::UTF8ToUTF16(parameters->iban_value))));
}
////////////////////////////////////////////////////////////////////////////////
@@ -783,17 +627,16 @@ ExtensionFunction::ResponseAction AutofillPrivateAddVirtualCardFunction::Run() {
autofill::AutofillManager* autofill_manager =
GetAutofillManager(GetSenderWebContents());
- if (!autofill_manager || !autofill_manager->client() ||
- !autofill_manager->client()->GetFormDataImporter() ||
+ if (!autofill_manager || !autofill_manager->client().GetFormDataImporter() ||
!autofill_manager->client()
- ->GetFormDataImporter()
+ .GetFormDataImporter()
->GetVirtualCardEnrollmentManager()) {
return RespondNow(Error(kErrorDataUnavailable));
}
autofill::VirtualCardEnrollmentManager* virtual_card_enrollment_manager =
autofill_manager->client()
- ->GetFormDataImporter()
+ .GetFormDataImporter()
->GetVirtualCardEnrollmentManager();
virtual_card_enrollment_manager->InitVirtualCardEnroll(
@@ -824,17 +667,16 @@ AutofillPrivateRemoveVirtualCardFunction::Run() {
autofill::AutofillManager* autofill_manager =
GetAutofillManager(GetSenderWebContents());
- if (!autofill_manager || !autofill_manager->client() ||
- !autofill_manager->client()->GetFormDataImporter() ||
+ if (!autofill_manager || !autofill_manager->client().GetFormDataImporter() ||
!autofill_manager->client()
- ->GetFormDataImporter()
+ .GetFormDataImporter()
->GetVirtualCardEnrollmentManager()) {
return RespondNow(Error(kErrorDataUnavailable));
}
autofill::VirtualCardEnrollmentManager* virtual_card_enrollment_manager =
autofill_manager->client()
- ->GetFormDataImporter()
+ .GetFormDataImporter()
->GetVirtualCardEnrollmentManager();
virtual_card_enrollment_manager->Unenroll(
@@ -856,50 +698,75 @@ AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction::Run() {
return RespondNow(Error(kErrorDeviceAuthUnavailable));
}
- // If `device_authenticator` is not available, then don't do anything.
- scoped_refptr<device_reauth::DeviceAuthenticator> device_authenticator =
- client->GetDeviceAuthenticator();
- if (!device_authenticator) {
- return RespondNow(Error(kErrorDeviceAuthUnavailable));
- }
-
- // `device_authenticator` is a scoped_refptr, so we need to keep it alive
- // until the callback that uses it is complete.
- base::OnceClosure bind_device_authenticator =
- base::DoNothingWithBoundArgs(device_authenticator);
const std::u16string message =
l10n_util::GetStringUTF16(IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT);
+ // If `personal_data_manager` is not available or `IsDataLoaded` is false,
+ // then don't do anything.
+ autofill::PersonalDataManager* personal_data_manager =
+ client->GetPersonalDataManager();
+ if (!personal_data_manager || !personal_data_manager->IsDataLoaded()) {
+ return RespondNow(Error(kErrorDataUnavailable));
+ }
+
// We will be modifying the pref `kAutofillPaymentMethodsMandatoryReauth`
// asynchronously. The pref value directly correlates to the mandatory auth
// toggle.
- autofill_util::AuthenticateUser(
- device_authenticator, message,
+ // We are also logging the start of the auth flow and
+ // `!personal_data_manager->IsPaymentMethodsMandatoryReauthEnabled()` denotes
+ // if the user is either opting in or out.
+ base::RecordAction(base::UserMetricsAction(
+ "PaymentsUserAuthTriggeredForMandatoryAuthToggle"));
+ LogMandatoryReauthOptInOrOutUpdateEvent(
+ MandatoryReauthOptInOrOutSource::kSettingsPage,
+ /*opt_in=*/
+ !personal_data_manager->IsPaymentMethodsMandatoryReauthEnabled(),
+ MandatoryReauthAuthenticationFlowEvent::kFlowStarted);
+ client->GetOrCreatePaymentsMandatoryReauthManager()->AuthenticateWithMessage(
+ message,
base::BindOnce(
&AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction::
UpdateMandatoryAuthTogglePref,
- this)
- .Then(base::IgnoreArgs(std::move(bind_device_authenticator))));
- base::RecordAction(base::UserMetricsAction(
- "PaymentsUserAuthTriggeredForMandatoryAuthToggle"));
+ this));
+
return RespondNow(NoArguments());
#else
return RespondNow(Error(kErrorDeviceAuthUnavailable));
#endif // BUILDFLAG (IS_MAC) || BUILDFLAG(IS_WIN)
}
-// Update the Mandatory auth toggle pref after a successful user auth.
+// Update the Mandatory auth toggle pref and log whether the auth was successful
+// or not.
void AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction::
UpdateMandatoryAuthTogglePref(bool reauth_succeeded) {
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
- if (reauth_succeeded && browser_context()) {
- PrefService* prefs =
- Profile::FromBrowserContext(browser_context())->GetPrefs();
- autofill::prefs::SetPaymentMethodsMandatoryReauthEnabled(
- prefs, !prefs->GetBoolean(
- autofill::prefs::kAutofillPaymentMethodsMandatoryReauth));
+ content::WebContents* sender_web_contents = GetSenderWebContents();
+ if (!sender_web_contents) {
+ return;
+ }
+ autofill::ContentAutofillClient* client =
+ autofill::ContentAutofillClient::FromWebContents(sender_web_contents);
+ CHECK(client);
+ autofill::PersonalDataManager* personal_data_manager =
+ client->GetPersonalDataManager();
+ // This function is not called in incognito mode and therefore a
+ // PersonalDataManager should always exist.
+ CHECK(personal_data_manager);
+
+ // `opt_in` bool denotes whether the user is trying to opt in or out of the
+ // mandatory reauth feature. If the mandatory reauth toggle on the settings is
+ // currently enabled, then the `opt_in` bool will be false because the user is
+ // opting-out, otherwise the `opt_in` bool will be true.
+ const bool opt_in =
+ !personal_data_manager->IsPaymentMethodsMandatoryReauthEnabled();
+ LogMandatoryReauthOptInOrOutUpdateEvent(
+ MandatoryReauthOptInOrOutSource::kSettingsPage, opt_in,
+ reauth_succeeded ? MandatoryReauthAuthenticationFlowEvent::kFlowSucceeded
+ : MandatoryReauthAuthenticationFlowEvent::kFlowFailed);
+ if (reauth_succeeded) {
base::RecordAction(base::UserMetricsAction(
"PaymentsUserAuthSuccessfulForMandatoryAuthToggle"));
+ personal_data_manager->SetPaymentMethodsMandatoryReauthEnabled(opt_in);
}
#endif
}
@@ -924,44 +791,40 @@ AutofillPrivateAuthenticateUserToEditLocalCardFunction::Run() {
return RespondNow(Error(kErrorDataUnavailable));
}
if (personal_data_manager->IsPaymentMethodsMandatoryReauthEnabled()) {
- // If `device_authenticator` is not available, then don't do anything.
- scoped_refptr<device_reauth::DeviceAuthenticator> device_authenticator =
- client->GetDeviceAuthenticator();
- if (!device_authenticator) {
- return RespondNow(Error(kErrorDeviceAuthUnavailable));
- }
-
- // `device_authenticator` is a scoped_refptr, so we need to keep it alive
- // until the callback that uses it is complete.
- base::OnceClosure bind_device_authenticator =
- base::DoNothingWithBoundArgs(device_authenticator);
const std::u16string message = l10n_util::GetStringUTF16(
IDS_PAYMENTS_AUTOFILL_EDIT_CARD_MANDATORY_REAUTH_PROMPT);
base::RecordAction(base::UserMetricsAction(
"PaymentsUserAuthTriggeredToShowEditLocalCardDialog"));
+ LogMandatoryReauthSettingsPageEditCardEvent(
+ MandatoryReauthAuthenticationFlowEvent::kFlowStarted);
// Based on the result of the auth, we will be asynchronously returning if
// the user can edit the local card.
- autofill_util::AuthenticateUser(
- device_authenticator, message,
- base::BindOnce(&AutofillPrivateAuthenticateUserToEditLocalCardFunction::
- CanShowEditDialogForLocalCard,
- this)
- .Then(base::IgnoreArgs(std::move(bind_device_authenticator))));
-
- // Due to async nature of AuthenticateWithMessage() on device authenticator
- // we use the below check to make sure we have a `Respond` captured. If we
- // didn't have this check, then we would show the edit card dialog box even
- // before the user successfully completes the auth.
+ client->GetOrCreatePaymentsMandatoryReauthManager()
+ ->AuthenticateWithMessage(
+ message,
+ base::BindOnce(
+ &AutofillPrivateAuthenticateUserToEditLocalCardFunction::
+ CanShowEditDialogForLocalCard,
+ this));
+
+ // Due to async nature of AuthenticateWithMessage() on mandatory re-auth
+ // manager we use the below check to make sure we have a `Respond` captured.
+ // If we didn't have this check, then we would show the edit card dialog box
+ // even before the user successfully completes the auth.
return did_respond() ? AlreadyResponded() : RespondLater();
}
#endif
return RespondNow(WithArguments(true));
}
-// Return the auth result for showing the edit card for local card.
+// Return the auth result for showing the edit card dialog for local card. We
+// also log whether the auth was successful or not.
void AutofillPrivateAuthenticateUserToEditLocalCardFunction::
CanShowEditDialogForLocalCard(bool can_show) {
+ LogMandatoryReauthSettingsPageEditCardEvent(
+ can_show ? MandatoryReauthAuthenticationFlowEvent::kFlowSucceeded
+ : MandatoryReauthAuthenticationFlowEvent::kFlowFailed);
if (can_show) {
base::RecordAction(base::UserMetricsAction(
"PaymentsUserAuthSuccessfulToShowEditLocalCardDialog"));
@@ -969,4 +832,20 @@ void AutofillPrivateAuthenticateUserToEditLocalCardFunction::
Respond(WithArguments(can_show));
}
+////////////////////////////////////////////////////////////////////////////////
+// AutofillPrivateCheckIfDeviceAuthAvailableFunction
+
+ExtensionFunction::ResponseAction
+AutofillPrivateCheckIfDeviceAuthAvailableFunction::Run() {
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
+ autofill::ContentAutofillClient* client =
+ autofill::ContentAutofillClient::FromWebContents(GetSenderWebContents());
+ if (client) {
+ return RespondNow(WithArguments(
+ autofill::IsDeviceAuthAvailable(client->GetDeviceAuthenticator())));
+ }
+#endif // BUILDFLAG (IS_MAC) || BUILDFLAG(IS_WIN)
+ return RespondNow(Error(kErrorDeviceAuthUnavailable));
+}
+
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api.h b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api.h
index 8e067366973..73315366dee 100644
--- a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api.h
+++ b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api.h
@@ -129,23 +129,6 @@ class AutofillPrivateRemoveEntryFunction : public ExtensionFunction {
ResponseAction Run() override;
};
-class AutofillPrivateValidatePhoneNumbersFunction : public ExtensionFunction {
- public:
- AutofillPrivateValidatePhoneNumbersFunction() = default;
- AutofillPrivateValidatePhoneNumbersFunction(
- const AutofillPrivateValidatePhoneNumbersFunction&) = delete;
- AutofillPrivateValidatePhoneNumbersFunction& operator=(
- const AutofillPrivateValidatePhoneNumbersFunction&) = delete;
- DECLARE_EXTENSION_FUNCTION("autofillPrivate.validatePhoneNumbers",
- AUTOFILLPRIVATE_VALIDATEPHONENUMBERS)
-
- protected:
- ~AutofillPrivateValidatePhoneNumbersFunction() override = default;
-
- // ExtensionFunction overrides.
- ResponseAction Run() override;
-};
-
class AutofillPrivateMaskCreditCardFunction : public ExtensionFunction {
public:
AutofillPrivateMaskCreditCardFunction() = default;
@@ -286,23 +269,6 @@ class AutofillPrivateIsValidIbanFunction : public ExtensionFunction {
ResponseAction Run() override;
};
-class AutofillPrivateGetUpiIdListFunction : public ExtensionFunction {
- public:
- AutofillPrivateGetUpiIdListFunction() = default;
- AutofillPrivateGetUpiIdListFunction(
- const AutofillPrivateGetUpiIdListFunction&) = delete;
- AutofillPrivateGetUpiIdListFunction& operator=(
- const AutofillPrivateGetUpiIdListFunction&) = delete;
- DECLARE_EXTENSION_FUNCTION("autofillPrivate.getUpiIdList",
- AUTOFILLPRIVATE_GETUPIIDLIST)
-
- protected:
- ~AutofillPrivateGetUpiIdListFunction() override = default;
-
- // ExtensionFunction overrides.
- ResponseAction Run() override;
-};
-
class AutofillPrivateAddVirtualCardFunction : public ExtensionFunction {
public:
AutofillPrivateAddVirtualCardFunction() = default;
@@ -383,6 +349,24 @@ class AutofillPrivateAuthenticateUserToEditLocalCardFunction
void CanShowEditDialogForLocalCard(bool can_show);
};
+class AutofillPrivateCheckIfDeviceAuthAvailableFunction
+ : public ExtensionFunction {
+ public:
+ AutofillPrivateCheckIfDeviceAuthAvailableFunction() = default;
+ AutofillPrivateCheckIfDeviceAuthAvailableFunction(
+ const AutofillPrivateCheckIfDeviceAuthAvailableFunction&) = delete;
+ AutofillPrivateCheckIfDeviceAuthAvailableFunction& operator=(
+ const AutofillPrivateCheckIfDeviceAuthAvailableFunction&) = delete;
+ DECLARE_EXTENSION_FUNCTION("autofillPrivate.checkIfDeviceAuthAvailable",
+ AUTOFILLPRIVATE_CHECKIFDEVICEAUTHAVAILABLE)
+
+ protected:
+ ~AutofillPrivateCheckIfDeviceAuthAvailableFunction() override = default;
+
+ // ExtensionFunction overrides.
+ ResponseAction Run() override;
+};
+
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_API_H_
diff --git a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api_unittest.cc b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api_unittest.cc
new file mode 100644
index 00000000000..58101af4364
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api_unittest.cc
@@ -0,0 +1,140 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/autofill_private/autofill_private_api.h"
+
+#include <vector>
+
+#include "chrome/browser/autofill/autofill_uitest_util.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
+#include "components/autofill/content/browser/test_autofill_client_injector.h"
+#include "components/autofill/content/browser/test_content_autofill_client.h"
+#include "components/autofill/core/browser/metrics/payments/mandatory_reauth_metrics.h"
+#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/device_reauth/mock_device_authenticator.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/test/browser_test.h"
+
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
+using autofill::autofill_metrics::MandatoryReauthAuthenticationFlowEvent;
+
+// There are 2 boolean params set in the test suites.
+// The first param can be retrieved via `IsFeatureTurnedOn()` which determines
+// if the toggle is currently turned on or off. The second param can be
+// retrieved via `IsUserAuthSuccessful()` which determines if the user auth was
+// successful or not.
+class MandatoryReauthSettingsPageMetricsTest
+ : public extensions::ExtensionApiTest,
+ public testing::WithParamInterface<std::tuple<bool, bool>> {
+ public:
+ MandatoryReauthSettingsPageMetricsTest() = default;
+ MandatoryReauthSettingsPageMetricsTest(
+ const MandatoryReauthSettingsPageMetricsTest&) = delete;
+ MandatoryReauthSettingsPageMetricsTest& operator=(
+ const MandatoryReauthSettingsPageMetricsTest&) = delete;
+ ~MandatoryReauthSettingsPageMetricsTest() override = default;
+
+ void SetUpOnMainThread() override {
+ ExtensionApiTest::SetUpOnMainThread();
+ autofill_client()->GetPersonalDataManager()->SetPrefService(
+ autofill_client()->GetPrefs());
+ autofill_client()
+ ->GetPersonalDataManager()
+ ->SetPaymentMethodsMandatoryReauthEnabled(IsFeatureTurnedOn());
+ }
+
+ bool IsFeatureTurnedOn() const { return std::get<0>(GetParam()); }
+
+ bool IsUserAuthSuccessful() const { return std::get<1>(GetParam()); }
+
+ protected:
+ bool RunAutofillSubtest(const std::string& subtest) {
+ autofill::WaitForPersonalDataManagerToBeLoaded(profile());
+
+ const std::string extension_url = "main.html?" + subtest;
+ return RunExtensionTest("autofill_private",
+ {.extension_url = extension_url.c_str()},
+ {.load_as_component = true});
+ }
+
+ autofill::TestContentAutofillClient* autofill_client() {
+ return test_autofill_client_injector_
+ [browser()->tab_strip_model()->GetActiveWebContents()];
+ }
+
+ private:
+ autofill::TestAutofillClientInjector<autofill::TestContentAutofillClient>
+ test_autofill_client_injector_;
+};
+
+// This tests the logging for mandatory reauth opt-in / opt-out flows when
+// triggered from the settings page.
+IN_PROC_BROWSER_TEST_P(MandatoryReauthSettingsPageMetricsTest,
+ SettingsPageMandatoryReauthToggleSwitching) {
+ base::HistogramTester histogram_tester;
+
+ ON_CALL(*static_cast<autofill::payments::MockMandatoryReauthManager*>(
+ autofill_client()->GetOrCreatePaymentsMandatoryReauthManager()),
+ AuthenticateWithMessage)
+ .WillByDefault(
+ testing::WithArg<1>([auth_success = IsUserAuthSuccessful()](
+ base::OnceCallback<void(bool)> callback) {
+ std::move(callback).Run(auth_success);
+ }));
+
+ RunAutofillSubtest("authenticateUserAndFlipMandatoryAuthToggle");
+
+ std::string histogram_name = base::StrCat(
+ {"Autofill.PaymentMethods.MandatoryReauth.OptChangeEvent.SettingsPage.",
+ IsFeatureTurnedOn() ? "OptOut" : "OptIn"});
+
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples(histogram_name),
+ testing::ElementsAre(
+ base::Bucket(MandatoryReauthAuthenticationFlowEvent::kFlowStarted, 1),
+ base::Bucket(
+ IsUserAuthSuccessful()
+ ? MandatoryReauthAuthenticationFlowEvent::kFlowSucceeded
+ : MandatoryReauthAuthenticationFlowEvent::kFlowFailed,
+ 1)));
+}
+
+IN_PROC_BROWSER_TEST_P(MandatoryReauthSettingsPageMetricsTest,
+ SettingsPageMandatoryReauthEditLocalCard) {
+ base::HistogramTester histogram_tester;
+
+ ON_CALL(*static_cast<autofill::payments::MockMandatoryReauthManager*>(
+ autofill_client()->GetOrCreatePaymentsMandatoryReauthManager()),
+ AuthenticateWithMessage)
+ .WillByDefault(
+ testing::WithArg<1>([auth_success = IsUserAuthSuccessful()](
+ base::OnceCallback<void(bool)> callback) {
+ std::move(callback).Run(auth_success);
+ }));
+
+ RunAutofillSubtest("authenticateUserToEditLocalCard");
+
+ std::string histogram_name =
+ "Autofill.PaymentMethods.MandatoryReauth.AuthEvent.SettingsPage.EditCard";
+
+ std::vector<base::Bucket> expected_histogram_buckets;
+ if (IsFeatureTurnedOn()) {
+ expected_histogram_buckets = {
+ base::Bucket(MandatoryReauthAuthenticationFlowEvent::kFlowStarted, 1),
+ base::Bucket(
+ IsUserAuthSuccessful()
+ ? MandatoryReauthAuthenticationFlowEvent::kFlowSucceeded
+ : MandatoryReauthAuthenticationFlowEvent::kFlowFailed,
+ 1)};
+ }
+
+ EXPECT_EQ(histogram_tester.GetAllSamples(histogram_name),
+ expected_histogram_buckets);
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+ MandatoryReauthSettingsPageMetricsTest,
+ testing::Combine(testing::Bool(), testing::Bool()));
+#endif // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
diff --git a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc
index cff47530b0d..8aaeda25f32 100644
--- a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc
@@ -6,8 +6,8 @@
#include <memory>
-#include "base/allocator/partition_allocator/pointers/raw_ptr.h"
#include "base/command_line.h"
+#include "base/memory/raw_ptr.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/values.h"
#include "build/build_config.h"
@@ -18,10 +18,10 @@
#include "components/autofill/content/browser/test_autofill_client_injector.h"
#include "components/autofill/content/browser/test_content_autofill_client.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/payments/test/mock_mandatory_reauth_manager.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/common/autofill_prefs.h"
-#include "components/device_reauth/mock_device_authenticator.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_utils.h"
@@ -45,6 +45,8 @@ class AutofillPrivateApiTest : public ExtensionApiTest {
void SetUpOnMainThread() override {
ExtensionApiTest::SetUpOnMainThread();
content::RunAllPendingInMessageLoop();
+ autofill_client()->GetPersonalDataManager()->SetPrefService(
+ autofill_client()->GetPrefs());
}
protected:
@@ -62,9 +64,6 @@ class AutofillPrivateApiTest : public ExtensionApiTest {
[browser()->tab_strip_model()->GetActiveWebContents()];
}
- std::unique_ptr<autofill::TestPersonalDataManager>
- test_personal_data_manager_;
-
private:
autofill::TestAutofillClientInjector<autofill::TestContentAutofillClient>
test_autofill_client_injector_;
@@ -86,10 +85,6 @@ IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, RemoveEntry) {
EXPECT_TRUE(RunAutofillSubtest("removeEntry")) << message_;
}
-IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, ValidatePhoneNumbers) {
- EXPECT_TRUE(RunAutofillSubtest("validatePhoneNumbers")) << message_;
-}
-
IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, AddAndUpdateAddress) {
EXPECT_TRUE(RunAutofillSubtest("addAndUpdateAddress")) << message_;
}
@@ -153,19 +148,20 @@ IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, isValidIban) {
IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest,
authenticateUserAndFlipMandatoryAuthToggle) {
base::UserActionTester user_action_tester;
- auto mock_device_authenticator = autofill_client()->GetDeviceAuthenticator();
+ auto* mock_mandatory_reauth_manager =
+ autofill_client()->GetOrCreatePaymentsMandatoryReauthManager();
- ON_CALL(*static_cast<device_reauth::MockDeviceAuthenticator*>(
- mock_device_authenticator.get()),
+ ON_CALL(*static_cast<autofill::payments::MockMandatoryReauthManager*>(
+ mock_mandatory_reauth_manager),
AuthenticateWithMessage)
.WillByDefault(
testing::WithArg<1>([](base::OnceCallback<void(bool)> callback) {
std::move(callback).Run(true);
}));
- EXPECT_CALL(*static_cast<device_reauth::MockDeviceAuthenticator*>(
- mock_device_authenticator.get()),
- AuthenticateWithMessage(testing::_, testing::_))
+ EXPECT_CALL(*static_cast<autofill::payments::MockMandatoryReauthManager*>(
+ mock_mandatory_reauth_manager),
+ AuthenticateWithMessage)
.Times(1);
EXPECT_TRUE(RunAutofillSubtest("authenticateUserAndFlipMandatoryAuthToggle"))
<< message_;
@@ -182,19 +178,20 @@ IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest,
autofill_client()
->GetPersonalDataManager()
->SetPaymentMethodsMandatoryReauthEnabled(true);
- auto mock_device_authenticator = autofill_client()->GetDeviceAuthenticator();
+ auto* mock_mandatory_reauth_manager =
+ autofill_client()->GetOrCreatePaymentsMandatoryReauthManager();
- ON_CALL(*static_cast<device_reauth::MockDeviceAuthenticator*>(
- mock_device_authenticator.get()),
+ ON_CALL(*static_cast<autofill::payments::MockMandatoryReauthManager*>(
+ mock_mandatory_reauth_manager),
AuthenticateWithMessage)
.WillByDefault(
testing::WithArg<1>([](base::OnceCallback<void(bool)> callback) {
std::move(callback).Run(true);
}));
- EXPECT_CALL(*static_cast<device_reauth::MockDeviceAuthenticator*>(
- mock_device_authenticator.get()),
- AuthenticateWithMessage(testing::_, testing::_))
+ EXPECT_CALL(*static_cast<autofill::payments::MockMandatoryReauthManager*>(
+ mock_mandatory_reauth_manager),
+ AuthenticateWithMessage)
.Times(1);
EXPECT_TRUE(RunAutofillSubtest("authenticateUserToEditLocalCard"))
<< message_;
diff --git a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc
index 9380de9af1b..44fd4d2a245 100644
--- a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc
+++ b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.cc
@@ -100,9 +100,4 @@ void AutofillPrivateEventRouter::BroadcastCurrentData() {
event_router_->BroadcastEvent(std::move(extension_event));
}
-AutofillPrivateEventRouter* AutofillPrivateEventRouter::Create(
- content::BrowserContext* context) {
- return new AutofillPrivateEventRouter(context);
-}
-
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h
index d8e01b94c14..7685c65d86a 100644
--- a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h
+++ b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h
@@ -27,16 +27,14 @@ class AutofillPrivateEventRouter :
public EventRouter::Observer,
public autofill::PersonalDataManagerObserver {
public:
- static AutofillPrivateEventRouter* Create(
- content::BrowserContext* browser_context);
+ // Uses AutofillPrivateEventRouterFactory instead.
+ explicit AutofillPrivateEventRouter(content::BrowserContext* context);
AutofillPrivateEventRouter(const AutofillPrivateEventRouter&) = delete;
AutofillPrivateEventRouter& operator=(const AutofillPrivateEventRouter&) =
delete;
~AutofillPrivateEventRouter() override = default;
protected:
- explicit AutofillPrivateEventRouter(content::BrowserContext* context);
-
// KeyedService overrides:
void Shutdown() override;
diff --git a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc
index 79d934c0ee2..674ecfec9b2 100644
--- a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc
+++ b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc
@@ -40,10 +40,11 @@ AutofillPrivateEventRouterFactory::AutofillPrivateEventRouterFactory()
DependsOn(autofill::PersonalDataManagerFactory::GetInstance());
}
-KeyedService* AutofillPrivateEventRouterFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+AutofillPrivateEventRouterFactory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const {
// TODO(1426498): pass router's dependencies directly instead of context.
- return AutofillPrivateEventRouter::Create(context);
+ return std::make_unique<AutofillPrivateEventRouter>(context);
}
bool AutofillPrivateEventRouterFactory::
diff --git a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h
index 45ba793c6ad..3068c41f1ed 100644
--- a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h
+++ b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h
@@ -41,7 +41,7 @@ class AutofillPrivateEventRouterFactory : public ProfileKeyedServiceFactory {
~AutofillPrivateEventRouterFactory() override = default;
// BrowserContextKeyedServiceFactory:
- KeyedService* BuildServiceInstanceFor(
+ std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
content::BrowserContext* profile) const override;
};
diff --git a/chromium/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chromium/chrome/browser/extensions/api/autofill_private/autofill_util.cc
index b06f9f98d19..a630230b9e7 100644
--- a/chromium/chrome/browser/extensions/api/autofill_private/autofill_util.cc
+++ b/chromium/chrome/browser/extensions/api/autofill_private/autofill_util.cc
@@ -93,26 +93,32 @@ autofill_private::AddressEntry ProfileToAddressEntry(
// Add all address fields to the entry.
address.guid = profile.guid();
- address.full_names = GetList(profile, autofill::NAME_FULL);
- address.honorific =
- GetStringFromProfile(profile, autofill::NAME_HONORIFIC_PREFIX);
- address.company_name = GetStringFromProfile(profile, autofill::COMPANY_NAME);
- address.address_lines =
- GetStringFromProfile(profile, autofill::ADDRESS_HOME_STREET_ADDRESS);
- address.address_level1 =
- GetStringFromProfile(profile, autofill::ADDRESS_HOME_STATE);
- address.address_level2 =
- GetStringFromProfile(profile, autofill::ADDRESS_HOME_CITY);
- address.address_level3 =
- GetStringFromProfile(profile, autofill::ADDRESS_HOME_DEPENDENT_LOCALITY);
- address.postal_code =
- GetStringFromProfile(profile, autofill::ADDRESS_HOME_ZIP);
- address.sorting_code =
- GetStringFromProfile(profile, autofill::ADDRESS_HOME_SORTING_CODE);
- address.country_code =
- GetStringFromProfile(profile, autofill::ADDRESS_HOME_COUNTRY);
- address.phone_numbers = GetList(profile, autofill::PHONE_HOME_WHOLE_NUMBER);
- address.email_addresses = GetList(profile, autofill::EMAIL_ADDRESS);
+
+ // TODO(crbug.com/1441904): provide all available fields instead of the hard
+ // coded list of fields.
+ std::vector<autofill::ServerFieldType> field_types = {
+ autofill::NAME_FULL,
+ autofill::NAME_HONORIFIC_PREFIX,
+ autofill::COMPANY_NAME,
+ autofill::ADDRESS_HOME_STREET_ADDRESS,
+ autofill::ADDRESS_HOME_STATE,
+ autofill::ADDRESS_HOME_CITY,
+ autofill::ADDRESS_HOME_DEPENDENT_LOCALITY,
+ autofill::ADDRESS_HOME_ZIP,
+ autofill::ADDRESS_HOME_SORTING_CODE,
+ autofill::ADDRESS_HOME_COUNTRY,
+ autofill::PHONE_HOME_WHOLE_NUMBER,
+ autofill::EMAIL_ADDRESS};
+
+ base::ranges::transform(
+ field_types, back_inserter(address.fields), [&profile](auto field_type) {
+ autofill_private::AddressField field;
+ field.type = autofill_private::ParseServerFieldType(
+ FieldTypeToStringPiece(field_type));
+ field.value = GetStringFromProfile(profile, field_type);
+ return field;
+ });
+
address.language_code = profile.language_code();
// Parse |label| so that it can be used to create address metadata.
@@ -200,9 +206,10 @@ autofill_private::CreditCardEntry CreditCardToCreditCardEntry(
autofill_private::CreditCardEntry card;
// Add all credit card fields to the entry.
- card.guid = credit_card.record_type() == autofill::CreditCard::LOCAL_CARD
- ? credit_card.guid()
- : credit_card.server_id();
+ card.guid =
+ credit_card.record_type() == autofill::CreditCard::RecordType::kLocalCard
+ ? credit_card.guid()
+ : credit_card.server_id();
card.name = base::UTF16ToUTF8(
credit_card.GetRawInfo(autofill::CREDIT_CARD_NAME_FULL));
card.card_number =
@@ -232,9 +239,9 @@ autofill_private::CreditCardEntry CreditCardToCreditCardEntry(
card.metadata->summary_label = base::UTF16ToUTF8(label_pieces.first);
card.metadata->summary_sublabel = base::UTF16ToUTF8(label_pieces.second);
card.metadata->is_local =
- credit_card.record_type() == autofill::CreditCard::LOCAL_CARD;
- card.metadata->is_cached =
- credit_card.record_type() == autofill::CreditCard::FULL_SERVER_CARD;
+ credit_card.record_type() == autofill::CreditCard::RecordType::kLocalCard;
+ card.metadata->is_cached = credit_card.record_type() ==
+ autofill::CreditCard::RecordType::kFullServerCard;
// IsValid() checks if both card number and expiration date are valid.
// IsServerCard() checks whether there is a duplicated server card in
// |personal_data|.
@@ -242,19 +249,19 @@ autofill_private::CreditCardEntry CreditCardToCreditCardEntry(
credit_card.IsValid() && !personal_data.IsServerCard(&credit_card);
card.metadata->is_virtual_card_enrollment_eligible =
credit_card.virtual_card_enrollment_state() ==
- autofill::CreditCard::VirtualCardEnrollmentState::ENROLLED ||
+ autofill::CreditCard::VirtualCardEnrollmentState::kEnrolled ||
credit_card.virtual_card_enrollment_state() ==
autofill::CreditCard::VirtualCardEnrollmentState::
- UNENROLLED_AND_ELIGIBLE;
+ kUnenrolledAndEligible;
card.metadata->is_virtual_card_enrolled =
credit_card.virtual_card_enrollment_state() ==
- autofill::CreditCard::VirtualCardEnrollmentState::ENROLLED;
+ autofill::CreditCard::VirtualCardEnrollmentState::kEnrolled;
return card;
}
autofill_private::IbanEntry IbanToIbanEntry(
- const autofill::IBAN& iban,
+ const autofill::Iban& iban,
const autofill::PersonalDataManager& personal_data) {
autofill_private::IbanEntry iban_entry;
@@ -326,8 +333,9 @@ CreditCardEntryList GenerateCreditCardList(
IbanEntryList GenerateIbanList(
const autofill::PersonalDataManager& personal_data) {
IbanEntryList list;
- for (const autofill::IBAN* iban : personal_data.GetLocalIBANs())
+ for (const autofill::Iban* iban : personal_data.GetLocalIbans()) {
list.push_back(IbanToIbanEntry(*iban, personal_data));
+ }
return list;
}
@@ -343,7 +351,7 @@ absl::optional<api::autofill_private::AccountInfo> GetAccountInfo(
api::autofill_private::AccountInfo api_account;
api_account.email = account->email;
api_account.is_sync_enabled_for_autofill_profiles =
- personal_data.IsSyncEnabledFor(syncer::UserSelectableType::kAutofill);
+ personal_data.IsSyncFeatureEnabledForAutofill();
api_account.is_eligible_for_address_account_storage =
personal_data.IsEligibleForAddressAccountStorage();
return std::move(api_account);
diff --git a/chromium/chrome/browser/extensions/api/automation/automation_apitest.cc b/chromium/chrome/browser/extensions/api/automation/automation_apitest.cc
index 61db738439f..e7c8aa0b93d 100644
--- a/chromium/chrome/browser/extensions/api/automation/automation_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -49,6 +49,7 @@
#include "ash/public/cpp/accelerators.h"
#include "ash/public/cpp/test/shell_test_api.h"
#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/screen.h"
#include "ui/display/test/display_manager_test_api.h" // nogncheck
@@ -56,13 +57,20 @@
namespace extensions {
-namespace {
-static const char kDomain[] = "a.com";
-static const char kSitesDir[] = "automation/sites";
-static const char kGotTree[] = "got_tree";
-} // anonymous namespace
-
class AutomationApiTest : public ExtensionApiTest {
+ public:
+ void SetUpOnMainThread() override {
+ ExtensionApiTest::SetUpOnMainThread();
+ host_resolver()->AddRule("*", "127.0.0.1");
+ }
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ extensions::ExtensionApiTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitchASCII(
+ extensions::switches::kAllowlistedExtensionID,
+ "ddchlicdkolnonkihahngkmmmjnjlkkf");
+ }
+
protected:
GURL GetURLForPath(const std::string& host, const std::string& path) {
std::string port = base::NumberToString(embedded_test_server()->port());
@@ -75,6 +83,7 @@ class AutomationApiTest : public ExtensionApiTest {
}
void StartEmbeddedTestServer() {
+ static const char kSitesDir[] = "automation/sites";
base::FilePath test_data;
ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data));
embedded_test_server()->ServeFilesFromDirectory(
@@ -82,19 +91,6 @@ class AutomationApiTest : public ExtensionApiTest {
ASSERT_TRUE(ExtensionApiTest::StartEmbeddedTestServer());
}
- public:
- void SetUpOnMainThread() override {
- ExtensionApiTest::SetUpOnMainThread();
- host_resolver()->AddRule("*", "127.0.0.1");
- }
-
- void SetUpCommandLine(base::CommandLine* command_line) override {
- extensions::ExtensionApiTest::SetUpCommandLine(command_line);
- command_line->AppendSwitchASCII(
- extensions::switches::kAllowlistedExtensionID,
- "ddchlicdkolnonkihahngkmmmjnjlkkf");
- }
-
base::test::ScopedFeatureList scoped_feature_list_;
};
@@ -108,6 +104,13 @@ class AutomationApiCanvasTest : public AutomationApiTest {
}
};
+#if defined(USE_AURA)
+
+namespace {
+static const char kDomain[] = "a.com";
+static const char kGotTree[] = "got_tree";
+} // anonymous namespace
+
IN_PROC_BROWSER_TEST_F(AutomationApiTest, TestRendererAccessibilityEnabled) {
StartEmbeddedTestServer();
const GURL url = GetURLForPath(kDomain, "/index.html");
@@ -170,19 +173,6 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, ImageLabels) {
EXPECT_EQ(expected_mode, accessibility_mode);
}
-// Flaky on Mac: crbug.com/1248445
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_GetTreeByTabId DISABLED_GetTreeByTabId
-#else
-#define MAYBE_GetTreeByTabId GetTreeByTabId
-#endif
-IN_PROC_BROWSER_TEST_F(AutomationApiTest, MAYBE_GetTreeByTabId) {
- StartEmbeddedTestServer();
- ASSERT_TRUE(RunExtensionTest("automation/tests/tabs",
- {.extension_url = "tab_id.html"}))
- << message_;
-}
-
IN_PROC_BROWSER_TEST_F(AutomationApiTest, Events) {
StartEmbeddedTestServer();
ASSERT_TRUE(RunExtensionTest("automation/tests/tabs",
@@ -247,50 +237,6 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, TableProperties) {
// Flaky on Mac and Windows: crbug.com/1235249
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
-#define MAYBE_TabsAutomationBooleanPermissions \
- DISABLED_TabsAutomationBooleanPermissions
-#else
-#define MAYBE_TabsAutomationBooleanPermissions TabsAutomationBooleanPermissions
-#endif
-IN_PROC_BROWSER_TEST_F(AutomationApiTest,
- MAYBE_TabsAutomationBooleanPermissions) {
- StartEmbeddedTestServer();
- ASSERT_TRUE(RunExtensionTest("automation/tests/tabs_automation_boolean",
- {.extension_url = "permissions.html"}))
- << message_;
-}
-
-// Flaky on Mac and Windows: crbug.com/1235249
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
-#define MAYBE_TabsAutomationBooleanActions \
- DISABLED_TabsAutomationBooleanActions
-#else
-#define MAYBE_TabsAutomationBooleanActions TabsAutomationBooleanActions
-#endif
-IN_PROC_BROWSER_TEST_F(AutomationApiTest, MAYBE_TabsAutomationBooleanActions) {
- StartEmbeddedTestServer();
- ASSERT_TRUE(RunExtensionTest("automation/tests/tabs_automation_boolean",
- {.extension_url = "actions.html"}))
- << message_;
-}
-
-// Flaky on Mac and Windows: crbug.com/1202710
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
-#define MAYBE_TabsAutomationHostsPermissions \
- DISABLED_TabsAutomationHostsPermissions
-#else
-#define MAYBE_TabsAutomationHostsPermissions TabsAutomationHostsPermissions
-#endif
-IN_PROC_BROWSER_TEST_F(AutomationApiTest,
- MAYBE_TabsAutomationHostsPermissions) {
- StartEmbeddedTestServer();
- ASSERT_TRUE(RunExtensionTest("automation/tests/tabs_automation_hosts",
- {.extension_url = "permissions.html"}))
- << message_;
-}
-
-// Flaky on Mac and Windows: crbug.com/1235249
-#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
#define MAYBE_CloseTab DISABLED_CloseTab
#else
#define MAYBE_CloseTab CloseTab
@@ -302,13 +248,6 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, MAYBE_CloseTab) {
<< message_;
}
-IN_PROC_BROWSER_TEST_F(AutomationApiTest, QuerySelector) {
- StartEmbeddedTestServer();
- ASSERT_TRUE(RunExtensionTest("automation/tests/tabs",
- {.extension_url = "queryselector.html"}))
- << message_;
-}
-
IN_PROC_BROWSER_TEST_F(AutomationApiTest, Find) {
StartEmbeddedTestServer();
ASSERT_TRUE(
@@ -418,12 +357,6 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, EnumValidity) {
<< message_;
}
-#if defined(USE_AURA)
-IN_PROC_BROWSER_TEST_F(AutomationApiTest, DesktopNotRequested) {
- ASSERT_TRUE(RunExtensionTest("automation/tests/tabs",
- {.extension_url = "desktop_not_requested.html"}))
- << message_;
-}
#endif // defined(USE_AURA)
#if !defined(USE_AURA)
@@ -704,6 +637,47 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, MAYBE_AddRemoveEventListeners) {
{.extension_url = "add_remove_event_listeners.html"}))
<< message_;
}
+
+class AutomationApiTestWithMockedSourceRenderer
+ : public AutomationApiTest,
+ public ui::AXActionHandlerObserver {
+ protected:
+ // This method is used to intercept AXActions dispatched from extensions.
+ // Because `DispatchActionResult`, from the automation API, is only used in
+ // specific source renderers (e.g. arc++), we mock the behavior here so we can
+ // test that the behavior in the automation api works correctly.
+ void InterceptAXActions() {
+ ui::AXActionHandlerRegistry* registry =
+ ui::AXActionHandlerRegistry ::GetInstance();
+ ASSERT_TRUE(registry);
+ registry->AddObserver(this);
+ }
+
+ private:
+ // ui::AXActionHandlerObserver :
+ void PerformAction(const ui::AXActionData& action_data) override {
+ extensions::AutomationEventRouter* router =
+ extensions::AutomationEventRouter::GetInstance();
+ ASSERT_TRUE(router);
+ EXPECT_EQ(action_data.action, ax::mojom::Action::kScrollBackward);
+ router->DispatchActionResult(action_data, /*result=*/true);
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(AutomationApiTestWithMockedSourceRenderer,
+ ActionResult) {
+ StartEmbeddedTestServer();
+
+ // Intercept AXActions for this test in order to test the behavior of
+ // DispatchActionResult. Here, we mock the action logic to always return true
+ // to return to the extension test that the action was handled and that the
+ // result is true. This will make sure that the passing of messages between
+ // processes is correct.
+ InterceptAXActions();
+ ASSERT_TRUE(RunExtensionTest("automation/tests/desktop",
+ {.extension_url = "action_result.html"}))
+ << message_;
+}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS)
diff --git a/chromium/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc b/chromium/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc
index 1b18b129b2e..1190aa6f7b3 100644
--- a/chromium/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc
+++ b/chromium/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc
@@ -20,6 +20,7 @@
#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/automation.h"
#include "extensions/common/permissions/permissions_data.h"
+#include "ui/accessibility/ax_tree_id.h"
#if defined(USE_AURA)
#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
diff --git a/chromium/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest_chromeos.cc b/chromium/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest_chromeos.cc
index 576e97007ce..bbcf1379af1 100644
--- a/chromium/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest_chromeos.cc
+++ b/chromium/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest_chromeos.cc
@@ -68,7 +68,8 @@ class BluetoothLowEnergyApiTestChromeOs : public PlatformAppBrowserTest {
ash::KioskAppManager* manager() const { return ash::KioskAppManager::Get(); }
- raw_ptr<ash::FakeChromeUserManager, ExperimentalAsh> fake_user_manager_;
+ raw_ptr<ash::FakeChromeUserManager, DanglingUntriaged | ExperimentalAsh>
+ fake_user_manager_;
std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
ash::ScopedCrosSettingsTestHelper settings_helper_;
diff --git a/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc b/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
index c6f74309f73..3b7a1df74d6 100644
--- a/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
+++ b/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
@@ -284,10 +284,8 @@ void BookmarkEventRouter::BookmarkNodeRemoved(
void BookmarkEventRouter::BookmarkAllUserNodesRemoved(
BookmarkModel* model,
const std::set<GURL>& removed_urls) {
- NOTREACHED();
- // TODO(shashishekhar) Currently this notification is only used on Android,
- // which does not support extensions. If Desktop needs to support this, add
- // a new event to the extensions api.
+ // TODO(crbug.com/1468324): This used to be used only on Android, but that's
+ // no longer the case. We need to implement a new event to handle this.
}
void BookmarkEventRouter::BookmarkNodeChanged(BookmarkModel* model,
diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc b/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc
index 0ded9284474..9fb90a0b518 100644
--- a/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc
+++ b/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc
@@ -124,8 +124,9 @@ void BrailleControllerImpl::WriteDots(const std::vector<uint8_t>& cells,
unsigned int row_limit = std::min(rows, cells_rows);
unsigned int col_limit = std::min(columns, cells_cols);
for (unsigned int row = 0; row < row_limit; row++) {
- for (unsigned int col = 0; col < col_limit; col++) {
- sized_cells[row * columns + col] = cells[row * cells_cols + col];
+ for (unsigned int col = 0;
+ col < col_limit && (row * columns + col) < cells.size(); col++) {
+ sized_cells[row * columns + col] = cells[row * columns + col];
}
}
diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_api.cc b/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_api.cc
index 31034fa1f0d..202e006b80a 100644
--- a/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_api.cc
@@ -171,9 +171,6 @@ ExtensionFunction::ResponseAction
BrailleDisplayPrivateWriteDotsFunction::Run() {
params_ = WriteDots::Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(params_);
- EXTENSION_FUNCTION_VALIDATE(
- params_->cells.size() >=
- static_cast<size_t>(params_->columns * params_->rows));
bool did_post_task = content::GetIOThreadTaskRunner({})->PostTaskAndReply(
FROM_HERE,
diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc b/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
index c447af6d75e..262764c9880 100644
--- a/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc
@@ -141,7 +141,8 @@ class MockBrlapiConnection : public BrlapiConnection {
}
}
- raw_ptr<MockBrlapiConnectionData, ExperimentalAsh> data_;
+ raw_ptr<MockBrlapiConnectionData, LeakedDanglingUntriaged | ExperimentalAsh>
+ data_;
OnDataReadyCallback on_data_ready_;
};
@@ -189,16 +190,59 @@ IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest, WriteDots) {
ASSERT_TRUE(RunExtensionTest("braille_display_private/write_dots", {},
{.load_as_component = true}))
<< message_;
- ASSERT_EQ(3U, connection_data_.written_content.size());
- const std::string expected_content(
- connection_data_.display_columns * connection_data_.display_rows, '\0');
- for (size_t i = 0; i < connection_data_.written_content.size(); ++i) {
- ASSERT_EQ(std::string(connection_data_.display_columns *
- connection_data_.display_rows,
- static_cast<char>(i)),
- connection_data_.written_content[i])
- << "String " << i << " doesn't match";
- }
+ ASSERT_EQ(4U, connection_data_.written_content.size());
+
+ // testWriteEmptyCells.
+ EXPECT_EQ(std::string(11, 0), connection_data_.written_content[0]);
+
+ // testWriteOversizedCells.
+ EXPECT_EQ(std::string(11, 1), connection_data_.written_content[1]);
+ EXPECT_EQ(std::string(11, 2), connection_data_.written_content[2]);
+
+ // testWriteUndersizedCellsNoCrash.
+ EXPECT_EQ(std::string(9, 3) + std::string(2, 0),
+ connection_data_.written_content[3]);
+}
+
+IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest, WriteDotsMultiLine) {
+ connection_data_.display_columns = 20;
+ connection_data_.display_rows = 7;
+ connection_data_.cell_size = 6;
+ ASSERT_TRUE(RunExtensionTest("braille_display_private/write_dots_multi_line",
+ {}, {.load_as_component = true}))
+ << message_;
+ ASSERT_EQ(6U, connection_data_.written_content.size());
+
+ // testWriteEmptyCells.
+ EXPECT_EQ(std::string(140, 0), connection_data_.written_content[0]);
+ EXPECT_EQ(std::string(140, 0), connection_data_.written_content[1]);
+ EXPECT_EQ(std::string(140, 0), connection_data_.written_content[2]);
+
+ // testWriteOversizedCells.
+
+ // The test passes a grid of cells 19x9 on a display of 20x7. (cols x rows).
+ // Thus, the last two rows get truncated, and the last column is unfilled
+ // (0s).
+ std::string grid;
+ grid += std::string(19, 1) + std::string(1, 0);
+ grid += std::string(19, 1) + std::string(1, 0);
+ grid += std::string(19, 1) + std::string(1, 0);
+ grid += std::string(19, 1) + std::string(1, 0);
+ grid += std::string(19, 1) + std::string(1, 0);
+ grid += std::string(19, 1) + std::string(1, 0);
+ grid += std::string(19, 1) + std::string(1, 0);
+ EXPECT_EQ(grid, connection_data_.written_content[3]);
+
+ // This one is 21x8, so only the last row is truncated.
+ EXPECT_EQ(std::string(140, 2), connection_data_.written_content[4]);
+
+ // testWriteUndersizedCellsNoCrash.
+
+ // 10x2.
+ std::string grid2 = std::string(10, 3) + std::string(10, 0) +
+ std::string(10, 3) + std::string(10, 0) +
+ std::string(100, 0);
+ EXPECT_EQ(grid2, connection_data_.written_content[5]);
}
IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest, KeyEvents) {
diff --git a/chromium/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc b/chromium/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
index b3e797e594e..4097a526437 100644
--- a/chromium/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
+++ b/chromium/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc
@@ -96,8 +96,9 @@ static_assert((kFilterableDataTypes &
uint64_t MaskForKey(const char* key) {
if (strcmp(key, extension_browsing_data_api_constants::kCacheKey) == 0)
return content::BrowsingDataRemover::DATA_TYPE_CACHE;
- if (strcmp(key, extension_browsing_data_api_constants::kCookiesKey) == 0)
+ if (strcmp(key, extension_browsing_data_api_constants::kCookiesKey) == 0) {
return content::BrowsingDataRemover::DATA_TYPE_COOKIES;
+ }
if (strcmp(key, extension_browsing_data_api_constants::kDownloadsKey) == 0)
return content::BrowsingDataRemover::DATA_TYPE_DOWNLOADS;
if (strcmp(key, extension_browsing_data_api_constants::kFileSystemsKey) == 0)
@@ -311,18 +312,16 @@ ExtensionFunction::ResponseAction BrowsingDataRemoverFunction::Run() {
if (origins) {
OriginParsingResult result = ParseOrigins(*origins);
- if (result.has_value()) {
- origins_ = std::move(*result);
- } else {
+ if (!result.has_value()) {
return RespondNow(std::move(result.error()));
}
+ origins_ = std::move(*result);
} else if (exclude_origins) {
OriginParsingResult result = ParseOrigins(*exclude_origins);
- if (result.has_value()) {
- origins_ = std::move(*result);
- } else {
+ if (!result.has_value()) {
return RespondNow(std::move(result.error()));
}
+ origins_ = std::move(*result);
}
mode_ = origins ? content::BrowsingDataFilterBuilder::Mode::kDelete
: content::BrowsingDataFilterBuilder::Mode::kPreserve;
diff --git a/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc b/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
index 9e4879b642d..08cd5f764d7 100644
--- a/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
@@ -289,7 +289,7 @@ class CertificateProviderApiTest : public extensions::ExtensionApiTest {
protected:
testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_;
- raw_ptr<chromeos::CertificateProviderService, DanglingUntriaged>
+ raw_ptr<chromeos::CertificateProviderService, AcrossTasksDanglingUntriaged>
cert_provider_service_ = nullptr;
policy::PolicyMap policy_map_;
@@ -490,9 +490,10 @@ class CertificateProviderApiMockedExtensionTest
return certificate_data;
}
- raw_ptr<content::WebContents, DanglingUntriaged> extension_contents_ =
- nullptr;
- raw_ptr<const extensions::Extension, DanglingUntriaged> extension_ = nullptr;
+ raw_ptr<content::WebContents, AcrossTasksDanglingUntriaged>
+ extension_contents_ = nullptr;
+ raw_ptr<const extensions::Extension, AcrossTasksDanglingUntriaged>
+ extension_ = nullptr;
base::FilePath extension_path_;
};
@@ -598,7 +599,8 @@ class CertificateProviderRequestPinTest : public CertificateProviderApiTest {
extension_ = LoadExtension(extension_path);
}
- raw_ptr<const extensions::Extension, DanglingUntriaged> extension_ = nullptr;
+ raw_ptr<const extensions::Extension, AcrossTasksDanglingUntriaged>
+ extension_ = nullptr;
std::unique_ptr<ExtensionTestMessageListener> command_request_listener_;
};
diff --git a/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc
index 76cfedc631b..4f11c0749d7 100644
--- a/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc
+++ b/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "base/check.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/memory/scoped_refptr.h"
@@ -36,8 +37,12 @@
#include "chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.h"
#include "chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.h"
#include "chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/instant_service.h"
#include "chrome/browser/search/instant_service_factory.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/webui/devtools_ui.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/url_constants.h"
@@ -63,6 +68,8 @@
#include "pdf/buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "services/network/public/mojom/fetch_api.mojom-shared.h"
+#include "ui/base/page_transition_types.h"
+#include "ui/base/window_open_disposition.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -84,18 +91,11 @@
#include "chrome/browser/extensions/clipboard_extension_helper_chromeos.h"
#endif
-#if BUILDFLAG(ENABLE_PDF)
-#include "chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.h"
-#include "components/pdf/browser/pdf_web_contents_helper.h"
-#endif
-
#if BUILDFLAG(ENABLE_PRINTING)
#include "chrome/browser/printing/printing_init.h"
#endif
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-// TODO(https://crbug.com/1060801): Here and elsewhere, possibly switch build
-// flag to #if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/supervised_user/supervised_user_extensions_delegate_impl.h"
#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
#endif
@@ -126,10 +126,6 @@ void ChromeExtensionsAPIClient::AttachWebContentsHelpers(
#if BUILDFLAG(ENABLE_PRINTING)
printing::InitializePrintingForWebContents(web_contents);
#endif
-#if BUILDFLAG(ENABLE_PDF)
- pdf::PDFWebContentsHelper::CreateForWebContentsWithClient(
- web_contents, std::make_unique<ChromePDFWebContentsHelperClient>());
-#endif
}
bool ChromeExtensionsAPIClient::ShouldHideResponseHeader(
@@ -193,17 +189,19 @@ void ChromeExtensionsAPIClient::NotifyWebRequestWithheld(
// Track down the ExtensionActionRunner and the extension. Since this is
// asynchronous, we could hit a null anywhere along the path.
- content::RenderFrameHost* rfh =
+ content::RenderFrameHost* render_frame_host =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
- if (!rfh)
+ if (!render_frame_host) {
return;
+ }
// We don't count subframes and prerendering blocked actions as yet, since
// there's no way to surface this to the user. Ignore these (which is also
// what we do for content scripts).
- if (!rfh->IsInPrimaryMainFrame())
+ if (!render_frame_host->IsInPrimaryMainFrame()) {
return;
+ }
content::WebContents* web_contents =
- content::WebContents::FromRenderFrameHost(rfh);
+ content::WebContents::FromRenderFrameHost(render_frame_host);
if (!web_contents)
return;
extensions::ExtensionActionRunner* runner =
@@ -229,7 +227,7 @@ void ChromeExtensionsAPIClient::NotifyWebRequestWithheld(
if (!extension->permissions_data()
->withheld_permissions()
.explicit_hosts()
- .MatchesURL(rfh->GetLastCommittedURL())) {
+ .MatchesURL(render_frame_host->GetLastCommittedURL())) {
return;
}
@@ -287,6 +285,20 @@ void ChromeExtensionsAPIClient::ClearActionCount(
}
}
+void ChromeExtensionsAPIClient::OpenFileUrl(
+ const GURL& file_url,
+ content::BrowserContext* browser_context) {
+ CHECK(file_url.is_valid());
+ CHECK(file_url.SchemeIsFile());
+ Profile* profile = Profile::FromBrowserContext(browser_context);
+ NavigateParams navigate_params(profile, file_url,
+ ui::PAGE_TRANSITION_FROM_API);
+ navigate_params.disposition = WindowOpenDisposition::CURRENT_TAB;
+ navigate_params.browser =
+ chrome::FindTabbedBrowser(profile, /*match_original_profiles=*/false);
+ Navigate(&navigate_params);
+}
+
AppViewGuestDelegate* ChromeExtensionsAPIClient::CreateAppViewGuestDelegate()
const {
return new ChromeAppViewGuestDelegate();
@@ -299,9 +311,8 @@ ChromeExtensionsAPIClient::CreateExtensionOptionsGuestDelegate(
}
std::unique_ptr<guest_view::GuestViewManagerDelegate>
-ChromeExtensionsAPIClient::CreateGuestViewManagerDelegate(
- content::BrowserContext* context) const {
- return std::make_unique<ChromeGuestViewManagerDelegate>(context);
+ChromeExtensionsAPIClient::CreateGuestViewManagerDelegate() const {
+ return std::make_unique<ChromeGuestViewManagerDelegate>();
}
std::unique_ptr<MimeHandlerViewGuestDelegate>
diff --git a/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.h b/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.h
index e13b68a8713..4d47b0b1e1e 100644
--- a/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.h
+++ b/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.h
@@ -49,12 +49,13 @@ class ChromeExtensionsAPIClient : public ExtensionsAPIClient {
bool clear_badge_text) override;
void ClearActionCount(content::BrowserContext* context,
const Extension& extension) override;
+ void OpenFileUrl(const GURL& file_url,
+ content::BrowserContext* browser_context) override;
AppViewGuestDelegate* CreateAppViewGuestDelegate() const override;
ExtensionOptionsGuestDelegate* CreateExtensionOptionsGuestDelegate(
ExtensionOptionsGuest* guest) const override;
std::unique_ptr<guest_view::GuestViewManagerDelegate>
- CreateGuestViewManagerDelegate(
- content::BrowserContext* context) const override;
+ CreateGuestViewManagerDelegate() const override;
std::unique_ptr<MimeHandlerViewGuestDelegate>
CreateMimeHandlerViewGuestDelegate(
MimeHandlerViewGuest* guest) const override;
diff --git a/chromium/chrome/browser/extensions/api/commands/command_service.cc b/chromium/chrome/browser/extensions/api/commands/command_service.cc
index f57c3d1897f..294b6ce11fa 100644
--- a/chromium/chrome/browser/extensions/api/commands/command_service.cc
+++ b/chromium/chrome/browser/extensions/api/commands/command_service.cc
@@ -29,7 +29,6 @@
#include "extensions/browser/extension_function_registry.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_system.h"
-#include "extensions/browser/notification_types.h"
#include "extensions/common/api/commands/commands_handler.h"
#include "extensions/common/command.h"
#include "extensions/common/feature_switch.h"
diff --git a/chromium/chrome/browser/extensions/api/content_settings/content_settings_api.cc b/chromium/chrome/browser/extensions/api/content_settings/content_settings_api.cc
index af7c3a8a01f..471ff11a732 100644
--- a/chromium/chrome/browser/extensions/api/content_settings/content_settings_api.cc
+++ b/chromium/chrome/browser/extensions/api/content_settings/content_settings_api.cc
@@ -33,8 +33,8 @@
#include "extensions/browser/api/content_settings/content_settings_helpers.h"
#include "extensions/browser/api/content_settings/content_settings_service.h"
#include "extensions/browser/api/content_settings/content_settings_store.h"
-#include "extensions/browser/extension_prefs_scope.h"
#include "extensions/browser/extension_util.h"
+#include "extensions/common/api/extension_types.h"
#include "extensions/common/constants.h"
#include "extensions/common/error_utils.h"
@@ -47,6 +47,8 @@ namespace pref_helpers = extensions::preference_helpers;
namespace {
+using extensions::api::types::ChromeSettingScope;
+
bool RemoveContentType(base::Value::List& args,
ContentSettingsType* content_type) {
if (args.empty() || !args[0].is_string())
@@ -89,11 +91,11 @@ ContentSettingsContentSettingClearFunction::Run() {
return RespondNow(Error(kUnknownErrorDoNotUse));
}
- ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
+ ChromeSettingScope scope = ChromeSettingScope::kRegular;
bool incognito = false;
if (params->details.scope ==
api::content_settings::Scope::kIncognitoSessionOnly) {
- scope = kExtensionPrefsScopeIncognitoSessionOnly;
+ scope = ChromeSettingScope::kIncognitoSessionOnly;
incognito = true;
}
@@ -148,7 +150,7 @@ ContentSettingsContentSettingGetFunction::Run() {
return RespondNow(Error(extension_misc::kIncognitoErrorMessage));
HostContentSettingsMap* map;
- content_settings::CookieSettings* cookie_settings;
+ scoped_refptr<content_settings::CookieSettings> cookie_settings;
Profile* profile = Profile::FromBrowserContext(browser_context());
if (incognito) {
if (!profile->HasPrimaryOTRProfile()) {
@@ -158,13 +160,11 @@ ContentSettingsContentSettingGetFunction::Run() {
}
map = HostContentSettingsMapFactory::GetForProfile(
profile->GetPrimaryOTRProfile(/*create_if_needed=*/true));
- cookie_settings =
- CookieSettingsFactory::GetForProfile(
- profile->GetPrimaryOTRProfile(/*create_if_needed=*/true))
- .get();
+ cookie_settings = CookieSettingsFactory::GetForProfile(
+ profile->GetPrimaryOTRProfile(/*create_if_needed=*/true));
} else {
map = HostContentSettingsMapFactory::GetForProfile(profile);
- cookie_settings = CookieSettingsFactory::GetForProfile(profile).get();
+ cookie_settings = CookieSettingsFactory::GetForProfile(profile);
}
// TODO(crbug.com/1386190): Consider whether the following check should
@@ -284,11 +284,11 @@ ContentSettingsContentSettingSetFunction::Run() {
return RespondNow(Error(kUnsupportedEmbeddedException));
}
- ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
+ ChromeSettingScope scope = ChromeSettingScope::kRegular;
bool incognito = false;
if (params->details.scope ==
api::content_settings::Scope::kIncognitoSessionOnly) {
- scope = kExtensionPrefsScopeIncognitoSessionOnly;
+ scope = ChromeSettingScope::kIncognitoSessionOnly;
incognito = true;
}
@@ -307,7 +307,7 @@ ContentSettingsContentSettingSetFunction::Run() {
return RespondNow(Error(kIncognitoContextError));
}
- if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
+ if (scope == ChromeSettingScope::kIncognitoSessionOnly &&
!Profile::FromBrowserContext(browser_context())->HasPrimaryOTRProfile()) {
return RespondNow(Error(extension_misc::kIncognitoSessionOnlyErrorMessage));
}
diff --git a/chromium/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc b/chromium/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
index 57dc41aa8f0..3a931619898 100644
--- a/chromium/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc
@@ -33,7 +33,6 @@
#include "components/keep_alive_registry/scoped_keep_alive.h"
#include "components/permissions/features.h"
#include "components/permissions/permission_manager.h"
-#include "components/permissions/permission_result.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/notification_service.h"
#include "content/public/common/content_switches.h"
@@ -245,7 +244,7 @@ class ExtensionContentSettingsApiTest : public ExtensionApiTest {
}
private:
- raw_ptr<Profile, DanglingUntriaged> profile_ = nullptr;
+ raw_ptr<Profile, AcrossTasksDanglingUntriaged> profile_ = nullptr;
std::unique_ptr<ScopedKeepAlive> keep_alive_;
std::unique_ptr<ScopedProfileKeepAlive> profile_keep_alive_;
};
diff --git a/chromium/chrome/browser/extensions/api/context_menus/extension_context_menu_browsertest.cc b/chromium/chrome/browser/extensions/api/context_menus/extension_context_menu_browsertest.cc
index 14a3e245196..cc29fa3e320 100644
--- a/chromium/chrome/browser/extensions/api/context_menus/extension_context_menu_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/context_menus/extension_context_menu_browsertest.cc
@@ -154,13 +154,13 @@ class ExtensionContextMenuBrowserTest
// This creates a test menu for a page with |page_url| and |link_url|, looks
// for an extension item with the given |label|, and returns true if the item
// was found.
- bool MenuHasItemWithLabel(const GURL& page_url,
+ bool MenuHasItemWithLabel(const GURL& frame_url,
const GURL& link_url,
- const GURL& frame_url,
+ bool is_subframe,
const std::string& label) {
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), page_url, link_url,
- frame_url));
+ TestRenderViewContextMenu::Create(GetWebContents(), frame_url, link_url,
+ is_subframe));
return MenuHasExtensionItemWithLabel(menu.get(), label);
}
@@ -329,8 +329,7 @@ class ExtensionContextMenuLazyTest
// Create and build our test context menu.
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), page_url, GURL(),
- GURL()));
+ TestRenderViewContextMenu::Create(GetWebContents(), page_url));
// Look for the extension item in the menu, and make sure it's |enabled|.
int command_id = ContextMenuMatcher::ConvertToExtensionsCustomCommandId(0);
@@ -368,8 +367,7 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, Simple) {
// Create and build our test context menu.
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), page_url, GURL(),
- GURL()));
+ TestRenderViewContextMenu::Create(GetWebContents(), page_url));
// Look for the extension item in the menu, and execute it.
int command_id = ContextMenuMatcher::ConvertToExtensionsCustomCommandId(0);
@@ -431,8 +429,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuPersistentTest, UpdateOnclick) {
// Create and build our test context menu.
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), page_url, GURL(),
- GURL()));
+ TestRenderViewContextMenu::Create(GetWebContents(), page_url));
// Look for the extension item in the menu, and execute it.
MenuItem::Id id(false, MenuItem::ExtensionKey(extension->id()));
@@ -448,8 +445,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuPersistentTest, UpdateOnclick) {
ASSERT_TRUE(listener_update2.WaitUntilSatisfied());
// Rebuild the context menu and click on the second extension item.
- menu = TestRenderViewContextMenu::Create(GetWebContents(), page_url, GURL(),
- GURL());
+ menu = TestRenderViewContextMenu::Create(GetWebContents(), page_url);
id.string_uid = "id2";
ASSERT_TRUE(FindCommandId(menu.get(), id, &command_id));
menu->ExecuteCommand(command_id, 0);
@@ -489,8 +485,7 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest,
// Create and build our test context menu.
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), page_url, GURL(),
- GURL()));
+ TestRenderViewContextMenu::Create(GetWebContents(), page_url));
VerifyRadioItemSelectionState(menu.get(), extension->id(), "radio1", true);
VerifyRadioItemSelectionState(menu.get(), extension->id(), "radio2", false);
@@ -538,8 +533,7 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest,
// Create and build our test context menu.
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), page_url, GURL(),
- GURL()));
+ TestRenderViewContextMenu::Create(GetWebContents(), page_url));
VerifyRadioItemSelectionState(menu.get(), extension->id(), "radio1", true);
VerifyRadioItemSelectionState(menu.get(), extension->id(), "radio2", false);
@@ -575,17 +569,17 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, Patterns) {
// Check that a document url that should match the items' patterns appears.
GURL google_url("http://www.google.com");
- ASSERT_TRUE(MenuHasItemWithLabel(google_url, GURL(), GURL(),
+ ASSERT_TRUE(MenuHasItemWithLabel(google_url, GURL(), false,
std::string("test_item1")));
- ASSERT_TRUE(MenuHasItemWithLabel(google_url, GURL(), GURL(),
+ ASSERT_TRUE(MenuHasItemWithLabel(google_url, GURL(), false,
std::string("test_item2")));
// Now check with a non-matching url.
GURL test_url("http://www.test.com");
- ASSERT_FALSE(MenuHasItemWithLabel(test_url, GURL(), GURL(),
- std::string("test_item1")));
- ASSERT_FALSE(MenuHasItemWithLabel(test_url, GURL(), GURL(),
- std::string("test_item2")));
+ ASSERT_FALSE(
+ MenuHasItemWithLabel(test_url, GURL(), false, std::string("test_item1")));
+ ASSERT_FALSE(
+ MenuHasItemWithLabel(test_url, GURL(), false, std::string("test_item2")));
}
// Tests registering an item with a very long title that should get truncated in
@@ -608,7 +602,7 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, LongTitle) {
// truncated.
GURL url("http://foo.com/");
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), url, GURL(), GURL()));
+ TestRenderViewContextMenu::Create(GetWebContents(), url));
std::u16string label;
ASSERT_TRUE(GetItemLabel(menu.get(), item->id(), &label));
@@ -654,7 +648,7 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, TopLevel) {
GURL url("http://foo.com/");
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), url, GURL(), GURL()));
+ TestRenderViewContextMenu::Create(GetWebContents(), url));
size_t index = 0;
MenuModel* model = nullptr;
@@ -742,7 +736,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuPersistentTest, Separators) {
GURL url("http://www.google.com/");
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), url, GURL(), GURL()));
+ TestRenderViewContextMenu::Create(GetWebContents(), url));
// The top-level item should be an "automagic parent" with the extension's
// name.
@@ -767,8 +761,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuPersistentTest, Separators) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), GURL(extension->GetResourceURL("test2.html"))));
EXPECT_TRUE(listener2.WaitUntilSatisfied());
- menu =
- TestRenderViewContextMenu::Create(GetWebContents(), url, GURL(), GURL());
+ menu = TestRenderViewContextMenu::Create(GetWebContents(), url);
ASSERT_TRUE(menu->GetMenuModelAndItemIndex(
ContextMenuMatcher::ConvertToExtensionsCustomCommandId(0),
&model,
@@ -791,14 +784,14 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, TargetURLs) {
// No target url - the item should not appear.
ASSERT_FALSE(
- MenuHasItemWithLabel(google_url, GURL(), GURL(), std::string("item1")));
+ MenuHasItemWithLabel(google_url, GURL(), false, std::string("item1")));
// A matching target url - the item should appear.
- ASSERT_TRUE(MenuHasItemWithLabel(google_url, google_url, GURL(),
+ ASSERT_TRUE(MenuHasItemWithLabel(google_url, google_url, false,
std::string("item1")));
// A non-matching target url - the item should not appear.
- ASSERT_FALSE(MenuHasItemWithLabel(google_url, non_google_url, GURL(),
+ ASSERT_FALSE(MenuHasItemWithLabel(google_url, non_google_url, false,
std::string("item1")));
}
@@ -832,13 +825,11 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuSWTest, IncognitoSplit) {
// Create and build our test context menu.
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), page_url, GURL(),
- GURL()));
+ TestRenderViewContextMenu::Create(GetWebContents(), page_url));
WebContents* incognito_web_contents =
browser_incognito->tab_strip_model()->GetActiveWebContents();
std::unique_ptr<TestRenderViewContextMenu> menu_incognito(
- TestRenderViewContextMenu::Create(incognito_web_contents, page_url,
- GURL(), GURL()));
+ TestRenderViewContextMenu::Create(incognito_web_contents, page_url));
// Look for the extension item in the menu, and execute it.
int command_id = ContextMenuMatcher::ConvertToExtensionsCustomCommandId(0);
@@ -864,18 +855,16 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, Frames) {
ASSERT_TRUE(listener.WaitUntilSatisfied());
GURL page_url("http://www.google.com");
- GURL no_frame_url;
- GURL frame_url("http://www.google.com");
-
- ASSERT_TRUE(MenuHasItemWithLabel(page_url, GURL(), no_frame_url,
- std::string("Page item")));
- ASSERT_FALSE(MenuHasItemWithLabel(page_url, GURL(), no_frame_url,
- std::string("Frame item")));
-
- ASSERT_TRUE(MenuHasItemWithLabel(page_url, GURL(), frame_url,
- std::string("Page item")));
- ASSERT_TRUE(MenuHasItemWithLabel(page_url, GURL(), frame_url,
- std::string("Frame item")));
+
+ ASSERT_TRUE(
+ MenuHasItemWithLabel(page_url, GURL(), false, std::string("Page item")));
+ ASSERT_FALSE(
+ MenuHasItemWithLabel(page_url, GURL(), false, std::string("Frame item")));
+
+ ASSERT_TRUE(
+ MenuHasItemWithLabel(page_url, GURL(), true, std::string("Page item")));
+ ASSERT_TRUE(
+ MenuHasItemWithLabel(page_url, GURL(), true, std::string("Frame item")));
}
// Tests that info.frameId is correctly set when the context menu is invoked.
@@ -932,18 +921,17 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, EventPage) {
host_helper.WaitForHostDestroyed();
// Test that menu items appear while the page is unloaded.
- ASSERT_TRUE(MenuHasItemWithLabel(
- about_blank, GURL(), GURL(), std::string("Item 1")));
- ASSERT_TRUE(MenuHasItemWithLabel(
- about_blank, GURL(), GURL(), std::string("Checkbox 1")));
+ ASSERT_TRUE(
+ MenuHasItemWithLabel(about_blank, GURL(), false, std::string("Item 1")));
+ ASSERT_TRUE(MenuHasItemWithLabel(about_blank, GURL(), false,
+ std::string("Checkbox 1")));
// Test that checked menu items retain their checkedness.
extensions::ExtensionHostTestHelper checkbox_checked(profile());
host_helper.RestrictToType(
extensions::mojom::ViewType::kExtensionBackgroundPage);
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), about_blank, GURL(),
- GURL()));
+ TestRenderViewContextMenu::Create(GetWebContents(), about_blank));
MenuItem::Id id(false, MenuItem::ExtensionKey(extension->id()));
id.string_uid = "checkbox1";
@@ -1003,8 +991,7 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, UpdateCheckboxes) {
// Create and build our test context menu.
std::unique_ptr<TestRenderViewContextMenu> menu(
- TestRenderViewContextMenu::Create(GetWebContents(), page_url, GURL(),
- GURL()));
+ TestRenderViewContextMenu::Create(GetWebContents(), page_url));
VerifyRadioItemSelectionState(menu.get(), extension->id(), "checkbox1",
false);
diff --git a/chromium/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc b/chromium/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
index 5f76f554f0f..f30d5c0283a 100644
--- a/chromium/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc
@@ -92,7 +92,7 @@ class CrashReportPrivateApiTest : public ExtensionApiTest {
const absl::optional<MockCrashEndpoint::Report>& last_report() {
return crash_endpoint_->last_report();
}
- raw_ptr<const Extension, ExperimentalAsh> extension_;
+ raw_ptr<const Extension, DanglingUntriaged | ExperimentalAsh> extension_;
std::unique_ptr<MockCrashEndpoint> crash_endpoint_;
std::unique_ptr<ScopedMockChromeJsErrorReportProcessor> processor_;
};
@@ -327,7 +327,7 @@ IN_PROC_BROWSER_TEST_P(CrashReportPrivateCalledFromSwaTest,
ASSERT_TRUE(embedded_test_server()->Started());
// Create and launch a test web app, opens in an app window.
GURL start_url = embedded_test_server()->GetURL("/test_app.html");
- auto web_app_info = std::make_unique<WebAppInstallInfo>();
+ auto web_app_info = std::make_unique<web_app::WebAppInstallInfo>();
web_app_info->start_url = start_url;
web_app::AppId app_id =
web_app::test::InstallWebApp(profile(), std::move(web_app_info));
diff --git a/chromium/chrome/browser/extensions/api/debugger/debugger_api.cc b/chromium/chrome/browser/extensions/api/debugger/debugger_api.cc
index ee4f1e0a2d5..09694b76bb9 100644
--- a/chromium/chrome/browser/extensions/api/debugger/debugger_api.cc
+++ b/chromium/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -61,6 +61,7 @@
#include "extensions/common/manifest_constants.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/switches.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/origin.h"
using content::DevToolsAgentHost;
@@ -163,15 +164,15 @@ bool ExtensionMayAttachToRenderFrameHost(
bool result = true;
render_frame_host->ForEachRenderFrameHostWithAction(
[&extension, extension_profile, error,
- &result](content::RenderFrameHost* rfh) {
- // If |rfh| is attached to an inner MimeHandlerViewGuest skip it.
- // This is done to fix crbug.com/1293856 because an extension cannot
- // inspect another extension.
- if (MimeHandlerViewGuest::FromRenderFrameHost(rfh)) {
+ &result](content::RenderFrameHost* render_frame_host) {
+ // If |render_frame_host| is attached to an inner MimeHandlerViewGuest
+ // skip it. This is done to fix crbug.com/1293856 because an extension
+ // cannot inspect another extension.
+ if (MimeHandlerViewGuest::FromRenderFrameHost(render_frame_host)) {
return content::RenderFrameHost::FrameIterationAction::kSkipChildren;
}
- if (rfh->GetWebUI()) {
+ if (render_frame_host->GetWebUI()) {
*error = debugger_api_constants::kRestrictedError;
result = false;
return content::RenderFrameHost::FrameIterationAction::kStop;
@@ -180,12 +181,12 @@ bool ExtensionMayAttachToRenderFrameHost(
// We check both the last committed URL and the SiteURL because this
// method may be called in the middle of a navigation where the SiteURL
// has been updated but navigation hasn't committed yet.
- if (!ExtensionMayAttachToURLOrInnerURL(extension, extension_profile,
- rfh->GetLastCommittedURL(),
- error) ||
+ if (!ExtensionMayAttachToURLOrInnerURL(
+ extension, extension_profile,
+ render_frame_host->GetLastCommittedURL(), error) ||
!ExtensionMayAttachToURLOrInnerURL(
extension, extension_profile,
- rfh->GetSiteInstance()->GetSiteURL(), error)) {
+ render_frame_host->GetSiteInstance()->GetSiteURL(), error)) {
result = false;
return content::RenderFrameHost::FrameIterationAction::kStop;
}
@@ -256,10 +257,12 @@ base::LazyInstance<AttachedClientHosts>::Leaky g_attached_client_hosts =
class ExtensionDevToolsClientHost : public content::DevToolsAgentHostClient,
public ExtensionRegistryObserver {
public:
- ExtensionDevToolsClientHost(Profile* profile,
- DevToolsAgentHost* agent_host,
- scoped_refptr<const Extension> extension,
- const Debuggee& debuggee);
+ ExtensionDevToolsClientHost(
+ Profile* profile,
+ DevToolsAgentHost* agent_host,
+ scoped_refptr<const Extension> extension,
+ absl::optional<WorkerId> extension_service_worker_id,
+ const Debuggee& debuggee);
ExtensionDevToolsClientHost(const ExtensionDevToolsClientHost&) = delete;
ExtensionDevToolsClientHost& operator=(const ExtensionDevToolsClientHost&) =
@@ -309,6 +312,10 @@ class ExtensionDevToolsClientHost : public content::DevToolsAgentHostClient,
raw_ptr<Profile> profile_;
scoped_refptr<DevToolsAgentHost> agent_host_;
scoped_refptr<const Extension> extension_;
+ // The WorkerId of the extension service worker that called attach() for this
+ // client host, if any.
+ const absl::optional<WorkerId> extension_service_worker_id_;
+
Debuggee debuggee_;
base::CallbackListSubscription on_app_terminating_subscription_;
int last_request_id_ = 0;
@@ -317,6 +324,11 @@ class ExtensionDevToolsClientHost : public content::DevToolsAgentHostClient,
api::debugger::DetachReason detach_reason_ =
api::debugger::DetachReason::kTargetClosed;
+ // A service worker keepalive used to keep the associated worker alive while
+ // this client is attached. Only used if `extension_service_worker_id_` has a
+ // value.
+ absl::optional<base::Uuid> service_worker_keepalive_;
+
// Listen to extension unloaded notification.
base::ScopedObservation<ExtensionRegistry, ExtensionRegistryObserver>
extension_registry_observation_{this};
@@ -326,10 +338,12 @@ ExtensionDevToolsClientHost::ExtensionDevToolsClientHost(
Profile* profile,
DevToolsAgentHost* agent_host,
scoped_refptr<const Extension> extension,
+ absl::optional<WorkerId> extension_service_worker_id,
const Debuggee& debuggee)
: profile_(profile),
agent_host_(agent_host),
- extension_(std::move(extension)) {
+ extension_(std::move(extension)),
+ extension_service_worker_id_(std::move(extension_service_worker_id)) {
CopyDebuggee(&debuggee_, debuggee);
g_attached_client_hosts.Get().insert(this);
@@ -366,12 +380,38 @@ bool ExtensionDevToolsClientHost::Attach() {
extension_id(), extension_->name(),
base::BindOnce(&ExtensionDevToolsClientHost::InfoBarDestroyed,
base::Unretained(this)));
+ if (extension_service_worker_id_) {
+ ProcessManager* process_manager = ProcessManager::Get(profile_);
+ CHECK(process_manager);
+ // The service worker should definitely be registered at this point.
+ CHECK(process_manager->HasServiceWorker(*extension_service_worker_id_));
+ service_worker_keepalive_ =
+ process_manager->IncrementServiceWorkerKeepaliveCount(
+ *extension_service_worker_id_,
+ content::ServiceWorkerExternalRequestTimeoutType::kDoesNotTimeout,
+ Activity::DEBUGGER, /*extra_data=*/std::string());
+ }
+
return true;
}
ExtensionDevToolsClientHost::~ExtensionDevToolsClientHost() {
ExtensionDevToolsInfoBarDelegate::NotifyExtensionDetached(extension_id());
g_attached_client_hosts.Get().erase(this);
+
+ // Decrement the associated worker keepalive, if any.
+ if (service_worker_keepalive_) {
+ CHECK(extension_service_worker_id_);
+ ProcessManager* process_manager = ProcessManager::Get(profile_);
+ CHECK(process_manager);
+ // The worker may have terminated for other reasons. Only decrement the
+ // keepalive if it's still around.
+ if (process_manager->HasServiceWorker(*extension_service_worker_id_)) {
+ process_manager->DecrementServiceWorkerKeepaliveCount(
+ *extension_service_worker_id_, *service_worker_keepalive_,
+ Activity::DEBUGGER, /*extra_data=*/std::string());
+ }
+ }
}
// DevToolsAgentHostClient implementation.
@@ -677,7 +717,7 @@ ExtensionFunction::ResponseAction DebuggerAttachFunction::Run() {
Profile* profile = Profile::FromBrowserContext(browser_context());
auto host = std::make_unique<ExtensionDevToolsClientHost>(
- profile, agent_host_.get(), extension(), debuggee_);
+ profile, agent_host_.get(), extension(), worker_id(), debuggee_);
if (!host->Attach()) {
return RespondNow(Error(debugger_api_constants::kRestrictedError));
diff --git a/chromium/chrome/browser/extensions/api/debugger/debugger_apitest.cc b/chromium/chrome/browser/extensions/api/debugger/debugger_apitest.cc
index e0062b9b410..46b52a820b7 100644
--- a/chromium/chrome/browser/extensions/api/debugger/debugger_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/debugger/debugger_apitest.cc
@@ -402,7 +402,9 @@ IN_PROC_BROWSER_TEST_F(DebuggerApiTest, InfoBar) {
EXPECT_EQ(1u, manager3->infobar_count());
// Closing tab should not affect anything.
- ASSERT_TRUE(another_browser->tab_strip_model()->CloseWebContentsAt(1, 0));
+ EXPECT_EQ(2, another_browser->tab_strip_model()->count());
+ another_browser->tab_strip_model()->CloseWebContentsAt(1, 0);
+ EXPECT_EQ(1, another_browser->tab_strip_model()->count());
manager3 = nullptr;
EXPECT_EQ(1u, manager1->infobar_count());
EXPECT_EQ(1u, manager2->infobar_count());
diff --git a/chromium/chrome/browser/extensions/api/debugger/extension_dev_tools_infobar_delegate.h b/chromium/chrome/browser/extensions/api/debugger/extension_dev_tools_infobar_delegate.h
index c00912f79d1..48fb3aad373 100644
--- a/chromium/chrome/browser/extensions/api/debugger/extension_dev_tools_infobar_delegate.h
+++ b/chromium/chrome/browser/extensions/api/debugger/extension_dev_tools_infobar_delegate.h
@@ -13,6 +13,7 @@
#include "base/memory/raw_ptr.h"
#include "base/timer/timer.h"
#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "extensions/common/extension_id.h"
class GlobalConfirmInfoBar;
@@ -57,7 +58,7 @@ class ExtensionDevToolsInfoBarDelegate : public ConfirmInfoBarDelegate {
base::CallbackListSubscription RegisterDestroyedCallback(
base::OnceClosure destroyed_callback);
- const std::string extension_id_;
+ const ExtensionId extension_id_;
const std::u16string extension_name_;
// infobar_ is set after attaching an extension and is deleted 5 seconds after
// detaching the extension. |infobar_| owns this object and is therefore
diff --git a/chromium/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc b/chromium/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc
index bc4971bc0f1..cdd579ef54a 100644
--- a/chromium/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc
@@ -158,7 +158,7 @@ class SetIconAPIPrerenderingTest : public SetIconAPITest {
private:
void SetUp() override {
- prerender_helper_.SetUp(embedded_test_server());
+ prerender_helper_.RegisterServerRequestMonitor(embedded_test_server());
ExtensionApiTest::SetUp();
}
diff --git a/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
index 26857eb016e..849d6bdb456 100644
--- a/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -154,10 +154,12 @@ base::Value::List VectorToList(const std::vector<T>& values) {
}
// Returns true if |window.scriptExecuted| is true for the given frame.
-bool WasFrameWithScriptLoaded(content::RenderFrameHost* rfh) {
- if (!rfh)
+bool WasFrameWithScriptLoaded(content::RenderFrameHost* render_frame_host) {
+ if (!render_frame_host) {
return false;
- return content::EvalJs(rfh, "!!window.scriptExecuted").ExtractBool();
+ }
+ return content::EvalJs(render_frame_host, "!!window.scriptExecuted")
+ .ExtractBool();
}
// Helper to wait for ruleset load in response to extension load.
@@ -2380,11 +2382,11 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest,
ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(
rules_1, "extension_1", {URLPattern::kAllUrlsPattern}));
- const std::string extension_id_1 = last_loaded_extension_id();
+ const ExtensionId extension_id_1 = last_loaded_extension_id();
ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(
rules_2, "extension_2", {URLPattern::kAllUrlsPattern}));
- const std::string extension_id_2 = last_loaded_extension_id();
+ const ExtensionId extension_id_2 = last_loaded_extension_id();
auto get_manifest_url = [](const ExtensionId& extension_id) {
return GURL(base::StringPrintf("%s://%s/manifest.json",
@@ -6649,7 +6651,7 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, FledgeAuctionScripts) {
navigator.joinAdInterestGroup({
name: 'cars',
owner: $1,
- biddingLogicUrl: $2,
+ biddingLogicURL: $2,
userBiddingSignals: [],
ads: [{
renderURL: 'https://example.com/render',
@@ -6682,7 +6684,7 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBrowserTest, FledgeAuctionScripts) {
(async function() {
let config = await navigator.runAdAuction({
seller: $1,
- decisionLogicUrl: $2,
+ decisionLogicURL: $2,
interestGroupBuyers: [$1],
});
document.querySelector('fencedframe').config =
@@ -6780,21 +6782,22 @@ class DeclarativeNetRequestBackForwardCacheBrowserTest
GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
// 1) Navigate to A.
- content::RenderFrameHost* rfh_a =
+ content::RenderFrameHost* render_frame_host_a =
ui_test_utils::NavigateToURL(browser(), url_a);
- auto delete_observer_rfh_a =
- std::make_unique<content::RenderFrameDeletedObserver>(rfh_a);
+ auto delete_observer_render_frame_host_a =
+ std::make_unique<content::RenderFrameDeletedObserver>(
+ render_frame_host_a);
// 2) Navigate to B.
- content::RenderFrameHost* rfh_b =
+ content::RenderFrameHost* render_frame_host_b =
ui_test_utils::NavigateToURL(browser(), url_b);
- // Ensure that |rfh_a| is in the cache.
- EXPECT_FALSE(delete_observer_rfh_a->deleted());
- EXPECT_NE(rfh_a, rfh_b);
- EXPECT_EQ(rfh_a->GetLifecycleState(),
+ // Ensure that |render_frame_host_a| is in the cache.
+ EXPECT_FALSE(delete_observer_render_frame_host_a->deleted());
+ EXPECT_NE(render_frame_host_a, render_frame_host_b);
+ EXPECT_EQ(render_frame_host_a->GetLifecycleState(),
content::RenderFrameHost::LifecycleState::kInBackForwardCache);
- return delete_observer_rfh_a;
+ return delete_observer_render_frame_host_a;
}
private:
@@ -6811,16 +6814,17 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBackForwardCacheBrowserTest,
rule.condition->url_filter = std::string("script.js");
ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules({rule}));
- auto bfcache_rfh_delete_observer = NavigateForBackForwardCache();
+ auto bfcache_render_frame_host_delete_observer =
+ NavigateForBackForwardCache();
const ExtensionId extension_id = last_loaded_extension_id();
// Add dynamic rule.
rule.condition->url_filter = std::string("dynamic.com");
ASSERT_NO_FATAL_FAILURE(AddDynamicRules(extension_id, {rule}));
- // Expect that |rfh_a| is destroyed as the cache would get cleared due to
- // addition of new rule.
- bfcache_rfh_delete_observer->WaitUntilDeleted();
+ // Expect that |render_frame_host_a| is destroyed as the cache would get
+ // cleared due to addition of new rule.
+ bfcache_render_frame_host_delete_observer->WaitUntilDeleted();
}
// Ensure that Back Forward is cleared on updating session rules.
@@ -6833,16 +6837,17 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBackForwardCacheBrowserTest,
rule.condition->url_filter = std::string("script.js");
ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules({rule}));
- auto bfcache_rfh_delete_observer = NavigateForBackForwardCache();
+ auto bfcache_render_frame_host_delete_observer =
+ NavigateForBackForwardCache();
const ExtensionId extension_id = last_loaded_extension_id();
// Add session-scoped rule to block requests to "session.example".
rule.condition->url_filter = std::string("session.example");
ASSERT_NO_FATAL_FAILURE(UpdateSessionRules(extension_id, {}, {rule}));
- // Expect that |rfh_a| is destroyed as the cache would get cleared due to
- // addition of new rule.
- bfcache_rfh_delete_observer->WaitUntilDeleted();
+ // Expect that |render_frame_host_a| is destroyed as the cache would get
+ // cleared due to addition of new rule.
+ bfcache_render_frame_host_delete_observer->WaitUntilDeleted();
}
// Ensure that Back Forward is cleared on updating enabled rulesets.
@@ -6858,16 +6863,17 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBackForwardCacheBrowserTest,
ASSERT_NO_FATAL_FAILURE(
LoadExtensionWithRulesets(rulesets, "test_extension", {} /* hosts */));
- auto bfcache_rfh_delete_observer = NavigateForBackForwardCache();
+ auto bfcache_render_frame_host_delete_observer =
+ NavigateForBackForwardCache();
const ExtensionId extension_id = last_loaded_extension_id();
// Enable |ruleset_2|.
ASSERT_NO_FATAL_FAILURE(
UpdateEnabledRulesets(last_loaded_extension_id(), {}, {"ruleset_2"}));
- // Expect that |rfh_a| is destroyed as the cache would get cleared due to
- // addition of new ruleset.
- bfcache_rfh_delete_observer->WaitUntilDeleted();
+ // Expect that |render_frame_host_a| is destroyed as the cache would get
+ // cleared due to addition of new ruleset.
+ bfcache_render_frame_host_delete_observer->WaitUntilDeleted();
}
// Ensure that Back Forward is cleared on new extension.
@@ -6875,16 +6881,17 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestBackForwardCacheBrowserTest,
BackForwardCacheClearedOnAddExtension) {
set_config_flags(ConfigFlag::kConfig_HasBackgroundScript);
- auto bfcache_rfh_delete_observer = NavigateForBackForwardCache();
+ auto bfcache_render_frame_host_delete_observer =
+ NavigateForBackForwardCache();
// Now block requests to script.js.
TestRule rule = CreateGenericRule();
rule.condition->url_filter = std::string("script.js");
ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules({rule}));
- // Expect that |rfh_a| is destroyed as the cache would get cleared due to
- // addition of new rule.
- bfcache_rfh_delete_observer->WaitUntilDeleted();
+ // Expect that |render_frame_host_a| is destroyed as the cache would get
+ // cleared due to addition of new rule.
+ bfcache_render_frame_host_delete_observer->WaitUntilDeleted();
}
INSTANTIATE_TEST_SUITE_P(All,
diff --git a/chromium/chrome/browser/extensions/api/declarative_net_request/ruleset_manager_unittest.cc b/chromium/chrome/browser/extensions/api/declarative_net_request/ruleset_manager_unittest.cc
index 7f08f2e1020..0d03680a22f 100644
--- a/chromium/chrome/browser/extensions/api/declarative_net_request/ruleset_manager_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/declarative_net_request/ruleset_manager_unittest.cc
@@ -184,7 +184,8 @@ TEST_P(RulesetManagerTest, MultipleRulesets) {
ASSERT_EQ(0u, manager()->GetMatcherCountForTest());
- std::string extension_id_one, extension_id_two;
+ ExtensionId extension_id_one;
+ ExtensionId extension_id_two;
size_t expected_matcher_count = 0;
// Add the required rulesets.
diff --git a/chromium/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chromium/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index 362165b3186..61b0f3825cf 100644
--- a/chromium/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -52,8 +52,12 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/browser/ui/extensions/extensions_dialogs.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model_factory.h"
+#include "chrome/browser/web_applications/extension_status_utils.h"
#include "chrome/common/extensions/api/developer_private.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/common/pref_names.h"
@@ -87,7 +91,6 @@
#include "extensions/browser/extension_util.h"
#include "extensions/browser/file_highlighter.h"
#include "extensions/browser/management_policy.h"
-#include "extensions/browser/notification_types.h"
#include "extensions/browser/path_util.h"
#include "extensions/browser/permissions_manager.h"
#include "extensions/browser/process_manager_factory.h"
@@ -159,12 +162,19 @@ const char kCannotRepairPolicyExtension[] =
"Cannot repair a policy-installed extension.";
const char kCannotChangeHostPermissions[] =
"Cannot change host permissions for the given extension.";
+const char kCannotSetPinnedWithoutAction[] =
+ "Cannot set pinned action state for an extension with no action.";
const char kInvalidHost[] = "Invalid host.";
const char kInvalidLazyBackgroundPageParameter[] =
"isServiceWorker can not be set for lazy background page based extensions.";
const char kInvalidRenderProcessId[] =
"render_process_id can be set to -1 for only lazy background page based or "
"service-worker based extensions.";
+const char kFailToUninstallEnterpriseOrComponentExtensions[] =
+ "Cannot uninstall the enterprise or component extensions in your list.";
+const char kFailToUninstallNoneExistentExtensions[] =
+ "Cannot uninstall non-existent extensions in your list.";
+const char kUserCancelledError[] = "User cancelled uninstall";
const char kUnpackedAppsFolder[] = "apps_target";
const char kManifestFile[] = "manifest.json";
@@ -361,18 +371,6 @@ void ProcessSitesForRuntimeHostPermissions(
}
}
-// Returns the current set of granted host permissions for the extension. Note
-// that permissions that are specified but withheld will not be returned.
-std::unique_ptr<const PermissionSet> GetExtensionGrantedPermissions(
- content::BrowserContext* context,
- const scoped_refptr<const Extension>& extension) {
- ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
- const PermissionsManager* manager = PermissionsManager::Get(context);
- return manager->HasWithheldHostPermissions(*extension)
- ? prefs->GetRuntimeGrantedPermissions(extension->id())
- : prefs->GetGrantedPermissions(extension->id());
-}
-
// Updates num_extensions counts in `site_groups` for `granted_hosts` from one
// extension.
void UpdateSiteGroupCountsForExtensionHosts(
@@ -509,7 +507,8 @@ std::unique_ptr<developer::ProfileInfo> DeveloperPrivateAPI::CreateProfileInfo(
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
supervised_user::SupervisedUserService* service =
SupervisedUserServiceFactory::GetForProfile(profile);
- info->is_child_account = service->AreExtensionsPermissionsEnabled();
+ info->is_child_account =
+ service && service->AreExtensionsPermissionsEnabled();
#else
info->is_child_account = false;
#endif
@@ -542,6 +541,7 @@ void BrowserContextKeyedAPIFactory<
DependsOn(EventRouterFactory::GetInstance());
DependsOn(ExtensionSystemFactory::GetInstance());
DependsOn(PermissionsManager::GetFactory());
+ DependsOn(ToolbarActionsModelFactory::GetInstance());
}
// static
@@ -569,6 +569,7 @@ DeveloperPrivateEventRouter::DeveloperPrivateEventRouter(Profile* profile)
extension_allowlist_observer_.Observe(
ExtensionSystem::Get(profile)->extension_service()->allowlist());
permissions_manager_observation_.Observe(PermissionsManager::Get(profile));
+ toolbar_actions_model_observation_.Observe(ToolbarActionsModel::Get(profile));
pref_change_registrar_.Init(profile->GetPrefs());
// The unretained is safe, since the PrefChangeRegistrar unregisters the
// callback on destruction.
@@ -637,6 +638,12 @@ void DeveloperPrivateEventRouter::OnErrorAdded(const ExtensionError* error) {
error->extension_id());
}
+void DeveloperPrivateEventRouter::OnExtensionConfigurationChanged(
+ const std::string& extension_id) {
+ BroadcastItemStateChanged(developer::EVENT_TYPE_CONFIGURATION_CHANGED,
+ extension_id);
+}
+
void DeveloperPrivateEventRouter::OnErrorsRemoved(
const std::set<std::string>& removed_ids) {
for (const std::string& id : removed_ids) {
@@ -748,6 +755,21 @@ void DeveloperPrivateEventRouter::OnExtensionPermissionsUpdated(
extension.id());
}
+void DeveloperPrivateEventRouter::OnToolbarPinnedActionsChanged() {
+ // Currently, only enabled extensions are considered since they are the only
+ // ones that have extension actions.
+ // TODO(crbug.com/1477884): Since pinned info is stored as a pref, include
+ // disabled extensions in this event as well.
+ const ExtensionSet& extensions =
+ ExtensionRegistry::Get(profile_)->enabled_extensions();
+ for (const auto& extension : extensions) {
+ if (ui_util::ShouldDisplayInExtensionSettings(*extension)) {
+ BroadcastItemStateChanged(developer::EVENT_TYPE_PINNED_ACTIONS_CHANGED,
+ extension->id());
+ }
+ }
+}
+
void DeveloperPrivateEventRouter::OnProfilePrefChanged() {
base::Value::List args;
args.Append(DeveloperPrivateAPI::CreateProfileInfo(profile_)->ToValue());
@@ -1162,6 +1184,26 @@ DeveloperPrivateUpdateExtensionConfigurationFunction::Run() {
ExtensionPrefs::Get(browser_context())
->SetBooleanPref(extension->id(), kPrefAcknowledgeSafetyCheckWarning,
*update.acknowledge_safety_check_warning);
+ DeveloperPrivateEventRouter* event_router =
+ DeveloperPrivateAPI::Get(browser_context())
+ ->developer_private_event_router();
+ if (event_router) {
+ event_router->OnExtensionConfigurationChanged(extension->id());
+ }
+ }
+ if (update.pinned_to_toolbar) {
+ ToolbarActionsModel* toolbar_actions_model = ToolbarActionsModel::Get(
+ Profile::FromBrowserContext(browser_context()));
+ if (!toolbar_actions_model->HasAction(extension->id())) {
+ return RespondNow(Error(kCannotSetPinnedWithoutAction));
+ }
+
+ bool is_action_pinned =
+ toolbar_actions_model->IsActionPinned(extension->id());
+ if (is_action_pinned != *update.pinned_to_toolbar) {
+ toolbar_actions_model->SetActionVisibility(extension->id(),
+ !is_action_pinned);
+ }
}
return RespondNow(NoArguments());
@@ -1635,7 +1677,6 @@ ExtensionFunction::ResponseAction DeveloperPrivateLoadDirectoryFunction::Run() {
if (directory_url.is_valid() &&
directory_url.type() != storage::kFileSystemTypeLocal &&
- directory_url.type() != storage::kFileSystemTypeRestrictedLocal &&
directory_url.type() != storage::kFileSystemTypeDragged) {
return LoadByFileSystemAPI(directory_url);
}
@@ -2006,11 +2047,14 @@ DeveloperPrivateOpenDevToolsFunction::Run() {
// NOTE(devlin): Even though the properties use "render_view_id", this
// actually refers to a render frame.
- content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
- properties.render_process_id, properties.render_view_id);
+ content::RenderFrameHost* render_frame_host =
+ content::RenderFrameHost::FromID(properties.render_process_id,
+ properties.render_view_id);
content::WebContents* web_contents =
- rfh ? content::WebContents::FromRenderFrameHost(rfh) : nullptr;
+ render_frame_host
+ ? content::WebContents::FromRenderFrameHost(render_frame_host)
+ : nullptr;
// It's possible that the render frame was closed since we last updated the
// links. Handle this gracefully.
if (!web_contents)
@@ -2410,23 +2454,19 @@ DeveloperPrivateGetUserAndExtensionSitesByEtldFunction::Run() {
std::vector<scoped_refptr<const Extension>> extensions_to_check;
ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
+ PermissionsManager* permissions_manager =
+ PermissionsManager::Get(browser_context());
// Note: we are only counting enabled extensions as the returned extension
// counts will reflect how many extensions can actually run on each site at
// the current moment.
for (const auto& extension : registry->enabled_extensions()) {
- // TODO(crbug.com/1331137): Some extensions can access certain sites even if
- // the user cannot modify their permissions. These also need to be added to
- // another list so the frontend knows that their site access cannot be
- // modified.
- PermissionsManager* manager = PermissionsManager::Get(browser_context());
- if (!ui_util::ShouldDisplayInExtensionSettings(*extension) ||
- !manager->CanAffectExtension(*extension)) {
+ if (!ui_util::ShouldDisplayInExtensionSettings(*extension)) {
continue;
}
std::unique_ptr<const PermissionSet> granted_permissions =
- GetExtensionGrantedPermissions(browser_context(), extension);
+ permissions_manager->GetExtensionGrantedPermissions(*extension);
std::vector<URLPattern> distinct_hosts =
ExtensionInfoGenerator::GetDistinctHosts(
granted_permissions->effective_hosts());
@@ -2445,7 +2485,7 @@ DeveloperPrivateGetUserAndExtensionSitesByEtldFunction::Run() {
// counts are accurate.
for (const auto& extension : extensions_to_check) {
std::unique_ptr<const PermissionSet> granted_permissions =
- GetExtensionGrantedPermissions(browser_context(), extension);
+ permissions_manager->GetExtensionGrantedPermissions(*extension);
UpdateSiteGroupCountsForExtensionHosts(
&site_groups, &match_subdomains_count,
granted_permissions->effective_hosts());
@@ -2492,20 +2532,22 @@ DeveloperPrivateGetMatchingExtensionsForSiteFunction::Run() {
if (parsed_site.Parse(params->site) != URLPattern::ParseResult::kSuccess)
return RespondNow(Error("Invalid site: " + params->site));
+ constexpr bool kIncludeApiPermissions = false;
+
std::vector<developer::MatchingExtensionInfo> matching_extensions;
URLPatternSet site_pattern({parsed_site});
- const ExtensionSet all_extensions =
- ExtensionRegistry::Get(browser_context())
- ->GenerateInstalledExtensionsSet(
- ExtensionRegistry::ENABLED | ExtensionRegistry::DISABLED |
- ExtensionRegistry::TERMINATED | ExtensionRegistry::BLOCKLISTED);
- for (const auto& extension : all_extensions) {
+ const ExtensionSet& enabled_extensions =
+ ExtensionRegistry::Get(browser_context())->enabled_extensions();
+ PermissionsManager* permissions_manager =
+ PermissionsManager::Get(browser_context());
+ for (const auto& extension : enabled_extensions) {
+ std::unique_ptr<const PermissionSet> granted_permissions =
+ permissions_manager->GetExtensionGrantedPermissions(*extension);
const URLPatternSet& extension_withheld_sites =
extension->permissions_data()->withheld_permissions().effective_hosts();
const URLPatternSet granted_intersection =
URLPatternSet::CreateIntersection(
- site_pattern,
- extension->permissions_data()->GetEffectiveHostPermissions(),
+ site_pattern, granted_permissions->effective_hosts(),
URLPatternSet::IntersectionBehavior::kDetailed);
const URLPatternSet withheld_intersection =
URLPatternSet::CreateIntersection(
@@ -2519,16 +2561,25 @@ DeveloperPrivateGetMatchingExtensionsForSiteFunction::Run() {
// have access to any sites that match `site_pattern`.
developer::HostAccess host_access = developer::HOST_ACCESS_ON_CLICK;
+ // TODO(crbug.com/1472899): Add a version of CanUserSelectSiteAccess to
+ // PermissionsManager which takes in a URLPattern.
+ bool can_request_all_sites =
+ granted_permissions->ShouldWarnAllHosts(kIncludeApiPermissions) ||
+ extension->permissions_data()
+ ->withheld_permissions()
+ .ShouldWarnAllHosts(kIncludeApiPermissions);
+
// If the extension has access to at least one site that matches
- // `site_pattern`, return ON_ALL_SITES or ON_SPECIFIC_SITES depending on
- // if the extension has any withheld sites.
+ // `site_pattern`, return ON_ALL_SITES if the extension can request all
+ // sites and has no withheld sites, or ON_SPECIFIC_SITES otherwise.
if (!granted_intersection.is_empty()) {
- host_access = extension_withheld_sites.is_empty()
+ host_access = can_request_all_sites && extension_withheld_sites.is_empty()
? developer::HOST_ACCESS_ON_ALL_SITES
: developer::HOST_ACCESS_ON_SPECIFIC_SITES;
}
developer::MatchingExtensionInfo matching_info;
+ matching_info.can_request_all_sites = can_request_all_sites;
matching_info.site_access = host_access;
matching_info.id = extension->id();
matching_extensions.push_back(std::move(matching_info));
@@ -2627,6 +2678,85 @@ void DeveloperPrivateUpdateSiteAccessFunction::OnSiteSettingsUpdated() {
Respond(NoArguments());
}
+DeveloperPrivateRemoveMultipleExtensionsFunction::
+ DeveloperPrivateRemoveMultipleExtensionsFunction() = default;
+DeveloperPrivateRemoveMultipleExtensionsFunction::
+ ~DeveloperPrivateRemoveMultipleExtensionsFunction() = default;
+
+ExtensionFunction::ResponseAction
+DeveloperPrivateRemoveMultipleExtensionsFunction::Run() {
+ absl::optional<developer::RemoveMultipleExtensions::Params> params =
+ developer::RemoveMultipleExtensions::Params::Create(args());
+ EXTENSION_FUNCTION_VALIDATE(params);
+ profile_ = Profile::FromBrowserContext(browser_context());
+ extension_ids_ = std::move(params->extension_ids);
+
+ // Verify the input extension list.
+ for (const auto& extension_id : extension_ids_) {
+ CHECK(profile_);
+ const Extension* current_extension =
+ ExtensionRegistry::Get(profile_)->GetExtensionById(
+ extension_id, ExtensionRegistry::EVERYTHING);
+ if (!current_extension) {
+ // Return early if the extension is a non-existent extension.
+ return RespondNow(Error(kFailToUninstallNoneExistentExtensions));
+ }
+ // If enterprise or component extensions are found, do nothing and respond
+ // with an error.
+ if (Manifest::IsComponentLocation(current_extension->location()) ||
+ Manifest::IsPolicyLocation(current_extension->location())) {
+ return RespondNow(Error(kFailToUninstallEnterpriseOrComponentExtensions));
+ }
+ }
+
+ if (accept_bubble_for_testing_.has_value()) {
+ if (*accept_bubble_for_testing_) {
+ OnDialogAccepted();
+ return AlreadyResponded();
+ }
+ return RespondNow(NoArguments());
+ }
+
+ Browser* browser = chrome::FindBrowserWithWebContents(GetSenderWebContents());
+ CHECK(browser);
+
+ ShowExtensionMultipleUninstallDialog(
+ browser->profile(), browser->window()->GetNativeWindow(), extension_ids_,
+ base::BindOnce(
+ &DeveloperPrivateRemoveMultipleExtensionsFunction::OnDialogAccepted,
+ this),
+ base::BindOnce(
+ &DeveloperPrivateRemoveMultipleExtensionsFunction::OnDialogCancelled,
+ this));
+ return RespondLater();
+}
+
+void DeveloperPrivateRemoveMultipleExtensionsFunction::OnDialogCancelled() {
+ // Let the consumer end know that the Close button was clicked.
+ Respond(Error(kUserCancelledError));
+}
+
+void DeveloperPrivateRemoveMultipleExtensionsFunction::OnDialogAccepted() {
+ for (const auto& extension_id : extension_ids_) {
+ if (!browser_context()) {
+ return;
+ }
+ const Extension* current_extension =
+ ExtensionRegistry::Get(profile_)->GetExtensionById(
+ extension_id, ExtensionRegistry::EVERYTHING);
+ // Extensions can be uninstalled externally while the dialog is open. Only
+ // uninstall extensions that are still existent.
+ if (!current_extension) {
+ continue;
+ }
+ // If an extension fails to be uninstalled, it will not pause the
+ // uninstall of the other extensions on the list.
+ ExtensionSystem::Get(profile_)->extension_service()->UninstallExtension(
+ extension_id, UNINSTALL_REASON_USER_INITIATED, nullptr);
+ }
+ Respond(NoArguments());
+}
+
} // namespace api
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chromium/chrome/browser/extensions/api/developer_private/developer_private_api.h
index 3936d9649eb..c826ae40970 100644
--- a/chromium/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chromium/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -20,6 +20,7 @@
#include "chrome/browser/extensions/extension_uninstall_dialog.h"
#include "chrome/browser/extensions/load_error_reporter.h"
#include "chrome/browser/extensions/pack_extension_job.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/common/extensions/api/developer_private.h"
#include "chrome/common/extensions/webstore_install_result.h"
#include "components/prefs/pref_change_registrar.h"
@@ -53,7 +54,7 @@ class ExtensionInfoGenerator;
// A key that indicates whether the safety check warning for this
// extension has been acknowledged because the user has chosen to keep
// it in a past review.
-constexpr PrefMap kPrefAcknowledgeSafetyCheckWarning = {
+inline constexpr PrefMap kPrefAcknowledgeSafetyCheckWarning = {
"ack_safety_check_warning", PrefType::kBool, PrefScope::kExtensionSpecific};
namespace api {
@@ -77,7 +78,8 @@ class DeveloperPrivateEventRouter : public ExtensionRegistryObserver,
public ExtensionAllowlist::Observer,
public ExtensionManagement::Observer,
public WarningService::Observer,
- public PermissionsManager::Observer {
+ public PermissionsManager::Observer,
+ public ToolbarActionsModel::Observer {
public:
explicit DeveloperPrivateEventRouter(Profile* profile);
@@ -91,6 +93,10 @@ class DeveloperPrivateEventRouter : public ExtensionRegistryObserver,
void AddExtensionId(const std::string& extension_id);
void RemoveExtensionId(const std::string& extension_id);
+ // Called when the configuration (such as user preferences) for an extension
+ // has changed in a way that may affect the chrome://extensions UI.
+ void OnExtensionConfigurationChanged(const std::string& extension_id);
+
private:
// ExtensionRegistryObserver:
void OnExtensionLoaded(content::BrowserContext* browser_context,
@@ -154,6 +160,15 @@ class DeveloperPrivateEventRouter : public ExtensionRegistryObserver,
const PermissionSet& permissions,
PermissionsManager::UpdateReason reason) override;
+ // ToolbarActionsModel::Observer:
+ void OnToolbarActionAdded(const ToolbarActionsModel::ActionId& id) override {}
+ void OnToolbarActionRemoved(
+ const ToolbarActionsModel::ActionId& id) override {}
+ void OnToolbarActionUpdated(
+ const ToolbarActionsModel::ActionId& id) override {}
+ void OnToolbarModelInitialized() override {}
+ void OnToolbarPinnedActionsChanged() override;
+
// Handles a profile preference change.
void OnProfilePrefChanged();
@@ -186,6 +201,8 @@ class DeveloperPrivateEventRouter : public ExtensionRegistryObserver,
extension_allowlist_observer_{this};
base::ScopedObservation<PermissionsManager, PermissionsManager::Observer>
permissions_manager_observation_{this};
+ base::ScopedObservation<ToolbarActionsModel, ToolbarActionsModel::Observer>
+ toolbar_actions_model_observation_{this};
raw_ptr<Profile> profile_;
@@ -940,6 +957,44 @@ class DeveloperPrivateUpdateSiteAccessFunction
void OnSiteSettingsUpdated();
};
+class DeveloperPrivateRemoveMultipleExtensionsFunction
+ : public DeveloperPrivateAPIFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("developerPrivate.removeMultipleExtensions",
+ DEVELOPERPRIVATE_REMOVEMULTIPLEEXTENSIONS)
+ DeveloperPrivateRemoveMultipleExtensionsFunction();
+
+ DeveloperPrivateRemoveMultipleExtensionsFunction(
+ const DeveloperPrivateRemoveMultipleExtensionsFunction&) = delete;
+ DeveloperPrivateRemoveMultipleExtensionsFunction& operator=(
+ const DeveloperPrivateRemoveMultipleExtensionsFunction&) = delete;
+
+ void accept_bubble_for_testing(bool accept_bubble) {
+ accept_bubble_for_testing_ = accept_bubble;
+ }
+
+ private:
+ ~DeveloperPrivateRemoveMultipleExtensionsFunction() override;
+
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ // A callback function to run when the user accepts the action dialog.
+ void OnDialogAccepted();
+
+ // A callback function to run when the user cancels the action dialog.
+ void OnDialogCancelled();
+
+ // The IDs of the extensions to be uninstalled.
+ std::vector<ExtensionId> extension_ids_;
+
+ raw_ptr<Profile> profile_;
+
+ // If true, immediately accept the blocked action dialog by running the
+ // callback.
+ absl::optional<bool> accept_bubble_for_testing_;
+};
+
} // namespace api
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chromium/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index c53ab8189ee..fe1672f097c 100644
--- a/chromium/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -22,8 +22,10 @@
#include "base/test/gtest_util.h"
#include "base/test/values_test_util.h"
#include "base/values.h"
+#include "chrome/browser/extensions/api/developer_private/extension_info_generator.h"
#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "chrome/browser/extensions/error_console/error_console.h"
+#include "chrome/browser/extensions/extension_action_test_util.h"
#include "chrome/browser/extensions/extension_management.h"
#include "chrome/browser/extensions/extension_management_test_util.h"
#include "chrome/browser/extensions/extension_service.h"
@@ -34,6 +36,7 @@
#include "chrome/browser/extensions/scripting_permissions_modifier.h"
#include "chrome/browser/extensions/site_permissions_helper.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/common/extensions/api/developer_private.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/test_browser_window.h"
@@ -82,6 +85,7 @@ namespace extensions {
namespace {
const char kGoodCrx[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+const char kGoogleOnlyCrx[] = "jjlcocfpfbknlbgijblaapbcpbdglkhf";
constexpr char kInvalidHost[] = "invalid host";
constexpr char kInvalidHostError[] = "Invalid host.";
@@ -226,13 +230,17 @@ void GetMatchingExtensionsForSite(
auto MatchMatchingExtensionInfo(
const std::string& extension_id,
- const api::developer_private::HostAccess& host_access) {
+ const api::developer_private::HostAccess& host_access,
+ bool can_request_all_sites) {
return testing::AllOf(
testing::Field(&api::developer_private::MatchingExtensionInfo::id,
extension_id),
testing::Field(
&api::developer_private::MatchingExtensionInfo::site_access,
- host_access));
+ host_access),
+ testing::Field(
+ &api::developer_private::MatchingExtensionInfo::can_request_all_sites,
+ can_request_all_sites));
}
api::developer_private::ExtensionSiteAccessUpdate CreateSiteAccessUpdate(
@@ -418,18 +426,27 @@ void DeveloperPrivateApiUnitTest::TestExtensionPrefSetting(
function->set_source_context_type(Feature::WEBUI_CONTEXT);
EXPECT_TRUE(RunFunction(function, args)) << key;
EXPECT_TRUE(has_pref.Run()) << key;
+ }
+
+ {
+ base::Value::Dict parameters;
+ parameters.Set("extensionId", extension_id);
+ parameters.Set(key, false);
+
+ base::Value::List args;
+ args.Append(std::move(parameters));
ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture;
- function = base::MakeRefCounted<
+ auto function = base::MakeRefCounted<
api::DeveloperPrivateUpdateExtensionConfigurationFunction>();
EXPECT_TRUE(RunFunction(function, args)) << key;
- EXPECT_TRUE(has_pref.Run()) << key;
+ EXPECT_FALSE(has_pref.Run()) << key;
}
{
base::Value::Dict parameters;
parameters.Set("extensionId", extension_id);
- parameters.Set(key, false);
+ parameters.Set(key, true);
base::Value::List args;
args.Append(std::move(parameters));
@@ -438,7 +455,7 @@ void DeveloperPrivateApiUnitTest::TestExtensionPrefSetting(
auto function = base::MakeRefCounted<
api::DeveloperPrivateUpdateExtensionConfigurationFunction>();
EXPECT_TRUE(RunFunction(function, args)) << key;
- EXPECT_FALSE(has_pref.Run()) << key;
+ EXPECT_TRUE(has_pref.Run()) << key;
}
}
@@ -516,6 +533,7 @@ void DeveloperPrivateApiUnitTest::SetUp() {
ExtensionServiceInitParams init_params;
init_params.profile_is_supervised = ProfileIsSupervised();
InitializeExtensionService(init_params);
+ extension_action_test_util::CreateToolbarModelForProfile(profile());
browser_window_ = std::make_unique<TestBrowserWindow>();
Browser::CreateParams params(profile(), true);
@@ -556,6 +574,19 @@ TEST_F(DeveloperPrivateApiUnitTest,
ScriptingPermissionsModifier(profile(), base::WrapRefCounted(extension))
.SetWithholdHostPermissions(true);
+ // Test pinning to toolbar first as this needs the extension to be enabled.
+ // The other pref settings tested below may disable the extension so it will
+ // not have an action in the toolbar.
+ auto pinned_to_toolbar = [&]() {
+ ToolbarActionsModel* toolbar_actions_model =
+ ToolbarActionsModel::Get(profile());
+ return toolbar_actions_model->HasAction(id) &&
+ toolbar_actions_model->IsActionPinned(id);
+ };
+ TestExtensionPrefSetting(base::BindLambdaForTesting(pinned_to_toolbar),
+ "pinnedToToolbar", id,
+ /*expected_default_value=*/false);
+
TestExtensionPrefSetting(
base::BindRepeating(&HasPrefsPermission, &util::IsIncognitoEnabled,
profile(), id),
@@ -2012,8 +2043,16 @@ TEST_P(DeveloperPrivateApiZipFileUnitTest, InstallDroppedFileZip) {
// Expect extension install directory to be immediate subdir of expected
// unpacked install directory. E.g. /a/b/c/d == /a/b/c + /d.
- EXPECT_EQ(extension->path(), expected_extension_install_directory_.Append(
- extension->path().BaseName()));
+ //
+ // Make sure we're comparing absolute paths to avoid failures like
+ // https://crbug.com/1453671 on macOS 14.
+ base::FilePath absolute_extension_path =
+ base::MakeAbsoluteFilePath(extension->path());
+ base::FilePath absolute_expected_extension_install_directory =
+ base::MakeAbsoluteFilePath(expected_extension_install_directory_.Append(
+ extension->path().BaseName()));
+ EXPECT_EQ(absolute_extension_path,
+ absolute_expected_extension_install_directory);
// Expect extension install directory to exist and be named with the right
// prefix.
@@ -2481,6 +2520,50 @@ TEST_F(DeveloperPrivateApiUnitTest,
}])");
}
+// Test that host permissions from policy installed extensions are included in
+// `getUserAndExtensionSitesByEtld` calls.
+TEST_F(
+ DeveloperPrivateApiUnitTest,
+ DeveloperPrivateGetUserAndExtensionSitesByEtld_PolicyControlledExtensions) {
+ std::string extension_id(kGoogleOnlyCrx);
+
+ // Set up a mock provider with a policy extension.
+ std::unique_ptr<MockExternalProvider> mock_provider =
+ std::make_unique<MockExternalProvider>(
+ service(), mojom::ManifestLocation::kExternalPolicyDownload);
+ MockExternalProvider* mock_provider_ptr = mock_provider.get();
+ AddMockExternalProvider(std::move(mock_provider));
+
+ // google_only.crx contains only a manifest.json file that requests
+ // *://www.google.com/* as a permission.
+ mock_provider_ptr->UpdateOrAddExtension(
+ extension_id, "1", data_dir().AppendASCII("google_only.crx"));
+ // Reloading extensions should find our externally registered extension
+ // and install it.
+ {
+ TestExtensionRegistryObserver observer(registry());
+ service()->CheckForExternalUpdates();
+ EXPECT_EQ(extension_id, observer.WaitForExtensionLoaded()->id());
+ }
+
+ auto function = base::MakeRefCounted<
+ api::DeveloperPrivateGetUserAndExtensionSitesByEtldFunction>();
+ EXPECT_TRUE(RunFunction(function, base::Value::List()))
+ << function->GetError();
+ const base::Value::List* results = function->GetResultListForTest();
+ ASSERT_EQ(1u, results->size());
+
+ EXPECT_THAT((*results)[0], base::test::IsJson(R"([{
+ "etldPlusOne": "google.com",
+ "numExtensions": 1,
+ "sites": [{
+ "siteSet": "EXTENSION_SPECIFIED",
+ "numExtensions": 1,
+ "site": "www.google.com",
+ }]
+ }])"));
+}
+
TEST_F(DeveloperPrivateApiUnitTest,
DeveloperPrivateGetMatchingExtensionsForSite) {
namespace developer = api::developer_private;
@@ -2504,21 +2587,19 @@ TEST_F(DeveloperPrivateApiUnitTest,
// "http://images.google.com/" should only match with `extension_2`.
EXPECT_THAT(infos, testing::UnorderedElementsAre(MatchMatchingExtensionInfo(
extension_2->id(),
- developer::HostAccess::HOST_ACCESS_ON_ALL_SITES)));
+ developer::HostAccess::HOST_ACCESS_ON_SPECIFIC_SITES,
+ /*can_request_all_sites=*/false)));
service()->DisableExtension(extension_2->id(),
disable_reason::DISABLE_USER_ACTION);
GetMatchingExtensionsForSite(profile(), "*://*.google.com/", &infos);
- // "*://*.google.com/" should only match with both `extension_1` and
- // `extension_2`.
- EXPECT_THAT(infos, testing::UnorderedElementsAre(
- MatchMatchingExtensionInfo(
- extension_1->id(),
- developer::HostAccess::HOST_ACCESS_ON_ALL_SITES),
- MatchMatchingExtensionInfo(
- extension_2->id(),
- developer::HostAccess::HOST_ACCESS_ON_ALL_SITES)));
+ // "*://*.google.com/" should match with `extension_1` but not `extension_2`
+ // since it is disabled.
+ EXPECT_THAT(infos, testing::UnorderedElementsAre(MatchMatchingExtensionInfo(
+ extension_1->id(),
+ developer::HostAccess::HOST_ACCESS_ON_SPECIFIC_SITES,
+ /*can_request_all_sites=*/false)));
}
// Test that the host access returned by GetMatchingExtensionsForSite reflects
@@ -2537,7 +2618,8 @@ TEST_F(DeveloperPrivateApiUnitTest,
EXPECT_THAT(infos, testing::UnorderedElementsAre(MatchMatchingExtensionInfo(
extension->id(),
- developer::HostAccess::HOST_ACCESS_ON_ALL_SITES)));
+ developer::HostAccess::HOST_ACCESS_ON_ALL_SITES,
+ /*can_request_all_sites=*/true)));
EXPECT_FALSE(PermissionsManager::Get(browser()->profile())
->HasWithheldHostPermissions(*extension));
@@ -2545,23 +2627,25 @@ TEST_F(DeveloperPrivateApiUnitTest,
modifier.SetWithholdHostPermissions(true);
GetMatchingExtensionsForSite(profile(), "http://example.com/", &infos);
- EXPECT_THAT(infos, testing::UnorderedElementsAre(MatchMatchingExtensionInfo(
- extension->id(),
- developer::HostAccess::HOST_ACCESS_ON_CLICK)));
+ EXPECT_THAT(infos,
+ testing::UnorderedElementsAre(MatchMatchingExtensionInfo(
+ extension->id(), developer::HostAccess::HOST_ACCESS_ON_CLICK,
+ /*can_request_all_sites=*/true)));
RunAddHostPermission(profile(), *extension, "*://*.google.com/*",
/*should_succeed=*/true, nullptr);
GetMatchingExtensionsForSite(profile(), "http://google.com/", &infos);
- EXPECT_THAT(infos,
- testing::UnorderedElementsAre(MatchMatchingExtensionInfo(
- extension->id(),
- developer::HostAccess::HOST_ACCESS_ON_SPECIFIC_SITES)));
-
- GetMatchingExtensionsForSite(profile(), "http://example.com/", &infos);
EXPECT_THAT(infos, testing::UnorderedElementsAre(MatchMatchingExtensionInfo(
extension->id(),
- developer::HostAccess::HOST_ACCESS_ON_CLICK)));
+ developer::HostAccess::HOST_ACCESS_ON_SPECIFIC_SITES,
+ /*can_request_all_sites=*/true)));
+
+ GetMatchingExtensionsForSite(profile(), "http://example.com/", &infos);
+ EXPECT_THAT(infos,
+ testing::UnorderedElementsAre(MatchMatchingExtensionInfo(
+ extension->id(), developer::HostAccess::HOST_ACCESS_ON_CLICK,
+ /*can_request_all_sites=*/true)));
}
// Tests the UpdateSiteAccess function when called on an extension with no
@@ -2741,6 +2825,163 @@ TEST_F(DeveloperPrivateApiUnitTest,
permissions_manager->HasGrantedHostPermission(*extension_2, kGoogleCom));
}
+// Test uninstalling multiple extensions.
+TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateRemoveMultipleExtensions) {
+ scoped_refptr<const Extension> extension_1 =
+ ExtensionBuilder("test_1").Build();
+ scoped_refptr<const Extension> extension_2 =
+ ExtensionBuilder("test_2").Build();
+ service()->AddExtension(extension_1.get());
+ service()->AddExtension(extension_2.get());
+ EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_1->id()));
+ EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_2->id()));
+
+ base::Value::List extension_ids_entries;
+ extension_ids_entries.reserve(2u);
+ extension_ids_entries.Append(extension_1->id());
+ extension_ids_entries.Append(extension_2->id());
+ std::string extension_ids_arg;
+ EXPECT_TRUE(
+ base::JSONWriter::Write(extension_ids_entries, &extension_ids_arg));
+ std::string args = base::StringPrintf(R"([%s])", extension_ids_arg.c_str());
+
+ auto function = base::MakeRefCounted<
+ api::DeveloperPrivateRemoveMultipleExtensionsFunction>();
+
+ // Accept the multiple extension uninstallation bubble by default in unit
+ // tests.
+ function->accept_bubble_for_testing(true);
+
+ // Run the private api to remove the installed extensions.
+ api_test_utils::RunFunction(function.get(), args, profile());
+
+ EXPECT_FALSE(registry()->enabled_extensions().Contains(extension_1->id()));
+ EXPECT_FALSE(registry()->enabled_extensions().Contains(extension_2->id()));
+ EXPECT_EQ(registry()->enabled_extensions().size(), 0u);
+}
+
+TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateRemoveComponentExtensions) {
+ // Create a component extension and a regular extension, then try to remove
+ // them.
+ scoped_refptr<const Extension> component_extension =
+ ExtensionBuilder("component_extension")
+ .SetLocation(mojom::ManifestLocation::kComponent)
+ .Build();
+ scoped_refptr<const Extension> test_extension =
+ ExtensionBuilder("test_extension").Build();
+ service()->AddExtension(component_extension.get());
+ service()->AddExtension(test_extension.get());
+
+ EXPECT_EQ(registry()->enabled_extensions().size(), 2u);
+
+ // Create a list of extensions with a component extension in it.
+ base::Value::List extensions_list;
+ extensions_list.reserve(2u);
+ extensions_list.Append(component_extension->id());
+ extensions_list.Append(test_extension->id());
+ std::string args;
+ EXPECT_TRUE(base::JSONWriter::Write(extensions_list, &args));
+ std::string component_args = base::StringPrintf(R"([%s])", args.c_str());
+ auto function = base::MakeRefCounted<
+ api::DeveloperPrivateRemoveMultipleExtensionsFunction>();
+
+ // Accept the multiple extension uninstallation bubble by default in unit
+ // tests.
+ function->accept_bubble_for_testing(true);
+ // Verify the error message for uninstalling component and enterprise
+ // extensions.
+ EXPECT_EQ(
+ "Cannot uninstall the enterprise or component extensions in your list.",
+ api_test_utils::RunFunctionAndReturnError(function.get(), component_args,
+ profile()));
+
+ // Because there is a component extension in the list, the uninstallation is
+ // canceled. The number of extensions remains the same.
+ EXPECT_EQ(registry()->enabled_extensions().size(), 2u);
+}
+
+TEST_F(DeveloperPrivateApiUnitTest,
+ DeveloperPrivateRemoveEnterpriseExtensions) {
+ // Create an enterprise extension and a regular extension, then try to remove
+ // them.
+ scoped_refptr<const Extension> enterprise_extension =
+ ExtensionBuilder("enterprise_extension")
+ .SetLocation(mojom::ManifestLocation::kExternalPolicy)
+ .Build();
+ scoped_refptr<const Extension> test_extension =
+ ExtensionBuilder("test_extension").Build();
+ service()->AddExtension(enterprise_extension.get());
+ service()->AddExtension(test_extension.get());
+
+ EXPECT_EQ(registry()->enabled_extensions().size(), 2u);
+
+ // Create a list of extensions with an enterprise extension in it.
+ base::Value::List extensions_list;
+ extensions_list.reserve(2u);
+ extensions_list.Append(enterprise_extension->id());
+ extensions_list.Append(test_extension->id());
+ std::string args;
+ EXPECT_TRUE(base::JSONWriter::Write(extensions_list, &args));
+ std::string enterprise_args = base::StringPrintf(R"([%s])", args.c_str());
+ auto function = base::MakeRefCounted<
+ api::DeveloperPrivateRemoveMultipleExtensionsFunction>();
+
+ // Accept the multiple extension uninstallation bubble by default in unit
+ // tests.
+ function->accept_bubble_for_testing(true);
+ // Verify the error message for uninstalling component and enterprise
+ // extensions.
+ EXPECT_EQ(
+ "Cannot uninstall the enterprise or component extensions in your list.",
+ api_test_utils::RunFunctionAndReturnError(function.get(), enterprise_args,
+ profile()));
+
+ // Because there is an enterprise extension in the list, the uninstallation is
+ // canceled. The number of extensions remains the same.
+ EXPECT_EQ(registry()->enabled_extensions().size(), 2u);
+}
+
+// Test that an event is dispatched when the list of pinned extension actions
+// has changed.
+TEST_F(DeveloperPrivateApiUnitTest,
+ ExtensionUpdatedEventOnPinnedActionsChange) {
+ // We need to call DeveloperPrivateAPI::Get() in order to instantiate the
+ // keyed service, since it's not created by default in unit tests.
+ DeveloperPrivateAPI::Get(profile());
+ EventRouter* event_router = EventRouter::Get(profile());
+
+ // The DeveloperPrivateEventRouter will only dispatch events if there's at
+ // least one listener to dispatch to. Create one.
+ const char* kEventName =
+ api::developer_private::OnItemStateChanged::kEventName;
+ event_router->AddEventListener(kEventName, render_process_host(),
+ crx_file::id_util::GenerateId("listener"));
+
+ TestEventRouterObserver test_observer(event_router);
+
+ scoped_refptr<const Extension> extension = ExtensionBuilder("test").Build();
+ service()->AddExtension(extension.get());
+ EXPECT_TRUE(registry()->enabled_extensions().Contains(extension->id()));
+
+ // The event router fetches icons from a blocking thread when sending the
+ // update event; allow it to finish before verifying the event was dispatched.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(WasItemChangedEventDispatched(
+ test_observer, extension->id(),
+ api::developer_private::EVENT_TYPE_PINNED_ACTIONS_CHANGED));
+
+ ToolbarActionsModel* toolbar_actions_model =
+ ToolbarActionsModel::Get(profile());
+
+ toolbar_actions_model->SetActionVisibility(
+ extension->id(), !toolbar_actions_model->IsActionPinned(extension->id()));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(WasItemChangedEventDispatched(
+ test_observer, extension->id(),
+ api::developer_private::EVENT_TYPE_PINNED_ACTIONS_CHANGED));
+}
+
class DeveloperPrivateApiAllowlistUnitTest
: public DeveloperPrivateApiUnitTest {
public:
diff --git a/chromium/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc b/chromium/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc
index fabe6549dda..2ac4fa20175 100644
--- a/chromium/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc
@@ -130,16 +130,26 @@ IN_PROC_BROWSER_TEST_F(DeveloperPrivateApiTest, InspectEmbeddedOptionsPage) {
profile());
// Verify that dev tools opened.
- content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
- view.render_process_id, view.render_view_id);
- ASSERT_TRUE(rfh);
- content::WebContents* wc = content::WebContents::FromRenderFrameHost(rfh);
+ content::RenderFrameHost* render_frame_host =
+ content::RenderFrameHost::FromID(view.render_process_id,
+ view.render_view_id);
+ ASSERT_TRUE(render_frame_host);
+ content::WebContents* wc =
+ content::WebContents::FromRenderFrameHost(render_frame_host);
ASSERT_TRUE(wc);
EXPECT_TRUE(DevToolsWindow::GetInstanceForInspectedWebContents(wc));
}
+// TODO(https://crbug.com/1457154): Test is flaky on MSan builders.
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_InspectInactiveServiceWorkerBackground \
+ DISABLED_InspectInactiveServiceWorkerBackground
+#else
+#define MAYBE_InspectInactiveServiceWorkerBackground \
+ InspectInactiveServiceWorkerBackground
+#endif
IN_PROC_BROWSER_TEST_F(DeveloperPrivateApiTest,
- InspectInactiveServiceWorkerBackground) {
+ MAYBE_InspectInactiveServiceWorkerBackground) {
ResultCatcher result_catcher;
// Load an extension that is service worker-based.
const Extension* extension =
diff --git a/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
index d1051e2fa6f..74a1d670662 100644
--- a/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
+++ b/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.cc
@@ -17,6 +17,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "chrome/browser/extensions/api/commands/command_service.h"
+#include "chrome/browser/extensions/api/developer_private/developer_private_api.h"
#include "chrome/browser/extensions/api/developer_private/inspectable_views_finder.h"
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
#include "chrome/browser/extensions/error_console/error_console.h"
@@ -26,12 +27,12 @@
#include "chrome/browser/extensions/shared_module_service.h"
#include "chrome/browser/extensions/site_permissions_helper.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
-#include "chrome/grit/google_chrome_strings.h"
#include "components/supervised_user/core/common/pref_names.h"
#include "content/public/browser/render_frame_host.h"
#include "extensions/browser/blocklist_extension_prefs.h"
@@ -55,11 +56,13 @@
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "extensions/common/manifest_handlers/offline_enabled_info.h"
#include "extensions/common/manifest_handlers/options_page_info.h"
+#include "extensions/common/manifest_handlers/permissions_parser.h"
#include "extensions/common/manifest_url_handlers.h"
#include "extensions/common/permissions/permission_message_provider.h"
#include "extensions/common/permissions/permission_message_util.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/grit/extensions_browser_resources.h"
+#include "extensions/strings/grit/extensions_strings.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
@@ -142,15 +145,15 @@ developer::RuntimeError ConstructRuntimeError(const RuntimeError& error) {
developer::RuntimeError result;
PopulateErrorBase(error, &result);
switch (error.level()) {
- case logging::LOG_VERBOSE:
- case logging::LOG_INFO:
+ case logging::LOGGING_VERBOSE:
+ case logging::LOGGING_INFO:
result.severity = developer::ERROR_LEVEL_LOG;
break;
- case logging::LOG_WARNING:
+ case logging::LOGGING_WARNING:
result.severity = developer::ERROR_LEVEL_WARN;
break;
- case logging::LOG_FATAL:
- case logging::LOG_ERROR:
+ case logging::LOGGING_FATAL:
+ case logging::LOGGING_ERROR:
result.severity = developer::ERROR_LEVEL_ERROR;
break;
default:
@@ -311,6 +314,19 @@ developer::RuntimeHostPermissions CreateRuntimeHostPermissionsInfo(
return runtime_host_permissions;
}
+// Returns if the extension can access site data. This checks for host
+// permissions, activeTab and API permissions that will surface a warning for
+// all hosts access.
+bool CanAccessSiteData(PermissionsManager* permissions_manager,
+ const Extension& extension) {
+ return permissions_manager->ExtensionRequestsHostPermissionsOrActiveTab(
+ extension) ||
+ PermissionsParser::GetRequiredPermissions(&extension)
+ .ShouldWarnAllHosts() ||
+ PermissionsParser::GetOptionalPermissions(&extension)
+ .ShouldWarnAllHosts();
+}
+
// Populates the |permissions| data for the given |extension|.
void AddPermissionsInfo(content::BrowserContext* browser_context,
const Extension& extension,
@@ -331,6 +347,10 @@ void AddPermissionsInfo(content::BrowserContext* browser_context,
PermissionsManager* permissions_manager =
PermissionsManager::Get(browser_context);
+
+ permissions->can_access_site_data =
+ CanAccessSiteData(permissions_manager, extension);
+
bool enable_runtime_host_permissions =
permissions_manager->CanAffectExtension(extension);
@@ -401,6 +421,8 @@ void ExtensionInfoGenerator::CreateExtensionInfo(
state = developer::EXTENSION_STATE_DISABLED;
else if ((ext = registry->terminated_extensions().GetByID(id)) != nullptr)
state = developer::EXTENSION_STATE_TERMINATED;
+ else if ((ext = registry->blocklisted_extensions().GetByID(id)) != nullptr)
+ state = developer::EXTENSION_STATE_BLACKLISTED;
if (ext && ui_util::ShouldDisplayInExtensionSettings(*ext))
CreateExtensionInfoHelper(*ext, state);
@@ -539,7 +561,8 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper(
absl::optional<CWSInfoService::CWSInfo> cws_info =
cws_info_service_->GetCWSInfo(extension);
if (cws_info.has_value()) {
- info->safety_check_text = CreateSafetyCheckDisplayString(*cws_info);
+ info->safety_check_text =
+ CreateSafetyCheckDisplayString(*cws_info, state);
}
}
@@ -639,6 +662,11 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper(
info->incognito_access.is_active =
util::IsIncognitoEnabled(extension.id(), browser_context_);
+ // Safety check warning acknowledge status.
+ extension_prefs_->ReadPrefAsBoolean(
+ extension.id(), extensions::kPrefAcknowledgeSafetyCheckWarning,
+ &info->acknowledge_safety_check_warning);
+
// Install warnings, but only if unpacked, the error console isn't enabled
// (otherwise it shows these), and we're in developer mode (normal users don't
// need to see these).
@@ -763,6 +791,18 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper(
SitePermissionsHelper(profile).ShowAccessRequestsInToolbar(
extension.id());
+ // Pinned to toolbar.
+ // TODO(crbug.com/1477884): Currently this information is only shown for
+ // enabled extensions as only enabled extensions can have actions. However,
+ // this information can be found in prefs, so disabled extensiosn can be
+ // included as well.
+ ToolbarActionsModel* toolbar_actions_model =
+ ToolbarActionsModel::Get(profile);
+ if (toolbar_actions_model->HasAction(extension.id())) {
+ info->pinned_to_toolbar =
+ toolbar_actions_model->IsActionPinned(extension.id());
+ }
+
// The icon.
ExtensionResource icon =
IconsInfo::GetIconResource(&extension,
@@ -786,8 +826,8 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper(
developer::SafetyCheckStrings
ExtensionInfoGenerator::CreateSafetyCheckDisplayString(
- CWSInfoService::CWSInfo& cws_info) {
- // TODO(crbug.com/1432194): Add panel_page_string logic.
+ const CWSInfoService::CWSInfo& cws_info,
+ developer::ExtensionState state) {
developer::SafetyCheckStrings display_strings;
std::string detail_page_string;
std::string panel_page_string;
@@ -796,10 +836,16 @@ ExtensionInfoGenerator::CreateSafetyCheckDisplayString(
case CWSInfoService::CWSViolationType::kMalware:
detail_page_string =
l10n_util::GetStringUTF8(IDS_SAFETY_CHECK_EXTENSIONS_MALWARE);
+ panel_page_string = l10n_util::GetStringUTF8(IDS_EXTENSIONS_SC_MALWARE);
break;
case CWSInfoService::CWSViolationType::kPolicy:
detail_page_string = l10n_util::GetStringUTF8(
IDS_SAFETY_CHECK_EXTENSIONS_POLICY_VIOLATION);
+ panel_page_string = state == developer::EXTENSION_STATE_ENABLED
+ ? l10n_util::GetStringUTF8(
+ IDS_EXTENSIONS_SC_POLICY_VIOLATION_ON)
+ : l10n_util::GetStringUTF8(
+ IDS_EXTENSIONS_SC_POLICY_VIOLATION_OFF);
break;
case CWSInfoService::CWSViolationType::kNone:
case CWSInfoService::CWSViolationType::kMinorPolicy:
@@ -807,6 +853,10 @@ ExtensionInfoGenerator::CreateSafetyCheckDisplayString(
if (cws_info.unpublished_long_ago) {
detail_page_string =
l10n_util::GetStringUTF8(IDS_SAFETY_CHECK_EXTENSIONS_UNPUBLISHED);
+ panel_page_string =
+ state == developer::EXTENSION_STATE_ENABLED
+ ? l10n_util::GetStringUTF8(IDS_EXTENSIONS_SC_UNPUBLISHED_ON)
+ : l10n_util::GetStringUTF8(IDS_EXTENSIONS_SC_UNPUBLISHED_OFF);
}
break;
}
diff --git a/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.h b/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.h
index 619b73d07cf..d0e2d6ae5e1 100644
--- a/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.h
+++ b/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.h
@@ -74,17 +74,18 @@ class ExtensionInfoGenerator {
static std::vector<URLPattern> GetDistinctHosts(
const URLPatternSet& patterns);
+ // Construct the needed strings for the safety check on the
+ // extensions page.
+ static api::developer_private::SafetyCheckStrings
+ CreateSafetyCheckDisplayString(const CWSInfoService::CWSInfo& cws_info,
+ api::developer_private::ExtensionState state);
+
private:
// Creates an ExtensionInfo for the given |extension| and |state|, and
// asynchronously adds it to the |list|.
void CreateExtensionInfoHelper(const Extension& extension,
api::developer_private::ExtensionState state);
- // Construct the needed strings for the safety check on the
- // extensions page.
- static api::developer_private::SafetyCheckStrings
- CreateSafetyCheckDisplayString(CWSInfoService::CWSInfo& cws_info);
-
// Callback for the asynchronous image loading.
void OnImageLoaded(
std::unique_ptr<api::developer_private::ExtensionInfo> info,
diff --git a/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc b/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
index 74dd9d5eee7..e577afbff5f 100644
--- a/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc
@@ -24,6 +24,7 @@
#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "chrome/browser/extensions/cws_info_service.h"
#include "chrome/browser/extensions/error_console/error_console.h"
+#include "chrome/browser/extensions/extension_action_test_util.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_service_test_with_install.h"
#include "chrome/browser/extensions/extension_util.h"
@@ -31,10 +32,11 @@
#include "chrome/browser/extensions/permissions_updater.h"
#include "chrome/browser/extensions/scripting_permissions_modifier.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/common/extensions/api/developer_private.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/chromium_strings.h"
-#include "chrome/grit/google_chrome_strings.h"
+#include "chrome/grit/generated_resources.h"
#include "components/crx_file/id_util.h"
#include "components/supervised_user/core/common/buildflags.h"
#include "extensions/browser/extension_registry.h"
@@ -124,6 +126,7 @@ class ExtensionInfoGeneratorUnitTest : public ExtensionServiceTestWithInstall {
void SetUp() override {
ExtensionServiceTestWithInstall::SetUp();
InitializeExtensionService(GetExtensionServiceInitParams());
+ extension_action_test_util::CreateToolbarModelForProfile(profile());
}
// Returns the initialization parameters for the extension service.
@@ -141,12 +144,6 @@ class ExtensionInfoGeneratorUnitTest : public ExtensionServiceTestWithInstall {
std::move(quit_closure_).Run();
}
- api::developer_private::SafetyCheckStrings CreateSafetyCheckDisplayStringTest(
- CWSInfoService::CWSInfo& cws_info) {
- return ExtensionInfoGenerator(browser_context())
- .CreateSafetyCheckDisplayString(cws_info);
- }
-
std::unique_ptr<developer::ExtensionInfo> GenerateExtensionInfo(
const std::string& extension_id) {
std::unique_ptr<developer::ExtensionInfo> info;
@@ -211,6 +208,10 @@ class ExtensionInfoGeneratorUnitTest : public ExtensionServiceTestWithInstall {
const base::FilePath& extension_path,
mojom::ManifestLocation location) {
ChromeTestExtensionLoader loader(browser_context());
+
+ // Unit tests are single process and as such, attempting to wait for an
+ // extension renderer process will cause the test to time out.
+ loader.set_wait_for_renderers(false);
loader.set_location(location);
loader.set_creation_flags(Extension::REQUIRE_KEY);
scoped_refptr<const Extension> extension =
@@ -298,13 +299,13 @@ TEST_F(ExtensionInfoGeneratorUnitTest, BasicInfoTest) {
error_console->ReportError(std::make_unique<RuntimeError>(
extension->id(), false, u"source", u"message",
StackTrace(1, StackFrame(1, 1, u"source", u"function")), kContextUrl,
- logging::LOG_ERROR, 1, 1));
+ logging::LOGGING_ERROR, 1, 1));
error_console->ReportError(std::make_unique<ManifestError>(
extension->id(), u"message", u"key", std::u16string()));
error_console->ReportError(std::make_unique<RuntimeError>(
extension->id(), false, u"source", u"message",
StackTrace(1, StackFrame(1, 1, u"source", u"function")), kContextUrl,
- logging::LOG_WARNING, 1, 1));
+ logging::LOGGING_WARNING, 1, 1));
// It's not feasible to validate every field here, because that would be
// a duplication of the logic in the method itself. Instead, test a handful
@@ -325,6 +326,7 @@ TEST_F(ExtensionInfoGeneratorUnitTest, BasicInfoTest) {
EXPECT_TRUE(info->incognito_access.is_enabled);
EXPECT_FALSE(info->incognito_access.is_active);
EXPECT_TRUE(base::StartsWith(info->icon_url, "data:image/png;base64,"));
+ EXPECT_FALSE(*info->pinned_to_toolbar);
// Strip out the kHostReadWrite permission created by the extension requesting
// host permissions above; runtime host permissions mean these are always
@@ -357,6 +359,7 @@ TEST_F(ExtensionInfoGeneratorUnitTest, BasicInfoTest) {
++i;
}
EXPECT_TRUE(info->permissions.runtime_host_permissions);
+ EXPECT_TRUE(info->permissions.can_access_site_data);
ASSERT_EQ(2u, info->runtime_errors.size());
const api::developer_private::RuntimeError& runtime_error =
@@ -477,10 +480,11 @@ TEST_F(ExtensionInfoGeneratorUnitTest, GenerateExtensionsJSONData) {
#if !BUILDFLAG(IS_CHROMEOS_ASH)
// Test Extension2
- extension_path = data_dir().AppendASCII("good")
- .AppendASCII("Extensions")
- .AppendASCII("hpiknbiabeeppbpihjehijgoemciehgk")
- .AppendASCII("2");
+ extension_path = data_dir()
+ .AppendASCII("good")
+ .AppendASCII("Extensions")
+ .AppendASCII("hpiknbiabeeppbpihjehijgoemciehgk")
+ .AppendASCII("2");
{
// It's OK to have duplicate URLs, so long as the IDs are different.
@@ -512,27 +516,60 @@ TEST_F(ExtensionInfoGeneratorUnitTest, GenerateExtensionsJSONData) {
// Test the safety check display strings
TEST_F(ExtensionInfoGeneratorUnitTest, SafetyCheckStringsTest) {
- CWSInfoService::CWSInfo cws_info;
- cws_info.is_present = true;
- cws_info.violation_type = CWSInfoService::CWSViolationType::kMalware;
- cws_info.unpublished_long_ago = true;
- developer::SafetyCheckStrings display_strings =
- CreateSafetyCheckDisplayStringTest(cws_info);
- EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SAFETY_CHECK_EXTENSIONS_MALWARE),
- display_strings.detail_string);
- cws_info.is_present = true;
- cws_info.violation_type = CWSInfoService::CWSViolationType::kPolicy;
- cws_info.unpublished_long_ago = true;
- display_strings = CreateSafetyCheckDisplayStringTest(cws_info);
- EXPECT_EQ(
- l10n_util::GetStringUTF8(IDS_SAFETY_CHECK_EXTENSIONS_POLICY_VIOLATION),
- display_strings.detail_string);
- cws_info.is_present = true;
- cws_info.violation_type = CWSInfoService::CWSViolationType::kNone;
- cws_info.unpublished_long_ago = true;
- display_strings = CreateSafetyCheckDisplayStringTest(cws_info);
- EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SAFETY_CHECK_EXTENSIONS_UNPUBLISHED),
- display_strings.detail_string);
+ {
+ CWSInfoService::CWSInfo cws_info;
+ cws_info.is_present = true;
+ cws_info.violation_type = CWSInfoService::CWSViolationType::kMalware;
+ cws_info.unpublished_long_ago = true;
+ developer::SafetyCheckStrings display_strings =
+ ExtensionInfoGenerator::CreateSafetyCheckDisplayString(
+ cws_info, developer::EXTENSION_STATE_DISABLED);
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SAFETY_CHECK_EXTENSIONS_MALWARE),
+ display_strings.detail_string);
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSIONS_SC_MALWARE),
+ display_strings.panel_string);
+ }
+ {
+ CWSInfoService::CWSInfo cws_info;
+ cws_info.is_present = true;
+ cws_info.violation_type = CWSInfoService::CWSViolationType::kPolicy;
+ cws_info.unpublished_long_ago = true;
+ developer::SafetyCheckStrings display_strings =
+ ExtensionInfoGenerator::CreateSafetyCheckDisplayString(
+ cws_info, developer::EXTENSION_STATE_DISABLED);
+ EXPECT_EQ(
+ l10n_util::GetStringUTF8(IDS_SAFETY_CHECK_EXTENSIONS_POLICY_VIOLATION),
+ display_strings.detail_string);
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSIONS_SC_POLICY_VIOLATION_OFF),
+ display_strings.panel_string);
+ }
+ {
+ CWSInfoService::CWSInfo cws_info;
+ cws_info.is_present = true;
+ cws_info.violation_type = CWSInfoService::CWSViolationType::kPolicy;
+ developer::SafetyCheckStrings display_strings =
+ ExtensionInfoGenerator::CreateSafetyCheckDisplayString(
+ cws_info, developer::EXTENSION_STATE_ENABLED);
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSIONS_SC_POLICY_VIOLATION_ON),
+ display_strings.panel_string);
+ }
+ {
+ CWSInfoService::CWSInfo cws_info;
+ cws_info.is_present = true;
+ cws_info.violation_type = CWSInfoService::CWSViolationType::kNone;
+ cws_info.unpublished_long_ago = true;
+ developer::SafetyCheckStrings display_strings =
+ ExtensionInfoGenerator::CreateSafetyCheckDisplayString(
+ cws_info, developer::EXTENSION_STATE_DISABLED);
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SAFETY_CHECK_EXTENSIONS_UNPUBLISHED),
+ display_strings.detail_string);
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSIONS_SC_UNPUBLISHED_OFF),
+ display_strings.panel_string);
+ display_strings = ExtensionInfoGenerator::CreateSafetyCheckDisplayString(
+ cws_info, developer::EXTENSION_STATE_ENABLED);
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSIONS_SC_UNPUBLISHED_ON),
+ display_strings.panel_string);
+ }
}
TEST_F(ExtensionInfoGeneratorUnitTest, SafetyCheckEmptyStringTest) {
@@ -541,7 +578,8 @@ TEST_F(ExtensionInfoGeneratorUnitTest, SafetyCheckEmptyStringTest) {
cws_info.violation_type = CWSInfoService::CWSViolationType::kNone;
cws_info.unpublished_long_ago = false;
developer::SafetyCheckStrings display_strings;
- display_strings = CreateSafetyCheckDisplayStringTest(cws_info);
+ display_strings = ExtensionInfoGenerator::CreateSafetyCheckDisplayString(
+ cws_info, developer::EXTENSION_STATE_DISABLED);
EXPECT_EQ(display_strings.detail_string, "");
EXPECT_EQ(display_strings.panel_string, "");
}
@@ -602,6 +640,7 @@ TEST_F(ExtensionInfoGeneratorUnitTest, RuntimeHostPermissions) {
"no urls", base::Value::List(), ManifestLocation::kInternal);
info = GenerateExtensionInfo(no_urls_extension->id());
EXPECT_FALSE(info->permissions.runtime_host_permissions);
+ EXPECT_FALSE(info->permissions.can_access_site_data);
}
// Tests that specific_site_controls is correctly populated when permissions
@@ -882,6 +921,27 @@ TEST_F(ExtensionInfoGeneratorUnitTest, ActiveTabFileUrls) {
EXPECT_FALSE(info->file_access.is_active);
}
+// Test that `permissions.can_access_site_data` is set to true for extensions
+// with API permissions that can access site data, without specifying host
+// permissions.
+TEST_F(ExtensionInfoGeneratorUnitTest,
+ CanAccessSiteDataWithoutHostPermissions) {
+ scoped_refptr<const Extension> active_tab_extension =
+ CreateExtension("activeTab", base::Value::List().Append("activeTab"),
+ ManifestLocation::kInternal);
+ scoped_refptr<const Extension> debugger_extension =
+ CreateExtension("activeTab", base::Value::List().Append("debugger"),
+ ManifestLocation::kInternal);
+
+ std::unique_ptr<developer::ExtensionInfo> active_tab_info =
+ GenerateExtensionInfo(active_tab_extension->id());
+ std::unique_ptr<developer::ExtensionInfo> debugger_info =
+ GenerateExtensionInfo(debugger_extension->id());
+
+ EXPECT_TRUE(active_tab_info->permissions.can_access_site_data);
+ EXPECT_TRUE(debugger_info->permissions.can_access_site_data);
+}
+
// Tests that blocklisted extensions are returned by the ExtensionInfoGenerator.
TEST_F(ExtensionInfoGeneratorUnitTest, Blocklisted) {
const scoped_refptr<const Extension> extension1 = CreateExtension(
@@ -911,6 +971,11 @@ TEST_F(ExtensionInfoGeneratorUnitTest, Blocklisted) {
ASSERT_NE(nullptr, info2);
EXPECT_EQ(developer::EXTENSION_STATE_BLACKLISTED, info1->state);
EXPECT_EQ(developer::EXTENSION_STATE_ENABLED, info2->state);
+
+ // Verify getExtensionInfo() returns data on blocklisted extensions.
+ auto info3 = GenerateExtensionInfo(id1);
+ ASSERT_NE(nullptr, info3);
+ EXPECT_EQ(developer::EXTENSION_STATE_BLACKLISTED, info3->state);
}
// Test generating extension action commands properly.
@@ -987,6 +1052,32 @@ TEST_F(ExtensionInfoGeneratorUnitTest,
EXPECT_FALSE(info->disable_reasons.parent_disabled_permissions);
}
+// Test that the generator returns if the extension can be pinned to the toolbar
+// and if it can, whether or not it's pinned.
+TEST_F(ExtensionInfoGeneratorUnitTest, IsPinnedToToolbar) {
+ // By default, the extension is not pinned to the toolbar but can be.
+ const scoped_refptr<const Extension> extension = CreateExtension(
+ "test1", base::Value::List(), ManifestLocation::kInternal);
+ std::unique_ptr<developer::ExtensionInfo> info =
+ GenerateExtensionInfo(extension->id());
+ EXPECT_FALSE(*info->pinned_to_toolbar);
+
+ // Pin the extension to the toolbar and test that this is reflected in the
+ // generated info.
+ ToolbarActionsModel* toolbar_actions_model =
+ ToolbarActionsModel::Get(profile());
+ toolbar_actions_model->SetActionVisibility(extension->id(), true);
+ info = GenerateExtensionInfo(extension->id());
+ EXPECT_TRUE(*info->pinned_to_toolbar);
+
+ // Disable the extension. Since disabled extensions have no action, the
+ // `pinned_to_toolbar` field should not exist.
+ service()->DisableExtension(extension->id(),
+ disable_reason::DISABLE_USER_ACTION);
+ info = GenerateExtensionInfo(extension->id());
+ EXPECT_FALSE(info->pinned_to_toolbar.has_value());
+}
+
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
// Tests for supervised users (child accounts). Supervised users are not allowed
// to install apps or extensions unless their parent approves.
diff --git a/chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index fc00e8031ce..ee717af4004 100644
--- a/chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/values.h"
+#include "chrome/browser/download/download_browsertest_utils.h"
#include "chrome/browser/extensions/api/downloads/downloads_api.h"
#include <stddef.h>
@@ -205,7 +206,7 @@ class DownloadsEventsListener : public EventRouter::TestObserver {
}
private:
- raw_ptr<Profile, DanglingUntriaged> profile_;
+ raw_ptr<Profile, AcrossTasksDanglingUntriaged> profile_;
std::string event_name_;
std::string json_args_;
base::Value args_;
@@ -231,7 +232,8 @@ class DownloadsEventsListener : public EventRouter::TestObserver {
}
// extensions::EventRouter::TestObserver:
- void OnDidDispatchEventToProcess(const extensions::Event& event) override {}
+ void OnDidDispatchEventToProcess(const extensions::Event& event,
+ int process_id) override {}
bool WaitFor(Profile* profile,
const std::string& event_name,
@@ -274,7 +276,7 @@ class DownloadsEventsListener : public EventRouter::TestObserver {
base::Time last_wait_;
std::unique_ptr<Event> waiting_for_;
base::circular_deque<std::unique_ptr<Event>> events_;
- raw_ptr<Profile, DanglingUntriaged> profile_;
+ raw_ptr<Profile, AcrossTasksDanglingUntriaged> profile_;
};
// Object waiting for a download open event.
@@ -420,6 +422,7 @@ class DownloadExtensionTest : public ExtensionApiTest {
DownloadTestFileActivityObserver observer(incognito_browser_->profile());
observer.EnableFileChooser(false);
}
+ SetPromptForDownload(incognito_browser_, false);
current_browser_ = incognito_browser_;
if (events_listener_.get())
events_listener_->UpdateProfile(current_browser()->profile());
@@ -758,8 +761,8 @@ class DownloadExtensionTest : public ExtensionApiTest {
raw_ptr<const Extension, DanglingUntriaged> extension_;
raw_ptr<const Extension, DanglingUntriaged> second_extension_;
- raw_ptr<Browser, DanglingUntriaged> incognito_browser_;
- raw_ptr<Browser, DanglingUntriaged> current_browser_;
+ raw_ptr<Browser, AcrossTasksDanglingUntriaged> incognito_browser_;
+ raw_ptr<Browser, AcrossTasksDanglingUntriaged> current_browser_;
std::unique_ptr<DownloadsEventsListener> events_listener_;
std::unique_ptr<net::test_server::ControllableHttpResponse> first_download_;
diff --git a/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash_unittest.cc b/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash_unittest.cc
index 65b7a109039..54dd7a0e223 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash_unittest.cc
@@ -71,6 +71,8 @@ class EnterpriseDeviceAttributesApiAshTest
DeviceSettingsTestBase::SetUp();
+ testing_profile_ = profile_manager_.CreateTestingProfile(kAccountId);
+
switch (GetParam()) {
case TestProfileChoice::kSigninProfile:
TestingProfile* signin_profile;
@@ -114,7 +116,7 @@ class EnterpriseDeviceAttributesApiAshTest
AccountId account_id = AccountId::FromUserEmail(kAccountId);
user_manager_->AddUserWithAffiliationAndTypeAndProfile(
account_id, is_affiliated, user_manager::USER_TYPE_REGULAR,
- profile_.get());
+ testing_profile_);
user_manager_->LoginUser(account_id);
}
@@ -128,8 +130,9 @@ class EnterpriseDeviceAttributesApiAshTest
}
}
- private:
+ protected:
TestingProfileManager profile_manager_;
+ raw_ptr<TestingProfile> testing_profile_;
std::unique_ptr<crosapi::CrosapiManager> manager_;
std::unique_ptr<policy::FakeDeviceAttributes> device_attributes_;
};
@@ -140,7 +143,7 @@ TEST_P(EnterpriseDeviceAttributesApiAshTest, GetDirectoryDeviceIdFunction) {
absl::optional<base::Value> result =
api_test_utils::RunFunctionAndReturnSingleResult(
- function.get(), /*args=*/"[]", profile_.get());
+ function.get(), /*args=*/"[]", testing_profile_);
ASSERT_TRUE(result->is_string());
EXPECT_EQ(
IsSigninProfileOrBelongsToAffiliatedUser() ? kFakeDirectoryApiId : "",
@@ -153,7 +156,7 @@ TEST_P(EnterpriseDeviceAttributesApiAshTest, GetDeviceSerialNumberFunction) {
absl::optional<base::Value> result =
api_test_utils::RunFunctionAndReturnSingleResult(
- function.get(), /*args=*/"[]", profile_.get());
+ function.get(), /*args=*/"[]", testing_profile_);
ASSERT_TRUE(result->is_string());
EXPECT_EQ(IsSigninProfileOrBelongsToAffiliatedUser() ? kFakeSerialNumber : "",
result->GetString());
@@ -165,7 +168,7 @@ TEST_P(EnterpriseDeviceAttributesApiAshTest, GetDeviceAssetIdFunction) {
absl::optional<base::Value> result =
api_test_utils::RunFunctionAndReturnSingleResult(
- function.get(), /*args=*/"[]", profile_.get());
+ function.get(), /*args=*/"[]", testing_profile_);
ASSERT_TRUE(result->is_string());
EXPECT_EQ(IsSigninProfileOrBelongsToAffiliatedUser() ? kFakeAssetId : "",
result->GetString());
@@ -178,7 +181,7 @@ TEST_P(EnterpriseDeviceAttributesApiAshTest,
absl::optional<base::Value> result =
api_test_utils::RunFunctionAndReturnSingleResult(
- function.get(), /*args=*/"[]", profile_.get());
+ function.get(), /*args=*/"[]", testing_profile_);
ASSERT_TRUE(result->is_string());
EXPECT_EQ(
IsSigninProfileOrBelongsToAffiliatedUser() ? kFakeAnnotatedLocation : "",
@@ -191,7 +194,7 @@ TEST_P(EnterpriseDeviceAttributesApiAshTest, GetDeviceHostnameFunction) {
absl::optional<base::Value> result =
api_test_utils::RunFunctionAndReturnSingleResult(
- function.get(), /*args=*/"[]", profile_.get());
+ function.get(), /*args=*/"[]", testing_profile_);
ASSERT_TRUE(result->is_string());
EXPECT_EQ(IsSigninProfileOrBelongsToAffiliatedUser() ? kFakeHostname : "",
result->GetString());
diff --git a/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_lacros_apitest.cc b/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_lacros_apitest.cc
index 26a26ad5314..20d4c806a37 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_lacros_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_lacros_apitest.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc b/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc
index a44a8347968..fd58a396cbb 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc
@@ -172,12 +172,13 @@ class EPKChallengeKeyTestBase : public BrowserWithTestWindowTest {
scoped_refptr<const extensions::Extension> extension_;
ash::StubInstallAttributes stub_install_attributes_;
// fake_user_manager_ is owned by user_manager_enabler_.
- raw_ptr<ash::FakeChromeUserManager, ExperimentalAsh> fake_user_manager_ =
- nullptr;
+ raw_ptr<ash::FakeChromeUserManager, DanglingUntriaged | ExperimentalAsh>
+ fake_user_manager_ = nullptr;
user_manager::ScopedUserManager user_manager_enabler_;
ash::platform_keys::MockKeyPermissionsManager key_permissions_manager_;
- raw_ptr<PrefService, ExperimentalAsh> prefs_ = nullptr;
- raw_ptr<ash::attestation::MockTpmChallengeKey, ExperimentalAsh>
+ raw_ptr<PrefService, DanglingUntriaged | ExperimentalAsh> prefs_ = nullptr;
+ raw_ptr<ash::attestation::MockTpmChallengeKey,
+ DanglingUntriaged | ExperimentalAsh>
mock_tpm_challenge_key_ = nullptr;
};
diff --git a/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc b/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
index 216beea8fd3..82f98dca30d 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc
@@ -26,6 +26,7 @@
#include "chrome/browser/net/nss_service_factory.h"
#include "chrome/browser/policy/extension_force_install_mixin.h"
#include "chrome/common/chrome_paths.h"
+#include "chromeos/ash/components/chaps_util/test_util.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -271,8 +272,7 @@ class EnterprisePlatformKeysTest
// Allows tests to generate software-backed keys by configuring fake ChapsUtil
// instances to be created in its constructor (and undoing the change in its
// destructor).
- ash::platform_keys::test_util::ScopedChapsUtilOverride
- scoped_chaps_util_override_;
+ chromeos::ScopedChapsUtilOverride scoped_chaps_util_override_;
};
} // namespace
@@ -446,8 +446,7 @@ class EnterprisePlatformKeysLoginScreenTest
// Allows tests to generate software-backed keys by configuring fake ChapsUtil
// instances to be created in its constructor (and undoing the change in its
// destructor).
- ash::platform_keys::test_util::ScopedChapsUtilOverride
- scoped_chaps_util_override_;
+ chromeos::ScopedChapsUtilOverride scoped_chaps_util_override_;
};
IN_PROC_BROWSER_TEST_P(EnterprisePlatformKeysLoginScreenTest, Basic) {
diff --git a/chromium/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc b/chromium/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
index cd924613ff0..7b32da90c64 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
@@ -73,10 +73,10 @@ class EPKPChallengeKeyTestBase : public BrowserWithTestWindowTest {
scoped_refptr<const Extension> extension_;
// fake_user_manager_ is owned by user_manager_enabler_.
- raw_ptr<ash::FakeChromeUserManager, ExperimentalAsh> fake_user_manager_ =
- nullptr;
+ raw_ptr<ash::FakeChromeUserManager, DanglingUntriaged | ExperimentalAsh>
+ fake_user_manager_ = nullptr;
user_manager::ScopedUserManager user_manager_enabler_;
- raw_ptr<PrefService, ExperimentalAsh> prefs_ = nullptr;
+ raw_ptr<PrefService, DanglingUntriaged | ExperimentalAsh> prefs_ = nullptr;
};
class EPKPChallengeMachineKeyTest : public EPKPChallengeKeyTestBase {
diff --git a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.cc b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.cc
index bf62e292d1d..d652d410065 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.cc
@@ -30,7 +30,7 @@
#endif
#if BUILDFLAG(IS_MAC)
-#include "base/mac/foundation_util.h"
+#include "base/apple/foundation_util.h"
#include "chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.h"
#include "crypto/apple_keychain.h"
#endif
@@ -170,7 +170,7 @@ int32_t ReadEncryptedSecret(std::string* password, bool force_recreate) {
crypto::AppleKeychain keychain;
UInt32 password_length = 0;
void* password_data = nullptr;
- base::ScopedCFTypeRef<SecKeychainItemRef> item_ref;
+ base::apple::ScopedCFTypeRef<SecKeychainItemRef> item_ref;
status = keychain.FindGenericPassword(
strlen(kServiceName), kServiceName, strlen(kAccountName), kAccountName,
&password_length, &password_data, item_ref.InitializeInto());
diff --git a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc
index 3cbbdf4cb79..594b680912d 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc
@@ -590,7 +590,7 @@ IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest,
kOptions = base::StringPrintf(
R"(
- const test_hive = 'HKEY_LOCAL_MACHINE';
+ const test_hive = 'HKEY_CURRENT_USER';
const registry_path = '%s';
const invalid_path = 'SOFTWARE\\Chromium\\DeviceTrust\\Invalid';
const valid_key = '%s';
@@ -624,9 +624,9 @@ IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest,
registry_path.c_str(), valid_key.c_str());
registry_util::RegistryOverrideManager registry_override_manager_;
- registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE);
+ registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
- base::win::RegKey key(HKEY_LOCAL_MACHINE,
+ base::win::RegKey key(HKEY_CURRENT_USER,
base::SysUTF8ToWide(registry_path).c_str(),
KEY_ALL_ACCESS);
ASSERT_TRUE(key.WriteValue(base::SysUTF8ToWide(valid_key).c_str(), 37) ==
diff --git a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.cc b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.cc
index 7841b19868e..d09fabda838 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.cc
@@ -7,8 +7,8 @@
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_cftyperef.h"
+#include "base/apple/foundation_util.h"
+#include "base/apple/scoped_cftyperef.h"
#include "base/strings/sys_string_conversions.h"
namespace extensions {
@@ -30,7 +30,7 @@ OSStatus CreateTargetAccess(CFStringRef service_name,
return status;
}
- base::ScopedCFTypeRef<CFArrayRef> acl_list;
+ base::apple::ScopedCFTypeRef<CFArrayRef> acl_list;
status = SecAccessCopyACLList(*access_ref, acl_list.InitializeInto());
if (status != noErr) {
return status;
@@ -39,8 +39,8 @@ OSStatus CreateTargetAccess(CFStringRef service_name,
for (CFIndex i = 0; i < CFArrayGetCount(acl_list); ++i) {
SecACLRef acl = (SecACLRef)CFArrayGetValueAtIndex(acl_list, i);
- base::ScopedCFTypeRef<CFArrayRef> app_list;
- base::ScopedCFTypeRef<CFStringRef> description;
+ base::apple::ScopedCFTypeRef<CFArrayRef> app_list;
+ base::apple::ScopedCFTypeRef<CFStringRef> description;
SecKeychainPromptSelector dummy_prompt_selector;
status = SecACLCopyContents(acl, app_list.InitializeInto(),
description.InitializeInto(),
@@ -93,7 +93,7 @@ OSStatus WriteKeychainItem(const std::string& service_name,
const_cast<char*>(account_name.data())}};
SecKeychainAttributeList attribute_list = {std::size(attributes), attributes};
- base::ScopedCFTypeRef<SecAccessRef> access_ref;
+ base::apple::ScopedCFTypeRef<SecAccessRef> access_ref;
OSStatus status = CreateTargetAccess(base::SysUTF8ToCFStringRef(service_name),
access_ref.InitializeInto());
if (status != noErr) {
@@ -107,7 +107,7 @@ OSStatus WriteKeychainItem(const std::string& service_name,
OSStatus VerifyKeychainForItemUnlocked(SecKeychainItemRef item_ref,
bool* unlocked) {
- base::ScopedCFTypeRef<SecKeychainRef> keychain;
+ base::apple::ScopedCFTypeRef<SecKeychainRef> keychain;
OSStatus status =
SecKeychainItemCopyKeychain(item_ref, keychain.InitializeInto());
if (status != noErr) {
@@ -118,7 +118,7 @@ OSStatus VerifyKeychainForItemUnlocked(SecKeychainItemRef item_ref,
}
OSStatus VerifyDefaultKeychainUnlocked(bool* unlocked) {
- base::ScopedCFTypeRef<SecKeychainRef> keychain;
+ base::apple::ScopedCFTypeRef<SecKeychainRef> keychain;
OSStatus status = SecKeychainCopyDefault(keychain.InitializeInto());
if (status != noErr) {
return status;
diff --git a/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc b/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
index 5c3f547ae65..079f1f43e07 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
+++ b/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
@@ -858,8 +858,9 @@ IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveFencedFrameTest,
manager->GetRenderFrameHostsForExtension(extension->id());
const auto& it = base::ranges::find_if(
hosts, &content::RenderFrameHost::IsInPrimaryMainFrame);
- content::RenderFrameHost* primary_rfh = (it != hosts.end()) ? *it : nullptr;
- ASSERT_TRUE(primary_rfh);
+ content::RenderFrameHost* primary_render_frame_host =
+ (it != hosts.end()) ? *it : nullptr;
+ ASSERT_TRUE(primary_render_frame_host);
// Navigate the popup's fenced frame to a (cross-site) web page via its
// parent, and wait for that page to send a message, which will ensure that
@@ -867,19 +868,20 @@ IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveFencedFrameTest,
GURL foo_url(https_server.GetURL("a.test", "/popup_fencedframe.html"));
content::TestNavigationObserver observer(
- content::WebContents::FromRenderFrameHost(primary_rfh));
+ content::WebContents::FromRenderFrameHost(primary_render_frame_host));
std::string script =
"document.querySelector('fencedframe').config = new FencedFrameConfig('" +
foo_url.spec() + "')";
- EXPECT_TRUE(ExecJs(primary_rfh, script));
+ EXPECT_TRUE(ExecJs(primary_render_frame_host, script));
observer.WaitForNavigationFinished();
- content::RenderFrameHost* fenced_frame_rfh =
- fenced_frame_test_helper().GetMostRecentlyAddedFencedFrame(primary_rfh);
- ASSERT_TRUE(fenced_frame_rfh);
+ content::RenderFrameHost* fenced_frame_render_frame_host =
+ fenced_frame_test_helper().GetMostRecentlyAddedFencedFrame(
+ primary_render_frame_host);
+ ASSERT_TRUE(fenced_frame_render_frame_host);
// Confirm that the new page (popup_fencedframe.html) is actually loaded.
- content::DOMMessageQueue dom_message_queue(fenced_frame_rfh);
+ content::DOMMessageQueue dom_message_queue(fenced_frame_render_frame_host);
std::string json;
EXPECT_TRUE(dom_message_queue.WaitForMessage(&json));
EXPECT_EQ("\"DONE\"", json);
diff --git a/chromium/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc b/chromium/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
index 0ca967e7b98..d268ada6388 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
@@ -23,6 +23,7 @@
#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/sessions/content/session_tab_helper.h"
+#include "components/version_info/channel.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
@@ -33,10 +34,12 @@
#include "extensions/browser/extension_action_manager.h"
#include "extensions/browser/extension_icon_image.h"
#include "extensions/browser/process_manager.h"
+#include "extensions/browser/service_worker/service_worker_test_utils.h"
#include "extensions/browser/state_store.h"
#include "extensions/common/api/extension_action/action_info.h"
#include "extensions/common/api/extension_action/action_info_test_util.h"
#include "extensions/common/extension.h"
+#include "extensions/common/features/feature_channel.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"
@@ -104,7 +107,7 @@ class TestStateStoreObserver : public StateStore::TestObserver {
}
private:
- std::string extension_id_;
+ ExtensionId extension_id_;
std::map<std::string, int> updated_values_;
base::ScopedObservation<StateStore, StateStore::TestObserver>
@@ -1869,6 +1872,73 @@ IN_PROC_BROWSER_TEST_P(ActionAndBrowserActionAPITest,
EXPECT_EQ("", action->GetExplicitlySetBadgeText(tab_id2));
}
+class ExtensionActionStableChannelApiTest : public ExtensionActionAPITest {
+ public:
+ ExtensionActionStableChannelApiTest() = default;
+ ~ExtensionActionStableChannelApiTest() override = default;
+
+ private:
+ ScopedCurrentChannel scoped_current_channel_{version_info::Channel::STABLE};
+};
+
+// Tests that the action.openPopup() API is available to policy-installed
+// extensions on stable. Since this is controlled through our features files
+// (which are tested separately), this is more of a smoke test than an
+// end-to-end test.
+// TODO(https://crbug.com/1245093): Remove this test when the API is available
+// for all extensions on stable.
+IN_PROC_BROWSER_TEST_F(ExtensionActionStableChannelApiTest,
+ OpenPopupAvailabilityOnStableChannel) {
+ TestExtensionDir test_dir;
+ static constexpr char kManifest[] =
+ R"({
+ "name": "Test",
+ "manifest_version": 3,
+ "version": "0.1",
+ "background": {"service_worker": "background.js"},
+ "action": {}
+ })";
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
+ "chrome.test.sendMessage('ready');");
+
+ auto is_open_popup_defined = [this](const Extension& extension) {
+ static constexpr char kScript[] =
+ R"(chrome.test.sendScriptResult(!!chrome.action.openPopup);)";
+ return BackgroundScriptExecutor::ExecuteScript(
+ profile(), extension.id(), kScript,
+ BackgroundScriptExecutor::ResultCapture::kSendScriptResult);
+ };
+
+ // Technically, we don't need the "ready" listener here, but this ensures we
+ // don't cross streams with the policy extension loaded below (where we do
+ // need the listener).
+ ExtensionTestMessageListener non_policy_listener("ready");
+ const Extension* non_policy_extension =
+ LoadExtension(test_dir.UnpackedPath());
+ ASSERT_TRUE(non_policy_extension);
+ ASSERT_TRUE(non_policy_listener.WaitUntilSatisfied());
+
+ // Somewhat annoying: due to how our test helpers are written,
+ // `EXPECT_EQ(false, base::Value)` works, but EXPECT_FALSE(base::Value) does
+ // not.
+ EXPECT_EQ(false, is_open_popup_defined(*non_policy_extension));
+
+ // Unlike `LoadExtension()`, `InstallExtension()` doesn't wait for the service
+ // worker to be ready, so we need a few manual waiters.
+ base::FilePath packed_path = test_dir.Pack();
+ service_worker_test_utils::TestRegistrationObserver registration_observer(
+ profile());
+ ExtensionTestMessageListener policy_listener("ready");
+ const Extension* policy_extension = InstallExtension(
+ packed_path, 1, mojom::ManifestLocation::kExternalPolicyDownload);
+ ASSERT_TRUE(policy_extension);
+ ASSERT_TRUE(policy_listener.WaitUntilSatisfied());
+ registration_observer.WaitForRegistrationStored();
+
+ EXPECT_EQ(true, is_open_popup_defined(*policy_extension));
+}
+
INSTANTIATE_TEST_SUITE_P(All,
MultiActionAPITest,
testing::Values(ActionInfo::TYPE_ACTION,
diff --git a/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
index eb76373357c..115b9112f04 100644
--- a/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
+++ b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc
@@ -32,7 +32,7 @@
#if BUILDFLAG(IS_MAC)
#include <CoreFoundation/CoreFoundation.h>
-#include "base/mac/foundation_util.h"
+#include "base/apple/foundation_util.h"
#endif
#if BUILDFLAG(IS_CHROMEOS)
diff --git a/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.cc b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.cc
index 219218e4914..403dac6742b 100644
--- a/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.cc
+++ b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.cc
@@ -12,6 +12,7 @@
#include "base/functional/callback.h"
#include "base/path_service.h"
#include "chrome/browser/ash/file_manager/volume_manager.h"
+#include "chrome/browser/ash/fileapi/file_system_backend.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/child_process_security_policy.h"
@@ -25,7 +26,6 @@
#include "extensions/browser/extension_util.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
-#include "storage/browser/file_system/file_system_backend.h"
#include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_url.h"
#include "storage/browser/file_system/isolated_context.h"
@@ -91,8 +91,7 @@ void OnConsentReceived(content::BrowserContext* browser_context,
scoped_refptr<storage::FileSystemContext> file_system_context =
util::GetStoragePartitionForExtensionId(origin.host(), browser_context)
->GetFileSystemContext();
- storage::ExternalFileSystemBackend* const backend =
- file_system_context->external_backend();
+ auto* const backend = ash::FileSystemBackend::Get(*file_system_context);
DCHECK(backend);
base::FilePath virtual_path;
@@ -225,8 +224,7 @@ void ChromeFileSystemDelegateAsh::RequestFileSystem(
scoped_refptr<storage::FileSystemContext> file_system_context =
util::GetStoragePartitionForExtensionId(extension.id(), browser_context)
->GetFileSystemContext();
- storage::ExternalFileSystemBackend* const backend =
- file_system_context->external_backend();
+ auto* const backend = ash::FileSystemBackend::Get(*file_system_context);
DCHECK(backend);
base::FilePath virtual_path;
diff --git a/chromium/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc b/chromium/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc
index 8c0f3be44b1..7cf734507db 100644
--- a/chromium/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc
@@ -123,13 +123,13 @@ class FileSystemApiConsentProviderTest : public testing::Test {
void TearDown() override {
scoped_user_manager_enabler_.reset();
user_manager_ = nullptr;
- testing_pref_service_.reset();
TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
+ testing_pref_service_.reset();
}
protected:
std::unique_ptr<TestingPrefServiceSimple> testing_pref_service_;
- raw_ptr<ash::FakeChromeUserManager, ExperimentalAsh>
+ raw_ptr<ash::FakeChromeUserManager, DanglingUntriaged | ExperimentalAsh>
user_manager_; // Owned by the scope enabler.
std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_enabler_;
content::BrowserTaskEnvironment task_environment_;
diff --git a/chromium/chrome/browser/extensions/api/file_system/file_entry_picker.cc b/chromium/chrome/browser/extensions/api/file_system/file_entry_picker.cc
index 0b1b8777b0c..deeba61820c 100644
--- a/chromium/chrome/browser/extensions/api/file_system/file_entry_picker.cc
+++ b/chromium/chrome/browser/extensions/api/file_system/file_entry_picker.cc
@@ -41,7 +41,9 @@ FileEntryPicker::FileEntryPicker(
base::FilePath::StringType(), owning_window, /*params=*/nullptr, caller);
}
-FileEntryPicker::~FileEntryPicker() = default;
+FileEntryPicker::~FileEntryPicker() {
+ select_file_dialog_->ListenerDestroyed();
+}
void FileEntryPicker::FileSelected(const base::FilePath& path,
int index,
diff --git a/chromium/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc b/chromium/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
index d925aefc663..55ebcb0b37f 100644
--- a/chromium/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
+++ b/chromium/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc
@@ -104,7 +104,7 @@ class ScopedAddListenerObserver : public EventRouter::Observer {
}
private:
- const std::string extension_id_;
+ const ExtensionId extension_id_;
base::OnceClosure callback_;
const raw_ptr<EventRouter, ExperimentalAsh> event_router_;
};
@@ -189,7 +189,7 @@ class FileSystemApiTestForDrive : public PlatformAppBrowserTest {
base::ScopedTempDir drivefs_root_;
base::FilePath drivefs_mount_point_;
std::unique_ptr<drive::FakeDriveFsHelper> fake_drivefs_helper_;
- raw_ptr<drive::DriveIntegrationService, ExperimentalAsh>
+ raw_ptr<drive::DriveIntegrationService, DanglingUntriaged | ExperimentalAsh>
integration_service_ = nullptr;
drive::DriveIntegrationServiceFactory::FactoryCallback
create_drive_integration_service_;
@@ -245,7 +245,8 @@ class FileSystemApiTestForRequestFileSystem : public PlatformAppBrowserTest {
protected:
base::ScopedTempDir temp_dir_;
- raw_ptr<ash::FakeChromeUserManager, ExperimentalAsh> fake_user_manager_;
+ raw_ptr<ash::FakeChromeUserManager, DanglingUntriaged | ExperimentalAsh>
+ fake_user_manager_;
std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
// Creates a testing file system in a testing directory.
diff --git a/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.cc b/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.cc
index 566480dfdbf..6c46d85d16f 100644
--- a/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.cc
+++ b/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.cc
@@ -38,6 +38,7 @@
#include "extensions/browser/extension_prefs_helper.h"
#include "extensions/browser/extension_prefs_helper_factory.h"
#include "extensions/browser/extension_system.h"
+#include "extensions/common/api/types.h"
#include "extensions/common/error_utils.h"
#if BUILDFLAG(IS_WIN)
@@ -47,6 +48,7 @@
namespace extensions {
namespace fonts = api::font_settings;
+using extensions::api::types::ChromeSettingScope;
namespace {
@@ -278,7 +280,7 @@ ExtensionFunction::ResponseAction FontSettingsClearFontFunction::Run() {
EXTENSION_FUNCTION_VALIDATE(profile->GetPrefs()->FindPreference(pref_path));
ExtensionPrefsHelper::Get(profile)->RemoveExtensionControlledPref(
- extension_id(), pref_path, kExtensionPrefsScopeRegular);
+ extension_id(), pref_path, ChromeSettingScope::kRegular);
return RespondNow(NoArguments());
}
@@ -332,7 +334,7 @@ ExtensionFunction::ResponseAction FontSettingsSetFontFunction::Run() {
EXTENSION_FUNCTION_VALIDATE(profile->GetPrefs()->FindPreference(pref_path));
ExtensionPrefsHelper::Get(profile)->SetExtensionControlledPref(
- extension_id(), pref_path, kExtensionPrefsScopeRegular,
+ extension_id(), pref_path, ChromeSettingScope::kRegular,
base::Value(params->details.font_id));
return RespondNow(NoArguments());
}
@@ -383,7 +385,7 @@ ExtensionFunction::ResponseAction ClearFontPrefExtensionFunction::Run() {
return RespondNow(Error(kSetFromIncognitoError));
ExtensionPrefsHelper::Get(profile)->RemoveExtensionControlledPref(
- extension_id(), GetPrefName(), kExtensionPrefsScopeRegular);
+ extension_id(), GetPrefName(), ChromeSettingScope::kRegular);
return RespondNow(NoArguments());
}
@@ -419,7 +421,7 @@ ExtensionFunction::ResponseAction SetFontPrefExtensionFunction::Run() {
EXTENSION_FUNCTION_VALIDATE(value);
ExtensionPrefsHelper::Get(profile)->SetExtensionControlledPref(
- extension_id(), GetPrefName(), kExtensionPrefsScopeRegular,
+ extension_id(), GetPrefName(), ChromeSettingScope::kRegular,
value->Clone());
return RespondNow(NoArguments());
}
diff --git a/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc b/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
index f7a31c16327..593f8c1cbe4 100644
--- a/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
+++ b/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc
@@ -6,26 +6,16 @@
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
-#include "base/strings/escape.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/extensions/api/identity/identity_api.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/account_consistency_mode_manager.h"
-#include "chrome/browser/signin/account_reconcilor_factory.h"
#include "chrome/browser/signin/google_accounts_private_api_host.h"
#include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/common/chrome_features.h"
-#include "components/signin/core/browser/account_reconcilor.h"
-#include "components/signin/public/base/multilogin_parameters.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
-#include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h"
#include "content/public/browser/storage_partition.h"
-#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "google_apis/gaia/gaia_auth_util.h"
-#include "google_apis/gaia/gaia_urls.h"
#include "net/cookies/cookie_util.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
-#include "url/gurl.h"
#include "url/url_constants.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -67,29 +57,11 @@ GaiaRemoteConsentFlow::~GaiaRemoteConsentFlow() {
void GaiaRemoteConsentFlow::Start() {
if (!web_flow_) {
- web_flow_ = std::make_unique<WebAuthFlow>(
- this, profile_, resolution_data_.url, WebAuthFlow::INTERACTIVE,
- WebAuthFlow::GET_AUTH_TOKEN, user_gesture_);
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
- // `profile_` may be nullptr in tests.
- if (profile_ &&
- !base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab)) {
- AccountReconcilorFactory::GetForProfile(profile_)
- ->GetConsistencyCookieManager()
- ->AddExtraCookieManager(GetCookieManagerForPartition());
- }
-#endif
+ web_flow_ =
+ std::make_unique<WebAuthFlow>(this, profile_, resolution_data_.url,
+ WebAuthFlow::INTERACTIVE, user_gesture_);
}
- if (base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab)) {
- StartWebFlow();
- return;
- }
-
- SetAccountsInCookie();
-}
-
-void GaiaRemoteConsentFlow::StartWebFlow() {
network::mojom::CookieManager* cookie_manager =
GetCookieManagerForPartition();
net::CookieOptions options;
@@ -104,34 +76,6 @@ void GaiaRemoteConsentFlow::StartWebFlow() {
web_flow_started_ = true;
}
-void GaiaRemoteConsentFlow::OnSetAccountsComplete(
- signin::SetAccountsInCookieResult result) {
- // No need to inject account cookies when the flow is displayed in a browser
- // tab.
- DCHECK(!base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab));
-
- set_accounts_in_cookie_task_.reset();
- if (web_flow_started_) {
- return;
- }
-
- if (result != signin::SetAccountsInCookieResult::kSuccess) {
- GaiaRemoteConsentFlowFailed(
- GaiaRemoteConsentFlow::Failure::SET_ACCOUNTS_IN_COOKIE_FAILED);
- return;
- }
-
- identity_api_set_consent_result_subscription_ =
- IdentityAPI::GetFactoryInstance()
- ->Get(profile_)
- ->RegisterOnSetConsentResultCallback(
- base::BindRepeating(&GaiaRemoteConsentFlow::OnConsentResultSet,
- base::Unretained(this)));
-
- scoped_observation_.Observe(IdentityManagerFactory::GetForProfile(profile_));
- StartWebFlow();
-}
-
void GaiaRemoteConsentFlow::ReactToConsentResult(
const std::string& consent_result) {
bool consent_approved = false;
@@ -151,21 +95,6 @@ void GaiaRemoteConsentFlow::ReactToConsentResult(
delegate_->OnGaiaRemoteConsentFlowApproved(consent_result, gaia_id);
}
-void GaiaRemoteConsentFlow::OnConsentResultSet(
- const std::string& consent_result,
- const std::string& window_id) {
- // JS hook in a browser tab calls `ReactToConsentResult()` directly.
- DCHECK(!base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab));
-
- if (!web_flow_ || window_id != web_flow_->GetAppWindowKey()) {
- return;
- }
-
- identity_api_set_consent_result_subscription_ = {};
-
- ReactToConsentResult(consent_result);
-}
-
void GaiaRemoteConsentFlow::OnAuthFlowFailure(WebAuthFlow::Failure failure) {
GaiaRemoteConsentFlow::Failure gaia_failure;
@@ -173,9 +102,6 @@ void GaiaRemoteConsentFlow::OnAuthFlowFailure(WebAuthFlow::Failure failure) {
case WebAuthFlow::WINDOW_CLOSED:
gaia_failure = GaiaRemoteConsentFlow::WINDOW_CLOSED;
break;
- case WebAuthFlow::USER_NAVIGATED_AWAY:
- gaia_failure = GaiaRemoteConsentFlow::USER_NAVIGATED_AWAY;
- break;
case WebAuthFlow::LOAD_FAILED:
case WebAuthFlow::TIMED_OUT:
gaia_failure = GaiaRemoteConsentFlow::LOAD_FAILED;
@@ -192,115 +118,22 @@ void GaiaRemoteConsentFlow::OnAuthFlowFailure(WebAuthFlow::Failure failure) {
GaiaRemoteConsentFlowFailed(gaia_failure);
}
-content::StoragePartition* GaiaRemoteConsentFlow::GetStoragePartition() {
- content::StoragePartition* storage_partition = web_flow_->GetGuestPartition();
- if (!storage_partition) {
- // `web_flow_` doesn't have a guest partition only when the Auth Through
- // Browser Tab flow is used.
- DCHECK(base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab));
- storage_partition = profile_->GetDefaultStoragePartition();
- }
-
- return storage_partition;
-}
-
-std::unique_ptr<GaiaAuthFetcher>
-GaiaRemoteConsentFlow::CreateGaiaAuthFetcherForPartition(
- GaiaAuthConsumer* consumer,
- const gaia::GaiaSource& source) {
- return std::make_unique<GaiaAuthFetcher>(
- consumer, source,
- GetStoragePartition()->GetURLLoaderFactoryForBrowserProcess());
-}
-
network::mojom::CookieManager*
GaiaRemoteConsentFlow::GetCookieManagerForPartition() {
- return GetStoragePartition()->GetCookieManagerForBrowserProcess();
-}
-
-void GaiaRemoteConsentFlow::OnEndBatchOfRefreshTokenStateChanges() {
- // No need to copy added accounts when showing the flow in a browser tab.
- DCHECK(!base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab));
-
-// On ChromeOS, new accounts are added through the account manager. They need to
-// be pushed to the partition used by this flow explicitly.
-// On Desktop, sign-in happens on the Web and a new account is directly added to
-// this partition's cookie jar. An extra update triggered from here might change
-// cookies order in the middle of the flow. This may lead to a bug like
-// https://crbug.com/1112343.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- DCHECK(ash::IsAccountManagerAvailable(profile_));
- SetAccountsInCookie();
-#elif BUILDFLAG(IS_CHROMEOS_LACROS)
- if (AccountConsistencyModeManager::IsMirrorEnabledForProfile(profile_))
- SetAccountsInCookie();
-#endif
+ return profile_->GetDefaultStoragePartition()
+ ->GetCookieManagerForBrowserProcess();
}
void GaiaRemoteConsentFlow::SetWebAuthFlowForTesting(
std::unique_ptr<WebAuthFlow> web_auth_flow) {
DetachWebAuthFlow();
web_flow_ = std::move(web_auth_flow);
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
- // `profile_` may be nullptr in tests.
- if (profile_) {
- AccountReconcilorFactory::GetForProfile(profile_)
- ->GetConsistencyCookieManager()
- ->AddExtraCookieManager(GetCookieManagerForPartition());
- }
-#endif
}
WebAuthFlow* GaiaRemoteConsentFlow::GetWebAuthFlowForTesting() const {
return web_flow_.get();
}
-void GaiaRemoteConsentFlow::SetAccountsInCookie() {
- // No need to inject account cookies when the flow is displayed in a browser
- // tab.
- DCHECK(!base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab));
-
- // Reset a task that is already in flight because it contains stale
- // information.
- if (set_accounts_in_cookie_task_)
- set_accounts_in_cookie_task_.reset();
-
- auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_);
- std::vector<CoreAccountId> accounts;
- if (IdentityAPI::GetFactoryInstance()
- ->Get(profile_)
- ->AreExtensionsRestrictedToPrimaryAccount()) {
- CoreAccountId primary_account_id =
- identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSync);
- accounts.push_back(primary_account_id);
- } else {
- auto chrome_accounts_with_refresh_tokens =
- identity_manager->GetAccountsWithRefreshTokens();
- for (const auto& chrome_account : chrome_accounts_with_refresh_tokens) {
- // An account in persistent error state would make multilogin fail.
- // Showing only a subset of accounts seems to be a better alternative than
- // failing with an error.
- if (identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
- chrome_account.account_id)) {
- continue;
- }
- accounts.push_back(chrome_account.account_id);
- }
- }
-
- // base::Unretained() is safe here because this class owns
- // |set_accounts_in_cookie_task_| that will eventually invoke this callback.
- set_accounts_in_cookie_task_ =
- identity_manager->GetAccountsCookieMutator()
- ->SetAccountsInCookieForPartition(
- this,
- {gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER,
- accounts},
- gaia::GaiaSource::kChrome,
- base::BindOnce(&GaiaRemoteConsentFlow::OnSetAccountsComplete,
- base::Unretained(this)));
-}
-
void GaiaRemoteConsentFlow::GaiaRemoteConsentFlowFailed(Failure failure) {
RecordResultHistogram(failure);
delegate_->OnGaiaRemoteConsentFlowFailed(failure);
@@ -310,26 +143,11 @@ void GaiaRemoteConsentFlow::DetachWebAuthFlow() {
if (!web_flow_)
return;
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
- // `profile_` may be nullptr in tests.
- if (profile_ &&
- !base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab)) {
- AccountReconcilorFactory::GetForProfile(profile_)
- ->GetConsistencyCookieManager()
- ->RemoveExtraCookieManager(GetCookieManagerForPartition());
- }
-#endif
web_flow_.release()->DetachDelegateAndDelete();
}
void GaiaRemoteConsentFlow::OnNavigationFinished(
content::NavigationHandle* navigation_handle) {
- // No need to create the receiver if we are not displaying the auth page
- // through a Browser Tgab.
- if (!base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab)) {
- return;
- }
-
GoogleAccountsPrivateApiHost::CreateReceiver(
base::BindRepeating(&GaiaRemoteConsentFlow::ReactToConsentResult,
weak_factory.GetWeakPtr()),
diff --git a/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h b/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
index e316a1dba95..b25f8fcd0fe 100644
--- a/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
+++ b/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h
@@ -5,26 +5,17 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_IDENTITY_GAIA_REMOTE_CONSENT_FLOW_H_
#define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_GAIA_REMOTE_CONSENT_FLOW_H_
-#include "base/callback_list.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
-#include "base/scoped_observation.h"
#include "chrome/browser/extensions/api/identity/extension_token_key.h"
#include "chrome/browser/extensions/api/identity/web_auth_flow.h"
#include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
-#include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h"
#include "content/public/browser/storage_partition.h"
-#include "google_apis/gaia/core_account_id.h"
-#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_mint_token_flow.h"
namespace extensions {
-class GaiaRemoteConsentFlow
- : public WebAuthFlow::Delegate,
- public signin::AccountsCookieMutator::PartitionDelegate,
- public signin::IdentityManager::Observer {
+class GaiaRemoteConsentFlow : public WebAuthFlow::Delegate {
public:
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
@@ -32,10 +23,12 @@ class GaiaRemoteConsentFlow
NONE = 0,
WINDOW_CLOSED = 1,
LOAD_FAILED = 2,
- SET_ACCOUNTS_IN_COOKIE_FAILED = 3,
+ // Deprecated:
+ // SET_ACCOUNTS_IN_COOKIE_FAILED = 3,
INVALID_CONSENT_RESULT = 4,
NO_GRANT = 5,
- USER_NAVIGATED_AWAY = 6,
+ // Deprecated:
+ // USER_NAVIGATED_AWAY = 6,
CANNOT_CREATE_WINDOW = 7,
kMaxValue = CANNOT_CREATE_WINDOW
};
@@ -65,14 +58,6 @@ class GaiaRemoteConsentFlow
// Starts the flow by setting accounts in cookie.
void Start();
- // Set accounts in cookie completion callback.
- void OnSetAccountsComplete(signin::SetAccountsInCookieResult result);
-
- // setConsentResult() JavaScript callback when using an App Window to display
- // the Auth page.
- void OnConsentResultSet(const std::string& consent_result,
- const std::string& window_id);
-
// Handles `consent_result` value when using either a Browser Tab or an App
// Window to display the Auth page.
void ReactToConsentResult(const std::string& consent_result);
@@ -82,29 +67,15 @@ class GaiaRemoteConsentFlow
void OnNavigationFinished(
content::NavigationHandle* navigation_handle) override;
- // signin::AccountsCookieMutator::PartitionDelegate:
- std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcherForPartition(
-
- GaiaAuthConsumer* consumer,
- const gaia::GaiaSource& source) override;
- network::mojom::CookieManager* GetCookieManagerForPartition() override;
-
- // signin::IdentityManager::Observer:
- void OnEndBatchOfRefreshTokenStateChanges() override;
-
void SetWebAuthFlowForTesting(std::unique_ptr<WebAuthFlow> web_auth_flow);
WebAuthFlow* GetWebAuthFlowForTesting() const;
private:
- void StartWebFlow();
-
- void SetAccountsInCookie();
-
void GaiaRemoteConsentFlowFailed(Failure failure);
void DetachWebAuthFlow();
- content::StoragePartition* GetStoragePartition();
+ network::mojom::CookieManager* GetCookieManagerForPartition();
const raw_ptr<Delegate> delegate_;
const raw_ptr<Profile> profile_;
@@ -114,13 +85,6 @@ class GaiaRemoteConsentFlow
std::unique_ptr<WebAuthFlow> web_flow_;
bool web_flow_started_;
- std::unique_ptr<signin::AccountsCookieMutator::SetAccountsInCookieTask>
- set_accounts_in_cookie_task_;
- base::CallbackListSubscription identity_api_set_consent_result_subscription_;
- base::ScopedObservation<signin::IdentityManager,
- signin::IdentityManager::Observer>
- scoped_observation_{this};
-
base::WeakPtrFactory<GaiaRemoteConsentFlow> weak_factory{this};
};
diff --git a/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_browsertest.cc b/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_browsertest.cc
index 0a0d118c20f..82d8d84bd83 100644
--- a/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_browsertest.cc
@@ -5,11 +5,9 @@
#include "chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h"
#include "base/strings/strcat.h"
-#include "chrome/browser/extensions/api/identity/identity_private_api.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/common/chrome_features.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/signin/public/base/consent_level.h"
#include "components/signin/public/identity_manager/identity_manager.h"
@@ -17,7 +15,6 @@
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
-#include "extensions/browser/api_test_utils.h"
#include "google_apis/gaia/core_account_id.h"
#include "google_apis/gaia/fake_gaia.h"
#include "google_apis/gaia/gaia_auth_test_util.h"
@@ -57,9 +54,7 @@ class MockGaiaRemoteConsentFlowDelegate
const std::string& gaia_id));
};
-class GaiaRemoteConsentFlowParamBrowserTest
- : public InProcessBrowserTest,
- public testing::WithParamInterface<bool> {
+class GaiaRemoteConsentFlowParamBrowserTest : public InProcessBrowserTest {
public:
GaiaRemoteConsentFlowParamBrowserTest()
: fake_gaia_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
@@ -79,9 +74,6 @@ class GaiaRemoteConsentFlowParamBrowserTest
fake_gaia_test_server()->AddDefaultHandlers(GetChromeTestDataDir());
fake_gaia_test_server_.RegisterRequestHandler(base::BindRepeating(
&FakeGaia::HandleRequest, base::Unretained(&fake_gaia_)));
-
- scoped_feature_list_.InitWithFeatureState(
- features::kWebAuthFlowInBrowserTab, GetParam());
}
void SetUp() override {
@@ -158,30 +150,14 @@ class GaiaRemoteConsentFlowParamBrowserTest
}
void SimulateConsentResult(const std::string& consent_value) {
- // When the auth flow is using the browser tab, we are able to properly test
- // the JS injected script since we rely on the Gaia Origin to filter out
- // unwanted urls, and in the test we are overriding the value of Gaia
- // Origin, so we can bypass the filter for testing.
- if (base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab)) {
- // JS function is properly called but returns nullptr.
- ASSERT_EQ(nullptr, content::EvalJs(
- flow()->GetWebAuthFlowForTesting()->web_contents(),
- "window.OAuthConsent.setConsentResult(\"" +
- consent_value + "\")"));
- return;
- }
-
- // Since we cannot bypass the filter that is added in the internal extension
- // (in it's manifest) we do not directly test the JS function but instead
- // the layer right above in the API through
- // `IdentityPrivateSetConsentResultFunction`.
- std::string consent_result =
- "[\"" + consent_value + "\", \"" +
- flow()->GetWebAuthFlowForTesting()->GetAppWindowKey() + "\"]";
- scoped_refptr<ExtensionFunction> func =
- base::MakeRefCounted<IdentityPrivateSetConsentResultFunction>();
- ASSERT_TRUE(
- api_test_utils::RunFunction(func.get(), consent_result, profile()));
+ // We are able to properly test the JS injected script since we rely on the
+ // Gaia Origin to filter out unwanted urls, and in the test we are
+ // overriding the value of Gaia Origin, so we can bypass the filter for
+ // testing. JS function is properly called but returns nullptr.
+ ASSERT_EQ(nullptr, content::EvalJs(
+ flow()->GetWebAuthFlowForTesting()->web_contents(),
+ "window.OAuthConsent.setConsentResult(\"" +
+ consent_value + "\")"));
}
MockGaiaRemoteConsentFlowDelegate& mock() {
@@ -207,7 +183,7 @@ class GaiaRemoteConsentFlowParamBrowserTest
base::test::ScopedFeatureList scoped_feature_list_;
};
-IN_PROC_BROWSER_TEST_P(GaiaRemoteConsentFlowParamBrowserTest,
+IN_PROC_BROWSER_TEST_F(GaiaRemoteConsentFlowParamBrowserTest,
SimulateInvalidConsent) {
LaunchAndWaitGaiaRemoteConsentFlow();
@@ -217,7 +193,7 @@ IN_PROC_BROWSER_TEST_P(GaiaRemoteConsentFlowParamBrowserTest,
SimulateConsentResult("invalid_consent");
}
-IN_PROC_BROWSER_TEST_P(GaiaRemoteConsentFlowParamBrowserTest, SimulateNoGrant) {
+IN_PROC_BROWSER_TEST_F(GaiaRemoteConsentFlowParamBrowserTest, SimulateNoGrant) {
LaunchAndWaitGaiaRemoteConsentFlow();
EXPECT_CALL(mock(), OnGaiaRemoteConsentFlowFailed(
@@ -227,7 +203,7 @@ IN_PROC_BROWSER_TEST_P(GaiaRemoteConsentFlowParamBrowserTest, SimulateNoGrant) {
SimulateConsentResult(declined_consent);
}
-IN_PROC_BROWSER_TEST_P(GaiaRemoteConsentFlowParamBrowserTest,
+IN_PROC_BROWSER_TEST_F(GaiaRemoteConsentFlowParamBrowserTest,
SimulateAccessGranted) {
LaunchAndWaitGaiaRemoteConsentFlow();
@@ -238,15 +214,5 @@ IN_PROC_BROWSER_TEST_P(GaiaRemoteConsentFlowParamBrowserTest,
SimulateConsentResult(approved_consent);
}
-INSTANTIATE_TEST_SUITE_P(
- ,
- GaiaRemoteConsentFlowParamBrowserTest,
- testing::Bool(),
- [](const testing::TestParamInfo<
- GaiaRemoteConsentFlowParamBrowserTest::ParamType>& info) {
- return base::StrCat({"WebAuthFlowInBrowserTab_",
- info.param ? "FeatureOn" : "FeatureOff"});
- });
-
} // namespace extensions
#endif // !BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc b/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc
index 8ce505e6ce8..fa754041c1c 100644
--- a/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc
@@ -7,11 +7,7 @@
#include <memory>
#include <vector>
-#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "build/chromeos_buildflags.h"
-#include "chrome/common/chrome_features.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,52 +17,35 @@ namespace extensions {
const char kResultHistogramName[] =
"Signin.Extensions.GaiaRemoteConsentFlowResult";
-const char kWindowKey[] = "window_key";
const char kGaiaId[] = "fake_gaia_id";
const char kConsentResult[] = "CAESCUVOQ1JZUFRFRBoMZmFrZV9nYWlhX2lk";
-class FakeWebAuthFlowWithWindowKey : public WebAuthFlow {
+class FakeWebAuthFlow : public WebAuthFlow {
public:
- explicit FakeWebAuthFlowWithWindowKey(WebAuthFlow::Delegate* delegate,
- std::string window_key)
+ explicit FakeWebAuthFlow(WebAuthFlow::Delegate* delegate)
: WebAuthFlow(delegate,
nullptr,
GURL(),
WebAuthFlow::INTERACTIVE,
- WebAuthFlow::GET_AUTH_TOKEN,
- /*user_gesture=*/true),
- fake_window_key_(window_key) {}
+ /*user_gesture=*/true) {}
- ~FakeWebAuthFlowWithWindowKey() override = default;
+ ~FakeWebAuthFlow() override = default;
void Start() override {}
-
- const std::string& GetAppWindowKey() const override {
- return fake_window_key_;
- }
-
- private:
- const std::string fake_window_key_;
};
class TestGaiaRemoteConsentFlow : public GaiaRemoteConsentFlow {
public:
TestGaiaRemoteConsentFlow(GaiaRemoteConsentFlow::Delegate* delegate,
const ExtensionTokenKey& token_key,
- const RemoteConsentResolutionData& resolution_data,
- const std::string& window_key)
+ const RemoteConsentResolutionData& resolution_data)
: GaiaRemoteConsentFlow(delegate,
nullptr,
token_key,
resolution_data,
- /*user_gesture=*/true),
- window_key_(window_key) {
- SetWebAuthFlowForTesting(
- std::make_unique<FakeWebAuthFlowWithWindowKey>(this, window_key_));
+ /*user_gesture=*/true) {
+ SetWebAuthFlowForTesting(std::make_unique<FakeWebAuthFlow>(this));
}
-
- private:
- const std::string window_key_;
};
class MockGaiaRemoteConsentFlowDelegate
@@ -90,13 +69,11 @@ class IdentityGaiaRemoteConsentFlowTest : public testing::Test {
// deleted.
}
- std::unique_ptr<TestGaiaRemoteConsentFlow> CreateTestFlow(
- const std::string& window_key) {
- return CreateTestFlow(window_key, &delegate_);
+ std::unique_ptr<TestGaiaRemoteConsentFlow> CreateTestFlow() {
+ return CreateTestFlow(&delegate_);
}
std::unique_ptr<TestGaiaRemoteConsentFlow> CreateTestFlow(
- const std::string& window_key,
GaiaRemoteConsentFlow::Delegate* delegate) {
CoreAccountInfo user_info;
user_info.account_id = CoreAccountId::FromGaiaId("account_id");
@@ -107,8 +84,8 @@ class IdentityGaiaRemoteConsentFlowTest : public testing::Test {
std::set<std::string>());
RemoteConsentResolutionData resolution_data;
resolution_data.url = GURL("https://example.com/auth/");
- return std::make_unique<TestGaiaRemoteConsentFlow>(
- delegate, token_key, resolution_data, window_key);
+ return std::make_unique<TestGaiaRemoteConsentFlow>(delegate, token_key,
+ resolution_data);
}
base::HistogramTester* histogram_tester() { return &histogram_tester_; }
@@ -120,7 +97,7 @@ class IdentityGaiaRemoteConsentFlowTest : public testing::Test {
};
TEST_F(IdentityGaiaRemoteConsentFlowTest, ConsentResult) {
- std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
+ std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow();
EXPECT_CALL(delegate_,
OnGaiaRemoteConsentFlowApproved(kConsentResult, kGaiaId));
flow->ReactToConsentResult(kConsentResult);
@@ -129,11 +106,9 @@ TEST_F(IdentityGaiaRemoteConsentFlowTest, ConsentResult) {
}
TEST_F(IdentityGaiaRemoteConsentFlowTest, ConsentResult_TwoWindows) {
- std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
- const char kWindowKey2[] = "window_key2";
+ std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow();
testing::StrictMock<MockGaiaRemoteConsentFlowDelegate> delegate2;
- std::unique_ptr<TestGaiaRemoteConsentFlow> flow2 =
- CreateTestFlow(kWindowKey2, &delegate2);
+ std::unique_ptr<TestGaiaRemoteConsentFlow> flow2 = CreateTestFlow(&delegate2);
const char kConsentResult2[] = "CAESCkVOQ1JZUFRFRDI";
EXPECT_CALL(delegate2, OnGaiaRemoteConsentFlowApproved(kConsentResult2, ""));
@@ -148,7 +123,7 @@ TEST_F(IdentityGaiaRemoteConsentFlowTest, ConsentResult_TwoWindows) {
TEST_F(IdentityGaiaRemoteConsentFlowTest, InvalidConsentResult) {
const char kInvalidConsentResult[] = "abc";
- std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
+ std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow();
EXPECT_CALL(delegate_,
OnGaiaRemoteConsentFlowFailed(
GaiaRemoteConsentFlow::Failure::INVALID_CONSENT_RESULT));
@@ -159,7 +134,7 @@ TEST_F(IdentityGaiaRemoteConsentFlowTest, InvalidConsentResult) {
TEST_F(IdentityGaiaRemoteConsentFlowTest, NoGrant) {
const char kNoGrantConsentResult[] = "CAA";
- std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
+ std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow();
EXPECT_CALL(delegate_, OnGaiaRemoteConsentFlowFailed(
GaiaRemoteConsentFlow::Failure::NO_GRANT));
flow->ReactToConsentResult(kNoGrantConsentResult);
@@ -168,7 +143,7 @@ TEST_F(IdentityGaiaRemoteConsentFlowTest, NoGrant) {
}
TEST_F(IdentityGaiaRemoteConsentFlowTest, WebAuthFlowFailure_WindowClosed) {
- std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
+ std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow();
EXPECT_CALL(delegate_, OnGaiaRemoteConsentFlowFailed(
GaiaRemoteConsentFlow::Failure::WINDOW_CLOSED));
flow->OnAuthFlowFailure(WebAuthFlow::Failure::WINDOW_CLOSED);
@@ -177,7 +152,7 @@ TEST_F(IdentityGaiaRemoteConsentFlowTest, WebAuthFlowFailure_WindowClosed) {
}
TEST_F(IdentityGaiaRemoteConsentFlowTest, WebAuthFlowFailure_LoadFailed) {
- std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
+ std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow();
EXPECT_CALL(delegate_, OnGaiaRemoteConsentFlowFailed(
GaiaRemoteConsentFlow::Failure::LOAD_FAILED));
flow->OnAuthFlowFailure(WebAuthFlow::Failure::LOAD_FAILED);
@@ -185,39 +160,4 @@ TEST_F(IdentityGaiaRemoteConsentFlowTest, WebAuthFlowFailure_LoadFailed) {
GaiaRemoteConsentFlow::LOAD_FAILED, 1);
}
-// The following tests are only meaningful if the feature
-// `kWebAuthFlowInBrowserTab` is disabled
-class IdentityGaiaRemoteConsentFlowWebAuthFlowInBrowserTabOffTest
- : public IdentityGaiaRemoteConsentFlowTest {
- public:
- IdentityGaiaRemoteConsentFlowWebAuthFlowInBrowserTabOffTest() {
- scoped_feature_list_.InitAndDisableFeature(
- features::kWebAuthFlowInBrowserTab);
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(IdentityGaiaRemoteConsentFlowWebAuthFlowInBrowserTabOffTest,
- ConsentResult_WrongWindowIgnored) {
- std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
- // No call is expected.
- flow->OnConsentResultSet(kConsentResult, "another_window_key");
-}
-
-TEST_F(IdentityGaiaRemoteConsentFlowWebAuthFlowInBrowserTabOffTest,
- SetAccountsFailure) {
- std::unique_ptr<TestGaiaRemoteConsentFlow> flow = CreateTestFlow(kWindowKey);
- EXPECT_CALL(
- delegate_,
- OnGaiaRemoteConsentFlowFailed(
- GaiaRemoteConsentFlow::Failure::SET_ACCOUNTS_IN_COOKIE_FAILED));
- flow->OnSetAccountsComplete(
- signin::SetAccountsInCookieResult::kPersistentError);
- histogram_tester()->ExpectUniqueSample(
- kResultHistogramName,
- GaiaRemoteConsentFlow::SET_ACCOUNTS_IN_COOKIE_FAILED, 1);
-}
-
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_api.cc b/chromium/chrome/browser/extensions/api/identity/identity_api.cc
index 4a8d4ba3679..3e2ff468d4a 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_api.cc
+++ b/chromium/chrome/browser/extensions/api/identity/identity_api.cc
@@ -98,16 +98,6 @@ void IdentityAPI::EraseStaleGaiaIdsForAllExtensions() {
}
}
-void IdentityAPI::SetConsentResult(const std::string& result,
- const std::string& window_id) {
- on_set_consent_result_callback_list_.Notify(result, window_id);
-}
-
-base::CallbackListSubscription IdentityAPI::RegisterOnSetConsentResultCallback(
- const base::RepeatingCallback<OnSetConsentResultSignature>& callback) {
- return on_set_consent_result_callback_list_.Add(callback);
-}
-
void IdentityAPI::Shutdown() {
on_shutdown_callback_list_.Notify();
identity_manager_->RemoveObserver(this);
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_api.h b/chromium/chrome/browser/extensions/api/identity/identity_api.h
index 1986a6cf897..657d14a0a87 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_api.h
+++ b/chromium/chrome/browser/extensions/api/identity/identity_api.h
@@ -40,9 +40,6 @@ namespace extensions {
class IdentityAPI : public BrowserContextKeyedAPI,
public signin::IdentityManager::Observer {
public:
- using OnSetConsentResultSignature = void(const std::string&,
- const std::string&);
-
explicit IdentityAPI(content::BrowserContext* context);
~IdentityAPI() override;
@@ -63,12 +60,6 @@ class IdentityAPI : public BrowserContextKeyedAPI,
// longer signed in to Chrome for all extensions.
void EraseStaleGaiaIdsForAllExtensions();
- // Consent result.
- void SetConsentResult(const std::string& result,
- const std::string& window_id);
- base::CallbackListSubscription RegisterOnSetConsentResultCallback(
- const base::RepeatingCallback<OnSetConsentResultSignature>& callback);
-
// BrowserContextKeyedAPI:
void Shutdown() override;
static BrowserContextKeyedAPIFactory<IdentityAPI>* GetFactoryInstance();
@@ -126,8 +117,6 @@ class IdentityAPI : public BrowserContextKeyedAPI,
OnSignInChangedCallback on_signin_changed_callback_for_testing_;
- base::RepeatingCallbackList<OnSetConsentResultSignature>
- on_set_consent_result_callback_list_;
base::OnceCallbackList<void()> on_shutdown_callback_list_;
};
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc b/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc
index 09e44df583f..8f7b190234a 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -78,9 +78,11 @@
#include "content/public/test/test_utils.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api_test_utils.h"
+#include "extensions/browser/pref_names.h"
#include "extensions/common/api/oauth2.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/extension_features.h"
+#include "extensions/common/extension_id.h"
#include "extensions/common/manifest_handlers/oauth2_manifest_handler.h"
#include "google_apis/gaia/oauth2_mint_token_flow.h"
#include "net/cookies/cookie_util.h"
@@ -113,10 +115,6 @@
#endif
using extensions::ExtensionsAPIClient;
-using guest_view::GuestViewBase;
-using guest_view::GuestViewManager;
-using guest_view::TestGuestViewManager;
-using guest_view::TestGuestViewManagerFactory;
using testing::_;
using testing::Return;
@@ -342,6 +340,14 @@ void SimulateUrlRedirect(const std::string& url_prefix,
"apply_consent(\"" + url_prefix + "\");"));
}
+// Similar to SimulateUrlRedirect, but uses provided url instead of the pattern
+void SimulateCustomUrlRedirect(const std::string& redirect_url,
+ content::WebContents* auth_web_contents) {
+ ASSERT_EQ(nullptr,
+ content::EvalJs(auth_web_contents, "window.location.replace(\"" +
+ redirect_url + "\");"));
+}
+
} // namespace
class FakeGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
@@ -1061,7 +1067,7 @@ class GetAuthTokenFunctionTest
base::test::ScopedFeatureList feature_list_;
base::HistogramTester histogram_tester_;
- std::string extension_id_;
+ ExtensionId extension_id_;
std::set<std::string> oauth_scopes_;
std::unique_ptr<ExtensionFunction::ScopedUserGestureForTests> user_gesture_;
};
@@ -1645,24 +1651,6 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
}
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
- InteractiveApprovalSetAccountsInCookieFailed) {
- SignIn("primary@example.com");
- scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
- func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
- func->push_mint_token_result(TestOAuth2MintTokenFlow::REMOTE_CONSENT_SUCCESS);
- func->set_scope_ui_failure(
- GaiaRemoteConsentFlow::SET_ACCOUNTS_IN_COOKIE_FAILED);
- std::string error = utils::RunFunctionAndReturnError(
- func.get(), "[{\"interactive\": true}]", browser()->profile());
- EXPECT_EQ(std::string(errors::kSetAccountsInCookieFailure), error);
- EXPECT_FALSE(func->login_ui_shown());
- EXPECT_TRUE(func->scope_ui_shown());
- histogram_tester()->ExpectUniqueSample(
- kGetAuthTokenResultHistogramName,
- IdentityGetAuthTokenError::State::kSetAccountsInCookieFailure, 1);
-}
-
-IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
InteractiveApprovalInvalidConsentResult) {
SignIn("primary@example.com");
scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
@@ -3555,7 +3543,7 @@ IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, NonInteractiveSuccess) {
scoped_refptr<IdentityLaunchWebAuthFlowFunction> function =
CreateLaunchWebAuthFlowFunction();
- function->InitFinalRedirectURLPrefixForTest("abcdefghij");
+ function->InitFinalRedirectURLDomainsForTest("abcdefghij");
absl::optional<base::Value> value = utils::RunFunctionAndReturnSingleResult(
function.get(),
"[{\"interactive\": false,"
@@ -3580,7 +3568,7 @@ IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,
scoped_refptr<IdentityLaunchWebAuthFlowFunction> function =
CreateLaunchWebAuthFlowFunction();
- function->InitFinalRedirectURLPrefixForTest("abcdefghij");
+ function->InitFinalRedirectURLDomainsForTest("abcdefghij");
std::string args = base::StringPrintf(
R"([{
"interactive": false,
@@ -3602,7 +3590,7 @@ IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,
scoped_refptr<IdentityLaunchWebAuthFlowFunction> function =
CreateLaunchWebAuthFlowFunction();
- function->InitFinalRedirectURLPrefixForTest("abcdefghij");
+ function->InitFinalRedirectURLDomainsForTest("abcdefghij");
absl::optional<base::Value> value = utils::RunFunctionAndReturnSingleResult(
function.get(),
"[{\"interactive\": true,"
@@ -3625,7 +3613,7 @@ IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,
scoped_refptr<IdentityLaunchWebAuthFlowFunction> function =
CreateLaunchWebAuthFlowFunction();
- function->InitFinalRedirectURLPrefixForTest("abcdefghij");
+ function->InitFinalRedirectURLDomainsForTest("abcdefghij");
std::string args =
"[{\"interactive\": true, \"url\": \"" + auth_url.spec() + "\"}]";
absl::optional<base::Value> value = utils::RunFunctionAndReturnSingleResult(
@@ -3639,63 +3627,7 @@ IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,
IdentityLaunchWebAuthFlowFunction::Error::kNone, 1);
}
-class LaunchWebAuthFlowFunctionTestWithWebAuthFlowInBrowserTabParam
- : public LaunchWebAuthFlowFunctionTest,
- public testing::WithParamInterface<bool> {
- public:
- LaunchWebAuthFlowFunctionTestWithWebAuthFlowInBrowserTabParam() {
- scoped_feature_list_.InitWithFeatureState(
- features::kWebAuthFlowInBrowserTab, use_tab_feature_enabled());
- }
-
- void SetUp() override {
- GuestViewManager::set_factory_for_testing(&factory_);
- LaunchWebAuthFlowFunctionTest::SetUp();
- }
-
- void TearDown() override {
- LaunchWebAuthFlowFunctionTest::TearDown();
- GuestViewManager::set_factory_for_testing(nullptr);
- }
-
- protected:
- bool use_tab_feature_enabled() { return GetParam(); }
-
- void CloseGuestView() {
- TestGuestViewManager* guest_view_manager = GetGuestViewManager();
- auto* guest_view = guest_view_manager->WaitForSingleGuestViewCreated();
- ASSERT_TRUE(guest_view);
-
- guest_view_manager->WaitUntilAttached(guest_view);
-
- auto* embedder_web_contents = guest_view->embedder_web_contents();
- ASSERT_TRUE(embedder_web_contents);
- embedder_web_contents->Close();
- }
-
- private:
- TestGuestViewManagerFactory factory_;
- base::test::ScopedFeatureList scoped_feature_list_;
-
- TestGuestViewManager* GetGuestViewManager() {
- TestGuestViewManager* manager = static_cast<TestGuestViewManager*>(
- TestGuestViewManager::FromBrowserContext(browser()->profile()));
- // Test code may access the TestGuestViewManager before it would be created
- // during creation of the first guest.
- if (!manager) {
- manager = static_cast<TestGuestViewManager*>(
- GuestViewManager::CreateWithDelegate(
- browser()->profile(),
- ExtensionsAPIClient::Get()->CreateGuestViewManagerDelegate(
- browser()->profile())));
- }
- return manager;
- }
-};
-
-IN_PROC_BROWSER_TEST_P(
- LaunchWebAuthFlowFunctionTestWithWebAuthFlowInBrowserTabParam,
- UserCloseWindow) {
+IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, UserCloseWindow) {
std::unique_ptr<net::EmbeddedTestServer> https_server = LaunchHttpsServer();
GURL auth_url(https_server->GetURL("/interaction_required.html"));
@@ -3703,30 +3635,21 @@ IN_PROC_BROWSER_TEST_P(
CreateLaunchWebAuthFlowFunction();
content::TestNavigationObserver url_obvserver(auth_url);
- if (use_tab_feature_enabled()) {
- url_obvserver.StartWatchingNewWebContents();
- }
+ url_obvserver.StartWatchingNewWebContents();
std::string args =
"[{\"interactive\": true, \"url\": \"" + auth_url.spec() + "\"}]";
RunFunctionAsync(function.get(), args);
+ url_obvserver.Wait();
+
+ Browser* popup_browser = chrome::FindBrowserWithWebContents(
+ function->GetWebAuthFlowForTesting()->web_contents());
+ TabStripModel* tabs = popup_browser->tab_strip_model();
+ EXPECT_NE(browser(), popup_browser);
+ ASSERT_EQ(tabs->GetActiveWebContents()->GetURL(), auth_url);
// Close the opened auth web contents.
- // Depending on the feature `WebAuthFlowInBrowserTab`, close the opened
- // GuestView (simulating the AppWindow), or close the new tab through the
- // created WebContents.
- if (use_tab_feature_enabled()) {
- url_obvserver.Wait();
-
- Browser* popup_browser = chrome::FindBrowserWithWebContents(
- function->GetWebAuthFlowForTesting()->web_contents());
- TabStripModel* tabs = popup_browser->tab_strip_model();
- EXPECT_NE(browser(), popup_browser);
- ASSERT_EQ(tabs->GetActiveWebContents()->GetURL(), auth_url);
- tabs->CloseWebContentsAt(tabs->active_index(), 0);
- } else {
- CloseGuestView();
- }
+ tabs->CloseWebContentsAt(tabs->active_index(), 0);
EXPECT_EQ(std::string(errors::kUserRejected), WaitForError(function.get()));
histogram_tester()->ExpectUniqueSample(
@@ -3734,25 +3657,27 @@ IN_PROC_BROWSER_TEST_P(
IdentityLaunchWebAuthFlowFunction::Error::kUserRejected, 1);
}
-INSTANTIATE_TEST_SUITE_P(
- ,
- LaunchWebAuthFlowFunctionTestWithWebAuthFlowInBrowserTabParam,
- testing::Bool(),
- [](const testing::TestParamInfo<
- LaunchWebAuthFlowFunctionTestWithWebAuthFlowInBrowserTabParam::
- ParamType>& info) {
- return base::StrCat(
- {info.param ? "With" : "Without", "WebAuthFlowInBrowserTab"});
- });
-
-class LaunchWebAuthFlowFunctionTestWithNewTab
- : public LaunchWebAuthFlowFunctionTest {
- public:
- LaunchWebAuthFlowFunctionTestWithNewTab() {
- scoped_feature_list_.InitAndEnableFeature(
- features::kWebAuthFlowInBrowserTab);
- }
+// Regression test for http://b/290733700.
+IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,
+ SchemeOtherThanHttpOrHttpsNotAllowed) {
+ // Only http and https schemes are allowed.
+ GURL invalid_auth_url("chrome-untrusted://some_chrome_url");
+ scoped_refptr<IdentityLaunchWebAuthFlowFunction> function =
+ CreateLaunchWebAuthFlowFunction();
+
+ std::string args =
+ "[{\"interactive\": true, \"url\": \"" + invalid_auth_url.spec() + "\"}]";
+ RunFunctionAsync(function.get(), args);
+ EXPECT_EQ(std::string(errors::kInvalidURLScheme),
+ WaitForError(function.get()));
+ histogram_tester()->ExpectUniqueSample(
+ kLaunchWebAuthFlowResultHistogramName,
+ IdentityLaunchWebAuthFlowFunction::Error::kInvalidURLScheme, 1);
+}
+
+class LaunchWebAuthFlowFunctionTestWithBrowserTab
+ : public LaunchWebAuthFlowFunctionTest {
protected:
void RunFunctionAndWaitForNavigation(
IdentityLaunchWebAuthFlowFunction* function,
@@ -3763,19 +3688,16 @@ class LaunchWebAuthFlowFunctionTestWithNewTab
RunFunctionAsync(function, args);
url_observer.Wait();
}
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
};
-IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithNewTab,
+IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithBrowserTab,
PageNavigateFromInitURLToFinalURL) {
std::unique_ptr<net::EmbeddedTestServer> https_server = LaunchHttpsServer();
scoped_refptr<IdentityLaunchWebAuthFlowFunction> function =
CreateLaunchWebAuthFlowFunction();
const std::string extension_id("abcdefghij");
- function->InitFinalRedirectURLPrefixForTest(extension_id);
+ function->InitFinalRedirectURLDomainsForTest(extension_id);
const GURL auth_url(https_server->GetURL("/consent_page.html"));
const GURL final_url("https://" + extension_id + ".chromiumapp.org/");
@@ -3790,7 +3712,38 @@ IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithNewTab,
base::Value output;
WaitForOneResult(function.get(), &output);
EXPECT_FALSE(function->GetWebAuthFlowForTesting());
- EXPECT_TRUE(output.GetString().find(final_url.spec()) != std::string::npos);
+ EXPECT_EQ(GURL(output.GetString()).Resolve("/"), final_url);
+ histogram_tester()->ExpectUniqueSample(
+ kLaunchWebAuthFlowResultHistogramName,
+ IdentityLaunchWebAuthFlowFunction::Error::kNone, 1);
+}
+
+IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithBrowserTab,
+ PageNavigateFromInitURLToCustomFinalURL) {
+ std::unique_ptr<net::EmbeddedTestServer> https_server = LaunchHttpsServer();
+ scoped_refptr<IdentityLaunchWebAuthFlowFunction> function =
+ CreateLaunchWebAuthFlowFunction();
+
+ const GURL auth_url(https_server->GetURL("/consent_page.html"));
+ const GURL final_url("example://example.com/");
+
+ const std::string args =
+ "[{\"interactive\": true, \"url\": \"" + auth_url.spec() + "\"}]";
+
+ browser()->profile()->GetPrefs()->SetDict(
+ extensions::pref_names::kOAuthRedirectUrls,
+ base::Value::Dict().Set(function->extension()->id(),
+ base::Value::List().Append(final_url.spec())));
+ RunFunctionAndWaitForNavigation(function.get(), auth_url, args);
+
+ SimulateCustomUrlRedirect(
+ final_url.spec() + "#some_information",
+ function->GetWebAuthFlowForTesting()->web_contents());
+
+ base::Value output;
+ WaitForOneResult(function.get(), &output);
+ EXPECT_FALSE(function->GetWebAuthFlowForTesting());
+ EXPECT_EQ(GURL(output.GetString()).Resolve("/"), final_url);
histogram_tester()->ExpectUniqueSample(
kLaunchWebAuthFlowResultHistogramName,
IdentityLaunchWebAuthFlowFunction::Error::kNone, 1);
@@ -3798,7 +3751,7 @@ IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithNewTab,
// TODO(crbug/1421278): This test should be adapted after the implementation of
// the bug. Multiple TODOs in the test to fix.
-IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithNewTab,
+IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithBrowserTab,
SimilarExtensionAndArgsShouldGenerateSameFlow) {
std::unique_ptr<net::EmbeddedTestServer> https_server = LaunchHttpsServer();
scoped_refptr<IdentityLaunchWebAuthFlowFunction> function1 =
@@ -3807,8 +3760,8 @@ IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithNewTab,
CreateLaunchWebAuthFlowFunction();
const std::string extension_id("final_url");
- function1->InitFinalRedirectURLPrefixForTest(extension_id);
- function2->InitFinalRedirectURLPrefixForTest(extension_id);
+ function1->InitFinalRedirectURLDomainsForTest(extension_id);
+ function2->InitFinalRedirectURLDomainsForTest(extension_id);
const GURL auth_url(https_server->GetURL("/consent_page.html"));
const GURL final_url("https://" + extension_id + ".chromiumapp.org/");
@@ -3847,7 +3800,7 @@ IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithNewTab,
IdentityLaunchWebAuthFlowFunction::Error::kNone, 1);
}
-IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithNewTab,
+IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithBrowserTab,
DifferentExtensionsShouldGenerateDifferentFlows) {
std::unique_ptr<net::EmbeddedTestServer> https_server = LaunchHttpsServer();
scoped_refptr<IdentityLaunchWebAuthFlowFunction> function1 =
@@ -3856,9 +3809,9 @@ IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithNewTab,
CreateLaunchWebAuthFlowFunction();
const std::string extension_id1("extension1");
- function1->InitFinalRedirectURLPrefixForTest(extension_id1);
+ function1->InitFinalRedirectURLDomainsForTest(extension_id1);
const std::string extension_id2("extension2");
- function2->InitFinalRedirectURLPrefixForTest(extension_id2);
+ function2->InitFinalRedirectURLDomainsForTest(extension_id2);
const GURL auth_url(https_server->GetURL("/consent_page.html"));
// Different final_urls.
@@ -3906,7 +3859,7 @@ IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTestWithNewTab,
// TODO(crbug/1421278): This test should be adapted after the implementation of
// the bug.
IN_PROC_BROWSER_TEST_F(
- LaunchWebAuthFlowFunctionTestWithNewTab,
+ LaunchWebAuthFlowFunctionTestWithBrowserTab,
ExtensionWithDifferentArgsShouldGenerateDifferentFlowsInAQueue) {
std::unique_ptr<net::EmbeddedTestServer> https_server = LaunchHttpsServer();
scoped_refptr<IdentityLaunchWebAuthFlowFunction> function1 =
@@ -3915,7 +3868,7 @@ IN_PROC_BROWSER_TEST_F(
CreateLaunchWebAuthFlowFunction();
const std::string extension_id("extension");
- function1->InitFinalRedirectURLPrefixForTest(extension_id);
+ function1->InitFinalRedirectURLDomainsForTest(extension_id);
const GURL auth_url1(https_server->GetURL("/consent_page.html"));
const GURL auth_url2(https_server->GetURL("/interaction_required.html"));
@@ -3933,8 +3886,8 @@ IN_PROC_BROWSER_TEST_F(
function1->GetWebAuthFlowForTesting()->web_contents();
content::WebContents* consent_web_contents2 =
function2->GetWebAuthFlowForTesting()->web_contents();
- // TODO(crbug/1421278): `function2->GetWebAuthFlowForTesting()` should be null
- // after the changes since it would be in a queue.
+ // TODO(crbug/1421278): `function2->GetWebAuthFlowForTesting()` should be
+ // null after the changes since it would be in a queue.
EXPECT_NE(consent_web_contents1, consent_web_contents2);
const std::string& current_consent_url2 =
@@ -4007,58 +3960,6 @@ IN_PROC_BROWSER_TEST_F(ClearAllCachedAuthTokensFunctionTest,
id_api()->token_cache()->GetToken(token_key).status());
}
-class ClearAllCachedAuthTokensFunctionTestWithPartitionParam
- : public ClearAllCachedAuthTokensFunctionTest,
- public testing::WithParamInterface<WebAuthFlow::Partition> {
- public:
- network::mojom::CookieManager* GetCookieManager() {
- Profile* profile = browser()->profile();
- return profile
- ->GetStoragePartition(
- WebAuthFlow::GetWebViewPartitionConfig(GetParam(), profile))
- ->GetCookieManagerForBrowserProcess();
- }
-
- // Returns the list of cookies in the cookie manager.
- net::CookieList GetCookies() {
- net::CookieList result;
- base::RunLoop get_all_cookies_loop;
- GetCookieManager()->GetAllCookies(base::BindLambdaForTesting(
- [&get_all_cookies_loop, &result](const net::CookieList& cookie_list) {
- result = cookie_list;
- get_all_cookies_loop.Quit();
- }));
- get_all_cookies_loop.Run();
- return result;
- }
-};
-
-IN_PROC_BROWSER_TEST_P(ClearAllCachedAuthTokensFunctionTestWithPartitionParam,
- CleanWebAuthFlowCookies) {
- auto test_cookie = net::CanonicalCookie::CreateUnsafeCookieForTesting(
- "test_name", "test_value", "test.com", "/", base::Time(), base::Time(),
- base::Time(), base::Time(), true, false,
- net::CookieSameSite::NO_RESTRICTION, net::COOKIE_PRIORITY_DEFAULT, false);
- base::test::TestFuture<bool> future;
- GetCookieManager()->SetCanonicalCookie(
- *test_cookie,
- net::cookie_util::SimulatedCookieSource(*test_cookie, url::kHttpsScheme),
- net::CookieOptions(),
- base::BindOnce(net::cookie_util::IsCookieAccessResultInclude)
- .Then(future.GetCallback()));
- EXPECT_TRUE(future.Get());
-
- EXPECT_FALSE(GetCookies().empty());
- ASSERT_TRUE(RunClearAllCachedAuthTokensFunction());
- EXPECT_TRUE(GetCookies().empty());
-}
-
-INSTANTIATE_TEST_SUITE_P(
- All,
- ClearAllCachedAuthTokensFunctionTestWithPartitionParam,
- ::testing::Values(WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::Partition::GET_AUTH_TOKEN));
-
class OnSignInChangedEventTest : public IdentityTestWithSignin {
protected:
void SetUpOnMainThread() override {
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.cc b/chromium/chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.cc
index 06a3fb6c919..0ab43bb2f4a 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.cc
+++ b/chromium/chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.cc
@@ -4,26 +4,13 @@
#include "chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.h"
-#include "base/functional/bind.h"
-#include "base/location.h"
-#include "base/task/single_thread_task_runner.h"
#include "chrome/browser/extensions/api/identity/identity_api.h"
#include "chrome/browser/extensions/api/identity/identity_constants.h"
#include "chrome/browser/extensions/api/identity/web_auth_flow.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/extensions/api/identity.h"
-#include "content/public/browser/storage_partition.h"
-#include "services/network/public/mojom/cookie_manager.mojom.h"
namespace extensions {
-namespace {
-
-constexpr WebAuthFlow::Partition kPartitionsToClean[] = {
- WebAuthFlow::GET_AUTH_TOKEN, WebAuthFlow::LAUNCH_WEB_AUTH_FLOW};
-
-}
-
IdentityClearAllCachedAuthTokensFunction::
IdentityClearAllCachedAuthTokensFunction() = default;
IdentityClearAllCachedAuthTokensFunction::
@@ -39,35 +26,7 @@ IdentityClearAllCachedAuthTokensFunction::Run() {
id_api->EraseGaiaIdForExtension(extension()->id());
id_api->token_cache()->EraseAllTokensForExtension(extension()->id());
- for (WebAuthFlow::Partition partition : kPartitionsToClean) {
- profile
- ->GetStoragePartition(
- WebAuthFlow::GetWebViewPartitionConfig(partition, profile))
- ->GetCookieManagerForBrowserProcess()
- ->DeleteCookies(
- network::mojom::CookieDeletionFilter::New(),
- base::BindOnce(
- &IdentityClearAllCachedAuthTokensFunction::OnCookiesDeleted,
- this));
- }
-
- // This object is retained by the DeleteCookies callbacks.
- return RespondLater();
-}
-
-void IdentityClearAllCachedAuthTokensFunction::OnCookiesDeleted(
- uint32_t num_deleted) {
- ++cleaned_partitions_;
-
- if (cleaned_partitions_ < std::size(kPartitionsToClean))
- return;
-
- // Post a task to ensure Respond() is not synchronously called from Run(). The
- // object is retained by this task.
- base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
- FROM_HERE,
- base::BindOnce(&IdentityClearAllCachedAuthTokensFunction::Respond, this,
- NoArguments()));
+ return RespondNow(NoArguments());
}
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.h b/chromium/chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.h
index 066987d20f1..774f4d48cde 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.h
+++ b/chromium/chrome/browser/extensions/api/identity/identity_clear_all_cached_auth_tokens_function.h
@@ -21,10 +21,6 @@ class IdentityClearAllCachedAuthTokensFunction : public ExtensionFunction {
// ExtensionFunction:
ResponseAction Run() override;
-
- void OnCookiesDeleted(uint32_t num_deleted);
-
- size_t cleaned_partitions_ = 0;
};
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_constants.cc b/chromium/chrome/browser/extensions/api/identity/identity_constants.cc
index 37d177dd0b8..ec84ec0adf8 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_constants.cc
+++ b/chromium/chrome/browser/extensions/api/identity/identity_constants.cc
@@ -25,11 +25,13 @@ const char kInvalidRedirect[] = "Did not redirect to the right URL.";
const char kOffTheRecord[] = "Identity API is disabled in incognito windows.";
const char kPageLoadFailure[] = "Authorization page could not be loaded.";
const char kPageLoadTimedOut[] = "Authorization page load timed out.";
-const char kSetAccountsInCookieFailure[] = "Account cookies could not be set.";
const char kInvalidConsentResult[] = "Returned an invalid consent result.";
const char kCanceled[] = "canceled";
const char kCannotCreateWindow[] =
"Couldn't create a browser window to display an authorization page.";
+const char kInvalidURLScheme[] =
+ "The auth url has an invalid scheme. Only http:// and https:// schemes are "
+ "allowed.";
const int kCachedRemoteConsentTTLSeconds = 1;
} // namespace identity_constants
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_constants.h b/chromium/chrome/browser/extensions/api/identity/identity_constants.h
index 91039aa4a2e..e8aa98376e0 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_constants.h
+++ b/chromium/chrome/browser/extensions/api/identity/identity_constants.h
@@ -22,10 +22,10 @@ extern const char kInvalidRedirect[];
extern const char kOffTheRecord[];
extern const char kPageLoadFailure[];
extern const char kPageLoadTimedOut[];
-extern const char kSetAccountsInCookieFailure[];
extern const char kInvalidConsentResult[];
extern const char kCanceled[];
extern const char kCannotCreateWindow[];
+extern const char kInvalidURLScheme[];
extern const int kCachedRemoteConsentTTLSeconds;
} // namespace identity_constants
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_error.cc b/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_error.cc
index e65baad32fc..670a7790de3 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_error.cc
+++ b/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_error.cc
@@ -64,8 +64,6 @@ std::string IdentityGetAuthTokenError::ToString() const {
return identity_constants::kOffTheRecord;
case State::kRemoteConsentPageLoadFailure:
return identity_constants::kPageLoadFailure;
- case State::kSetAccountsInCookieFailure:
- return identity_constants::kSetAccountsInCookieFailure;
case State::kInvalidConsentResult:
return identity_constants::kInvalidConsentResult;
case State::kCanceled:
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_error.h b/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_error.h
index 1624c64f0b4..84b4694931d 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_error.h
+++ b/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_error.h
@@ -41,7 +41,7 @@ class IdentityGetAuthTokenError {
kOffTheRecord = 22,
// kPageLoadFailure = 23, // Deprecated
kRemoteConsentPageLoadFailure = 24,
- kSetAccountsInCookieFailure = 25,
+ // kSetAccountsInCookieFailure = 25, // Deprecated
kInvalidConsentResult = 26,
kCanceled = 27,
kInteractivityDenied = 28,
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc b/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
index 87dc7d1caae..04470955181 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
+++ b/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
@@ -13,6 +13,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/strings/strcat.h"
+#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
@@ -60,12 +61,12 @@ bool IsBrowserSigninAllowed(Profile* profile) {
return profile->GetPrefs()->GetBoolean(prefs::kSigninAllowed);
}
-std::string GetOAuth2MintTokenFlowVersion() {
- return std::string(version_info::GetVersionNumber());
+base::StringPiece GetOAuth2MintTokenFlowVersion() {
+ return version_info::GetVersionNumber();
}
-std::string GetOAuth2MintTokenFlowChannel() {
- return std::string(version_info::GetChannelString(chrome::GetChannel()));
+base::StringPiece GetOAuth2MintTokenFlowChannel() {
+ return version_info::GetChannelString(chrome::GetChannel());
}
void RecordFunctionResult(const IdentityGetAuthTokenError& error,
@@ -237,7 +238,7 @@ void IdentityGetAuthTokenFunction::OnReceivedExtensionAccountInfo(
#if BUILDFLAG(IS_CHROMEOS)
if (g_browser_process->browser_policy_connector()
->IsDeviceEnterpriseManaged()) {
- if (profiles::IsPublicSession()) {
+ if (profiles::IsManagedGuestSession()) {
CompleteFunctionWithError(IdentityGetAuthTokenError(
IdentityGetAuthTokenError::State::kNotAllowlistedInPublicSession));
return;
@@ -456,8 +457,9 @@ void IdentityGetAuthTokenFunction::StartMintToken(
switch (cache_status) {
case IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND:
#if BUILDFLAG(IS_CHROMEOS)
- // Always force minting token for ChromeOS kiosk app and public session.
- if (profiles::IsPublicSession()) {
+ // Always force minting token for ChromeOS kiosk app and managed guest
+ // session.
+ if (profiles::IsManagedGuestSession()) {
CompleteFunctionWithError(
IdentityGetAuthTokenError(IdentityGetAuthTokenError::State::
kNotAllowlistedInPublicSession));
@@ -656,16 +658,10 @@ void IdentityGetAuthTokenFunction::OnGaiaRemoteConsentFlowFailed(
switch (failure) {
case GaiaRemoteConsentFlow::WINDOW_CLOSED:
- case GaiaRemoteConsentFlow::USER_NAVIGATED_AWAY:
error = IdentityGetAuthTokenError(
IdentityGetAuthTokenError::State::kRemoteConsentFlowRejected);
break;
- case GaiaRemoteConsentFlow::SET_ACCOUNTS_IN_COOKIE_FAILED:
- error = IdentityGetAuthTokenError(
- IdentityGetAuthTokenError::State::kSetAccountsInCookieFailure);
- break;
-
case GaiaRemoteConsentFlow::LOAD_FAILED:
error = IdentityGetAuthTokenError(
IdentityGetAuthTokenError::State::kRemoteConsentPageLoadFailure);
@@ -876,13 +872,13 @@ IdentityGetAuthTokenFunction::CreateMintTokenFlow() {
GetSigninScopedDeviceIdForProfile(GetProfile());
auto mint_token_flow = std::make_unique<OAuth2MintTokenFlow>(
this,
- OAuth2MintTokenFlow::Parameters(
+ OAuth2MintTokenFlow::Parameters::CreateForExtensionFlow(
extension()->id(), oauth2_client_id_,
- std::vector<std::string>(token_key_.scopes.begin(),
- token_key_.scopes.end()),
- enable_granular_permissions_, signin_scoped_device_id,
- GetSelectedUserId(), consent_result_, GetOAuth2MintTokenFlowVersion(),
- GetOAuth2MintTokenFlowChannel(), gaia_mint_token_mode_));
+ std::vector<base::StringPiece>(token_key_.scopes.begin(),
+ token_key_.scopes.end()),
+ gaia_mint_token_mode_, enable_granular_permissions_,
+ GetOAuth2MintTokenFlowVersion(), GetOAuth2MintTokenFlowChannel(),
+ signin_scoped_device_id, GetSelectedUserId(), consent_result_));
return mint_token_flow;
}
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.cc b/chromium/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.cc
index 810633b5b67..350fd13cfca 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.cc
+++ b/chromium/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.cc
@@ -14,6 +14,8 @@
#include "chrome/browser/extensions/api/identity/identity_constants.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/identity.h"
+#include "components/prefs/pref_service.h"
+#include "extensions/browser/pref_names.h"
namespace extensions {
@@ -26,7 +28,6 @@ IdentityLaunchWebAuthFlowFunction::Error WebAuthFlowFailureToError(
WebAuthFlow::Failure failure) {
switch (failure) {
case WebAuthFlow::WINDOW_CLOSED:
- case WebAuthFlow::USER_NAVIGATED_AWAY:
return IdentityLaunchWebAuthFlowFunction::Error::kUserRejected;
case WebAuthFlow::INTERACTION_REQUIRED:
return IdentityLaunchWebAuthFlowFunction::Error::kInteractionRequired;
@@ -62,6 +63,8 @@ std::string ErrorToString(IdentityLaunchWebAuthFlowFunction::Error error) {
return identity_constants::kPageLoadTimedOut;
case IdentityLaunchWebAuthFlowFunction::Error::kCannotCreateWindow:
return identity_constants::kCannotCreateWindow;
+ case IdentityLaunchWebAuthFlowFunction::Error::kInvalidURLScheme:
+ return identity_constants::kInvalidURLScheme;
}
}
@@ -99,6 +102,13 @@ ExtensionFunction::ResponseAction IdentityLaunchWebAuthFlowFunction::Run() {
EXTENSION_FUNCTION_VALIDATE(params);
GURL auth_url(params->details.url);
+ if (!auth_url.SchemeIsHTTPOrHTTPS()) {
+ Error error = Error::kInvalidURLScheme;
+
+ RecordHistogramFunctionResult(error);
+ return RespondNow(ExtensionFunction::Error(ErrorToString(error)));
+ }
+
WebAuthFlow::Mode mode =
params->details.interactive && *params->details.interactive
? WebAuthFlow::INTERACTIVE
@@ -120,14 +130,18 @@ ExtensionFunction::ResponseAction IdentityLaunchWebAuthFlowFunction::Run() {
// Set up acceptable target URLs. (Does not include chrome-extension
// scheme for this version of the API.)
- InitFinalRedirectURLPrefix(extension()->id());
+ InitFinalRedirectURLDomains(
+ extension()->id(),
+ Profile::FromBrowserContext(browser_context())
+ ->GetPrefs()
+ ->GetDict(extensions::pref_names::kOAuthRedirectUrls)
+ .FindList(extension()->id()));
AddRef(); // Balanced in OnAuthFlowSuccess/Failure.
auth_flow_ = std::make_unique<WebAuthFlow>(
- this, profile, auth_url, mode, WebAuthFlow::LAUNCH_WEB_AUTH_FLOW,
- user_gesture(), abort_on_load_for_non_interactive,
- timeout_for_non_interactive);
+ this, profile, auth_url, mode, user_gesture(),
+ abort_on_load_for_non_interactive, timeout_for_non_interactive);
// An extension might call `launchWebAuthFlow()` with any URL. Add an infobar
// to attribute displayed URL to the extension.
auth_flow_->SetShouldShowInfoBar(extension()->name());
@@ -142,16 +156,26 @@ bool IdentityLaunchWebAuthFlowFunction::ShouldKeepWorkerAliveIndefinitely() {
return true;
}
-void IdentityLaunchWebAuthFlowFunction::InitFinalRedirectURLPrefixForTest(
+void IdentityLaunchWebAuthFlowFunction::InitFinalRedirectURLDomainsForTest(
const std::string& extension_id) {
- InitFinalRedirectURLPrefix(extension_id);
+ InitFinalRedirectURLDomains(extension_id, nullptr);
}
-void IdentityLaunchWebAuthFlowFunction::InitFinalRedirectURLPrefix(
- const std::string& extension_id) {
- if (final_url_prefix_.is_empty()) {
- final_url_prefix_ = GURL(base::StringPrintf(
- kChromiumDomainRedirectUrlPattern, extension_id.c_str()));
+void IdentityLaunchWebAuthFlowFunction::InitFinalRedirectURLDomains(
+ const std::string& extension_id,
+ const base::Value::List* redirect_urls) {
+ if (!final_url_domains_.empty()) {
+ return;
+ }
+ final_url_domains_.emplace_back(base::StringPrintf(
+ kChromiumDomainRedirectUrlPattern, extension_id.c_str()));
+ if (redirect_urls) {
+ for (const auto& value : *redirect_urls) {
+ GURL domain(value.GetString());
+ if (domain.is_valid()) {
+ final_url_domains_.push_back(domain.Resolve("/"));
+ }
+ }
}
}
@@ -168,14 +192,16 @@ void IdentityLaunchWebAuthFlowFunction::OnAuthFlowFailure(
void IdentityLaunchWebAuthFlowFunction::OnAuthFlowURLChange(
const GURL& redirect_url) {
- if (redirect_url.GetWithEmptyPath() == final_url_prefix_) {
- RecordHistogramFunctionResult(
- IdentityLaunchWebAuthFlowFunction::Error::kNone);
- Respond(WithArguments(redirect_url.spec()));
- if (auth_flow_)
- auth_flow_.release()->DetachDelegateAndDelete();
- Release(); // Balanced in RunAsync.
+ if (!base::Contains(final_url_domains_, redirect_url.Resolve("/"))) {
+ return;
+ }
+ RecordHistogramFunctionResult(
+ IdentityLaunchWebAuthFlowFunction::Error::kNone);
+ Respond(WithArguments(redirect_url.spec()));
+ if (auth_flow_) {
+ auth_flow_.release()->DetachDelegateAndDelete();
}
+ Release(); // Balanced in RunAsync.
}
WebAuthFlow* IdentityLaunchWebAuthFlowFunction::GetWebAuthFlowForTesting() {
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.h b/chromium/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.h
index 9b4aace4145..2c52713b892 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.h
+++ b/chromium/chrome/browser/extensions/api/identity/identity_launch_web_auth_flow_function.h
@@ -38,13 +38,14 @@ class IdentityLaunchWebAuthFlowFunction : public ExtensionFunction,
kUnexpectedError = 5,
kPageLoadTimedOut = 6,
kCannotCreateWindow = 7,
- kMaxValue = kCannotCreateWindow,
+ kInvalidURLScheme = 8,
+ kMaxValue = kInvalidURLScheme,
};
IdentityLaunchWebAuthFlowFunction();
// Tests may override extension_id.
- void InitFinalRedirectURLPrefixForTest(const std::string& extension_id);
+ void InitFinalRedirectURLDomainsForTest(const std::string& extension_id);
WebAuthFlow* GetWebAuthFlowForTesting();
@@ -60,10 +61,11 @@ class IdentityLaunchWebAuthFlowFunction : public ExtensionFunction,
void OnAuthFlowTitleChange(const std::string& title) override {}
// Helper to initialize final URL prefix.
- void InitFinalRedirectURLPrefix(const std::string& extension_id);
+ void InitFinalRedirectURLDomains(const std::string& extension_id,
+ const base::Value::List* redirect_urls);
std::unique_ptr<WebAuthFlow> auth_flow_;
- GURL final_url_prefix_;
+ std::vector<GURL> final_url_domains_;
};
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_private_api.cc b/chromium/chrome/browser/extensions/api/identity/identity_private_api.cc
deleted file mode 100644
index 6737801a056..00000000000
--- a/chromium/chrome/browser/extensions/api/identity/identity_private_api.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/api/identity/identity_private_api.h"
-
-#include "chrome/browser/extensions/api/identity/identity_api.h"
-
-namespace extensions {
-
-IdentityPrivateSetConsentResultFunction::
- IdentityPrivateSetConsentResultFunction() = default;
-IdentityPrivateSetConsentResultFunction::
- ~IdentityPrivateSetConsentResultFunction() = default;
-
-ExtensionFunction::ResponseAction
-IdentityPrivateSetConsentResultFunction::Run() {
- absl::optional<Params> params = Params::Create(args());
- EXTENSION_FUNCTION_VALIDATE(params);
-
- IdentityAPI::GetFactoryInstance()
- ->Get(browser_context())
- ->SetConsentResult(params->result, params->window_id);
-
- return RespondNow(NoArguments());
-}
-
-} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_private_api.h b/chromium/chrome/browser/extensions/api/identity/identity_private_api.h
deleted file mode 100644
index a0c6cf921af..00000000000
--- a/chromium/chrome/browser/extensions/api/identity/identity_private_api.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_PRIVATE_API_H_
-#define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_PRIVATE_API_H_
-
-#include "chrome/common/extensions/api/identity_private.h"
-#include "extensions/browser/extension_function.h"
-
-namespace extensions {
-
-class IdentityPrivateSetConsentResultFunction : public ExtensionFunction {
- public:
- DECLARE_EXTENSION_FUNCTION("identityPrivate.setConsentResult",
- IDENTITYPRIVATE_SETCONSENTRESULT)
-
- IdentityPrivateSetConsentResultFunction();
-
- private:
- using Params = api::identity_private::SetConsentResult::Params;
- ~IdentityPrivateSetConsentResultFunction() override;
-
- ExtensionFunction::ResponseAction Run() override;
-};
-
-} // namespace extensions
-
-#endif // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_PRIVATE_API_H_
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_private_apitest.cc b/chromium/chrome/browser/extensions/api/identity/identity_private_apitest.cc
deleted file mode 100644
index 9fc9fc686be..00000000000
--- a/chromium/chrome/browser/extensions/api/identity/identity_private_apitest.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/api/identity/identity_private_api.h"
-
-#include "base/memory/scoped_refptr.h"
-#include "base/run_loop.h"
-#include "chrome/browser/extensions/api/identity/identity_api.h"
-#include "chrome/browser/extensions/extension_apitest.h"
-#include "content/public/test/browser_test.h"
-#include "extensions/browser/api_test_utils.h"
-
-namespace extensions {
-
-struct SetConsentResultParams {
- std::string consent_result;
- std::string window_id;
-};
-
-class IdentityPrivateApiTest : public ExtensionBrowserTest {
- protected:
- void SetUpOnMainThread() override {
- ExtensionBrowserTest::SetUpOnMainThread();
- callback_loop_ = std::make_unique<base::RunLoop>();
- // base::Unretained(this) is safe because the callback will be unregistered
- // on |callback_subscription_| destruction.
- callback_subscription_ = identity_api()->RegisterOnSetConsentResultCallback(
- base::BindRepeating(&IdentityPrivateApiTest::OnSetConsentResult,
- base::Unretained(this)));
- }
-
- IdentityAPI* identity_api() {
- return IdentityAPI::GetFactoryInstance()->Get(profile());
- }
-
- SetConsentResultParams WaitForConsentResult() {
- callback_loop_->Run();
- return {consent_result_, window_id_};
- }
-
- private:
- void OnSetConsentResult(const std::string& consent_result,
- const std::string& window_id) {
- consent_result_ = consent_result;
- window_id_ = window_id;
- callback_loop_->Quit();
- }
-
- std::string consent_result_;
- std::string window_id_;
- std::unique_ptr<base::RunLoop> callback_loop_;
- base::CallbackListSubscription callback_subscription_;
-};
-
-IN_PROC_BROWSER_TEST_F(IdentityPrivateApiTest, SetConsentResult) {
- scoped_refptr<ExtensionFunction> func =
- base::MakeRefCounted<IdentityPrivateSetConsentResultFunction>();
- bool success = api_test_utils::RunFunction(
- func.get(),
- std::string("[\"consent_result_value\", \"window_id_value\"]"),
- profile());
- ASSERT_TRUE(success);
- SetConsentResultParams params = WaitForConsentResult();
- EXPECT_EQ(params.consent_result, "consent_result_value");
- EXPECT_EQ(params.window_id, "window_id_value");
-}
-
-} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/identity/test_scoped_should_animate_web_auth_flow_info_bar.h b/chromium/chrome/browser/extensions/api/identity/test_scoped_should_animate_web_auth_flow_info_bar.h
deleted file mode 100644
index cc378b42fa7..00000000000
--- a/chromium/chrome/browser/extensions/api/identity/test_scoped_should_animate_web_auth_flow_info_bar.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_API_IDENTITY_TEST_SCOPED_SHOULD_ANIMATE_WEB_AUTH_FLOW_INFO_BAR_H_
-#define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_TEST_SCOPED_SHOULD_ANIMATE_WEB_AUTH_FLOW_INFO_BAR_H_
-
-#include "chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-
-namespace extensions {
-
-class TestScopedShouldAnimateWebAuthFlowInfoBar {
- public:
- explicit TestScopedShouldAnimateWebAuthFlowInfoBar(bool should_animate) {
- previous_state_ = WebAuthFlowInfoBarDelegate::should_animate_for_testing_;
- WebAuthFlowInfoBarDelegate::should_animate_for_testing_ = should_animate;
- }
-
- ~TestScopedShouldAnimateWebAuthFlowInfoBar() {
- WebAuthFlowInfoBarDelegate::should_animate_for_testing_ = previous_state_;
- }
-
- private:
- absl::optional<bool> previous_state_;
-};
-
-} // namespace extensions
-
-#endif // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_TEST_SCOPED_SHOULD_ANIMATE_WEB_AUTH_FLOW_INFO_BAR_H_
diff --git a/chromium/chrome/browser/extensions/api/identity/web_auth_flow.cc b/chromium/chrome/browser/extensions/api/identity/web_auth_flow.cc
index ee6bfbcbbb0..affc352d603 100644
--- a/chromium/chrome/browser/extensions/api/identity/web_auth_flow.cc
+++ b/chromium/chrome/browser/extensions/api/identity/web_auth_flow.cc
@@ -7,31 +7,16 @@
#include <memory>
#include <utility>
-#include "base/base64.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
-#include "base/location.h"
-#include "base/notreached.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/trace_event/trace_event.h"
#include "chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h"
-#include "chrome/browser/extensions/component_loader.h"
-#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_navigator.h"
-#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
-#include "chrome/common/chrome_features.h"
-#include "chrome/common/extensions/api/identity_private.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/grit/browser_resources.h"
-#include "components/guest_view/browser/guest_view_base.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
@@ -39,75 +24,22 @@
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
-#include "crypto/random.h"
-#include "extensions/browser/app_window/app_window.h"
-#include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_system.h"
-#include "extensions/browser/guest_view/web_view/web_view_guest.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "ui/base/page_transition_types.h"
-#include "ui/base/window_open_disposition.h"
#include "url/gurl.h"
#include "url/url_constants.h"
-using content::RenderViewHost;
using content::WebContents;
using content::WebContentsObserver;
-using guest_view::GuestViewBase;
namespace extensions {
-namespace {
-
-// Returns whether `partition` should be persisted on disk.
-bool ShouldPersistStorage(WebAuthFlow::Partition partition) {
- switch (partition) {
- case WebAuthFlow::LAUNCH_WEB_AUTH_FLOW:
- return base::FeatureList::IsEnabled(kPersistentStorageForWebAuthFlow);
- case WebAuthFlow::GET_AUTH_TOKEN:
- return false;
- }
-
- NOTREACHED() << "Unexpected partition value " << partition;
- return false;
-}
-
-// Returns a unique identifier of the storage partition corresponding to
-// `partition`.
-std::string GetStoragePartitionId(WebAuthFlow::Partition partition) {
- switch (partition) {
- case WebAuthFlow::LAUNCH_WEB_AUTH_FLOW:
- return "launchWebAuthFlow";
- case WebAuthFlow::GET_AUTH_TOKEN:
- return "getAuthFlow";
- }
-
- NOTREACHED() << "Unexpected partition value " << partition;
- return std::string();
-}
-
-// Returns a partition name suitable to use in the `webview.partition`
-// parameter.
-std::string GetPartitionNameForWebView(WebAuthFlow::Partition partition) {
- std::string persist_prefix =
- ShouldPersistStorage(partition) ? "persist:" : "";
- return persist_prefix + GetStoragePartitionId(partition);
-}
-} // namespace
-
-namespace identity_private = api::identity_private;
-
-BASE_FEATURE(kPersistentStorageForWebAuthFlow,
- "PersistentStorageForWebAuthFlow",
- base::FEATURE_DISABLED_BY_DEFAULT);
-
WebAuthFlow::WebAuthFlow(
Delegate* delegate,
Profile* profile,
const GURL& provider_url,
Mode mode,
- Partition partition,
bool user_gesture,
AbortOnLoad abort_on_load_for_non_interactive,
absl::optional<base::TimeDelta> timeout_for_non_interactive)
@@ -115,7 +47,6 @@ WebAuthFlow::WebAuthFlow(
profile_(profile),
provider_url_(provider_url),
mode_(mode),
- partition_(partition),
user_gesture_(user_gesture),
abort_on_load_for_non_interactive_(abort_on_load_for_non_interactive),
timeout_for_non_interactive_(timeout_for_non_interactive),
@@ -130,7 +61,7 @@ WebAuthFlow::WebAuthFlow(
WebAuthFlow::~WebAuthFlow() {
DCHECK(!delegate_);
- if (using_auth_with_browser_tab_ && web_contents()) {
+ if (web_contents()) {
web_contents()->Close();
}
@@ -140,12 +71,6 @@ WebAuthFlow::~WebAuthFlow() {
// below may generate notifications.
WebContentsObserver::Observe(nullptr);
- if (!app_window_key_.empty()) {
- AppWindowRegistry::Get(profile_)->RemoveObserver(this);
-
- if (app_window_ && app_window_->web_contents())
- app_window_->web_contents()->Close();
- }
TRACE_EVENT_NESTABLE_ASYNC_END0("identity", "WebAuthFlow", this);
}
@@ -161,54 +86,12 @@ void WebAuthFlow::Start() {
DCHECK(profile_);
DCHECK(!profile_->IsOffTheRecord());
- if (base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab)) {
- using_auth_with_browser_tab_ = true;
-
- content::WebContents::CreateParams params(profile_);
- web_contents_ = content::WebContents::Create(params);
- WebContentsObserver::Observe(web_contents_.get());
+ content::WebContents::CreateParams params(profile_);
+ web_contents_ = content::WebContents::Create(params);
+ WebContentsObserver::Observe(web_contents_.get());
- content::NavigationController::LoadURLParams load_params(provider_url_);
- web_contents_->GetController().LoadURLWithParams(load_params);
-
- MaybeStartTimeout();
- return;
- }
-
- AppWindowRegistry::Get(profile_)->AddObserver(this);
-
- // Attach a random ID string to the window so we can recognize it
- // in OnAppWindowAdded.
- std::string random_bytes;
- crypto::RandBytes(base::WriteInto(&random_bytes, 33), 32);
- base::Base64Encode(random_bytes, &app_window_key_);
-
- // identityPrivate.onWebFlowRequest(app_window_key, provider_url_, mode_)
- base::Value::List args;
- args.Append(app_window_key_);
- args.Append(provider_url_.spec());
- if (mode_ == WebAuthFlow::INTERACTIVE)
- args.Append("interactive");
- else
- args.Append("silent");
- args.Append(GetPartitionNameForWebView(partition_));
-
- auto event =
- std::make_unique<Event>(events::IDENTITY_PRIVATE_ON_WEB_FLOW_REQUEST,
- identity_private::OnWebFlowRequest::kEventName,
- std::move(args), profile_);
- ExtensionSystem* system = ExtensionSystem::Get(profile_);
-
- extensions::ComponentLoader* component_loader =
- system->extension_service()->component_loader();
- if (!component_loader->Exists(extension_misc::kIdentityApiUiAppId)) {
- component_loader->Add(
- IDR_IDENTITY_API_SCOPE_APPROVAL_MANIFEST,
- base::FilePath(FILE_PATH_LITERAL("identity_scope_approval_dialog")));
- }
-
- EventRouter::Get(profile_)->DispatchEventWithLazyListener(
- extension_misc::kIdentityApiUiAppId, std::move(event));
+ content::NavigationController::LoadURLParams load_params(provider_url_);
+ web_contents_->GetController().LoadURLWithParams(load_params);
MaybeStartTimeout();
}
@@ -219,67 +102,8 @@ void WebAuthFlow::DetachDelegateAndDelete() {
this);
}
-content::StoragePartition* WebAuthFlow::GetGuestPartition() {
- // When using the Auth through the Browser Tab, the guest partition shouldn't
- // be used, consider using `Profile::GetDefaultStoragePartition()` instead.
- if (base::FeatureList::IsEnabled(features::kWebAuthFlowInBrowserTab)) {
- return nullptr;
- }
-
- return profile_->GetStoragePartition(
- GetWebViewPartitionConfig(partition_, profile_));
-}
-
-const std::string& WebAuthFlow::GetAppWindowKey() const {
- return app_window_key_;
-}
-
-// static
-content::StoragePartitionConfig WebAuthFlow::GetWebViewPartitionConfig(
- Partition partition,
- content::BrowserContext* browser_context) {
- // This has to mirror the logic in WebViewGuest::CreateWebContents for
- // creating the correct StoragePartitionConfig.
- auto result = content::StoragePartitionConfig::Create(
- browser_context, extension_misc::kIdentityApiUiAppId,
- GetStoragePartitionId(partition),
- /*in_memory=*/!ShouldPersistStorage(partition));
- result.set_fallback_to_partition_domain_for_blob_urls(
- browser_context->IsOffTheRecord()
- ? content::StoragePartitionConfig::FallbackMode::
- kFallbackPartitionInMemory
- : content::StoragePartitionConfig::FallbackMode::
- kFallbackPartitionOnDisk);
- return result;
-}
-
-void WebAuthFlow::OnAppWindowAdded(AppWindow* app_window) {
- if (app_window->window_key() == app_window_key_ &&
- app_window->extension_id() == extension_misc::kIdentityApiUiAppId) {
- app_window_ = app_window;
- WebContentsObserver::Observe(app_window->web_contents());
- }
-}
-
-void WebAuthFlow::OnAppWindowRemoved(AppWindow* app_window) {
- if (app_window->window_key() == app_window_key_ &&
- app_window->extension_id() == extension_misc::kIdentityApiUiAppId) {
- app_window_ = nullptr;
- WebContentsObserver::Observe(nullptr);
-
- if (delegate_)
- delegate_->OnAuthFlowFailure(WebAuthFlow::WINDOW_CLOSED);
- }
-}
-
-bool WebAuthFlow::IsObservingProviderWebContents() const {
- return web_contents() &&
- (embedded_window_created_ || using_auth_with_browser_tab_);
-}
-
void WebAuthFlow::DisplayInfoBar() {
DCHECK(web_contents());
- DCHECK(using_auth_with_browser_tab_);
info_bar_delegate_ = WebAuthFlowInfoBarDelegate::Create(
web_contents(), info_bar_parameters_.extension_display_name);
@@ -291,11 +115,6 @@ void WebAuthFlow::CloseInfoBar() {
}
}
-bool WebAuthFlow::IsDisplayingAuthPageInTab() const {
- // If web_contents_ is nullptr, then the auth page tab is opened.
- return using_auth_with_browser_tab_ && !web_contents_;
-}
-
bool WebAuthFlow::DisplayAuthPageInPopupWindow() {
if (Browser::GetCreationStatusForProfile(profile_) !=
Browser::CreationStatus::kOk) {
@@ -318,15 +137,14 @@ bool WebAuthFlow::DisplayAuthPageInPopupWindow() {
}
void WebAuthFlow::BeforeUrlLoaded(const GURL& url) {
- if (delegate_ && IsObservingProviderWebContents()) {
+ if (delegate_) {
delegate_->OnAuthFlowURLChange(url);
}
}
void WebAuthFlow::AfterUrlLoaded() {
initial_url_loaded_ = true;
- if (delegate_ && IsObservingProviderWebContents() &&
- mode_ == WebAuthFlow::SILENT) {
+ if (delegate_ && mode_ == WebAuthFlow::SILENT) {
if (abort_on_load_for_non_interactive_ == AbortOnLoad::kYes) {
non_interactive_timeout_timer_->Stop();
delegate_->OnAuthFlowFailure(WebAuthFlow::INTERACTION_REQUIRED);
@@ -338,27 +156,11 @@ void WebAuthFlow::AfterUrlLoaded() {
// If `web_contents_` is nullptr, this means that the interactive tab has
// already been opened once.
- if (delegate_ && using_auth_with_browser_tab_ && web_contents_ &&
- mode_ == WebAuthFlow::INTERACTIVE) {
- switch (features::kWebAuthFlowInBrowserTabMode.Get()) {
- case features::WebAuthFlowInBrowserTabMode::kNewTab: {
- // Displays the auth page in a new tab attached to an existing/new
- // browser.
- chrome::ScopedTabbedBrowserDisplayer browser_displayer(profile_);
- NavigateParams params(browser_displayer.browser(),
- std::move(web_contents_));
- Navigate(&params);
- break;
- }
- case features::WebAuthFlowInBrowserTabMode::kPopupWindow: {
- bool is_auth_page_displayed = DisplayAuthPageInPopupWindow();
- if (!is_auth_page_displayed) {
- delegate_->OnAuthFlowFailure(
- WebAuthFlow::Failure::CANNOT_CREATE_WINDOW);
- return;
- }
- break;
- }
+ if (delegate_ && web_contents_ && mode_ == WebAuthFlow::INTERACTIVE) {
+ bool is_auth_page_displayed = DisplayAuthPageInPopupWindow();
+ if (!is_auth_page_displayed) {
+ delegate_->OnAuthFlowFailure(WebAuthFlow::Failure::CANNOT_CREATE_WINDOW);
+ return;
}
if (info_bar_parameters_.should_show) {
@@ -394,26 +196,6 @@ void WebAuthFlow::OnTimeout() {
}
}
-void WebAuthFlow::InnerWebContentsCreated(
- content::WebContents* inner_web_contents) {
- DCHECK(app_window_);
-
- if (!delegate_ || embedded_window_created_)
- return;
-
- // Switch from watching the app window to the guest inside it.
- embedded_window_created_ = true;
- WebContentsObserver::Observe(inner_web_contents);
-}
-
-void WebAuthFlow::PrimaryMainFrameRenderProcessGone(
- base::TerminationStatus status) {
- // When in `using_auth_with_browser_tab_` mode,
- // `WebAuthFlow::WebContentsDestroyed()` takes care of this flow.
- if (delegate_ && !using_auth_with_browser_tab_)
- delegate_->OnAuthFlowFailure(WebAuthFlow::WINDOW_CLOSED);
-}
-
void WebAuthFlow::WebContentsDestroyed() {
WebContentsObserver::Observe(nullptr);
if (delegate_) {
@@ -432,22 +214,6 @@ void WebAuthFlow::DidStopLoading() {
void WebAuthFlow::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
- // If the navigation is initiated by the user, the tab will exit the auth
- // flow screen, this should result in a declined authentication and deleting
- // the flow.
- // These conditions do not apply for the Popup Window, where the url bar is
- // deactivated and the user cannot navigate away directly, to allow going back
- // and forth within the same flow.
- if (IsDisplayingAuthPageInTab() &&
- features::kWebAuthFlowInBrowserTabMode.Get() !=
- features::WebAuthFlowInBrowserTabMode::kPopupWindow &&
- !navigation_handle->IsRendererInitiated()) {
- // Stop observing the web contents since it is not part of the flow anymore.
- WebContentsObserver::Observe(nullptr);
- delegate_->OnAuthFlowFailure(Failure::USER_NAVIGATED_AWAY);
- return;
- }
-
if (navigation_handle->IsInPrimaryMainFrame()) {
BeforeUrlLoaded(navigation_handle->GetURL());
}
diff --git a/chromium/chrome/browser/extensions/api/identity/web_auth_flow.h b/chromium/chrome/browser/extensions/api/identity/web_auth_flow.h
index acacaf3b44d..3fe9f2b11bd 100644
--- a/chromium/chrome/browser/extensions/api/identity/web_auth_flow.h
+++ b/chromium/chrome/browser/extensions/api/identity/web_auth_flow.h
@@ -11,11 +11,8 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
-#include "content/public/browser/storage_partition_config.h"
#include "content/public/browser/web_contents_observer.h"
-#include "extensions/browser/app_window/app_window_registry.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
-#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
class Profile;
@@ -25,22 +22,14 @@ class OneShotTimer;
class TickClock;
} // namespace base
-namespace content {
-class StoragePartition;
-}
-
namespace extensions {
class WebAuthFlowInfoBarDelegate;
-// When enabled, cookies in the `launchWebAuthFlow()` partition are persisted
-// across browser restarts.
-BASE_DECLARE_FEATURE(kPersistentStorageForWebAuthFlow);
-
// Controller class for web based auth flows. The WebAuthFlow creates
-// a dialog window in the scope approval component app by firing an
-// event. A webview embedded in the dialog will navigate to the
-// |provider_url| passed to the WebAuthFlow constructor.
+// a browser popup window (or a new tab based on the feature setting)
+// with a webview that will navigate to the |provider_url| passed to the
+// WebAuthFlow constructor.
//
// The WebAuthFlow monitors the WebContents of the webview, and
// notifies its delegate interface any time the WebContents navigates
@@ -54,24 +43,17 @@ BASE_DECLARE_FEATURE(kPersistentStorageForWebAuthFlow);
//
// A WebAuthFlow can be started in Mode::SILENT, which never displays
// a window. If a window would be required, the flow fails.
-class WebAuthFlow : public content::WebContentsObserver,
- public AppWindowRegistry::Observer {
+class WebAuthFlow : public content::WebContentsObserver {
public:
enum Mode {
INTERACTIVE, // Show UI to the user if necessary.
SILENT // No UI should be shown.
};
- enum Partition {
- GET_AUTH_TOKEN, // Use the getAuthToken() partition.
- LAUNCH_WEB_AUTH_FLOW // Use the launchWebAuthFlow() partition.
- };
-
enum Failure {
WINDOW_CLOSED, // Window closed by user (app or tab).
INTERACTION_REQUIRED, // Non-redirect page load in silent mode.
LOAD_FAILED,
- USER_NAVIGATED_AWAY, // The user navigated away from the auth page.
TIMED_OUT,
CANNOT_CREATE_WINDOW // Couldn't create a browser window.
};
@@ -110,7 +92,6 @@ class WebAuthFlow : public content::WebContentsObserver,
Profile* profile,
const GURL& provider_url,
Mode mode,
- Partition partition,
bool user_gesture,
AbortOnLoad abort_on_load_for_non_interactive = AbortOnLoad::kYes,
absl::optional<base::TimeDelta> timeout_for_non_interactive =
@@ -131,19 +112,6 @@ class WebAuthFlow : public content::WebContentsObserver,
// Prevents further calls to the delegate and deletes the flow.
void DetachDelegateAndDelete();
- // Returns a StoragePartition of the guest webview. Used to inject cookies
- // into Gaia page. Can override for testing.
- virtual content::StoragePartition* GetGuestPartition();
-
- // Returns an ID string attached to the window. Can override for testing.
- virtual const std::string& GetAppWindowKey() const;
-
- // Returns the StoragePartitionConfig for a given |partition| used in the
- // WebAuthFlow.
- static content::StoragePartitionConfig GetWebViewPartitionConfig(
- Partition partition,
- content::BrowserContext* browser_context);
-
// This call will make the interactive mode, that opens up a browser tab for
// auth, display an Infobar that shows the extension name.
void SetShouldShowInfoBar(const std::string& extension_display_name);
@@ -152,16 +120,8 @@ class WebAuthFlow : public content::WebContentsObserver,
base::WeakPtr<WebAuthFlowInfoBarDelegate> GetInfoBarDelegateForTesting();
private:
- // ::AppWindowRegistry::Observer implementation.
- void OnAppWindowAdded(AppWindow* app_window) override;
- void OnAppWindowRemoved(AppWindow* app_window) override;
-
// WebContentsObserver implementation.
void DidStopLoading() override;
- void InnerWebContentsCreated(
- content::WebContents* inner_web_contents) override;
- void PrimaryMainFrameRenderProcessGone(
- base::TerminationStatus status) override;
void WebContentsDestroyed() override;
void TitleWasSet(content::NavigationEntry* entry) override;
void DidStartNavigation(
@@ -177,31 +137,17 @@ class WebAuthFlow : public content::WebContentsObserver,
void MaybeStartTimeout();
void OnTimeout();
- bool IsObservingProviderWebContents() const;
-
bool DisplayAuthPageInPopupWindow();
void DisplayInfoBar();
void CloseInfoBar();
- bool IsDisplayingAuthPageInTab() const;
-
raw_ptr<Delegate> delegate_ = nullptr;
const raw_ptr<Profile> profile_;
const GURL provider_url_;
const Mode mode_;
- const Partition partition_;
const bool user_gesture_;
- // Variables used only if displaying the auth flow in an app window.
- raw_ptr<AppWindow> app_window_ = nullptr;
- std::string app_window_key_;
- bool embedded_window_created_ = false;
-
- // Variables used only if displaying the auth flow in a browser tab.
- //
- // Checks that the auth with browser tab is activated.
- bool using_auth_with_browser_tab_ = false;
// WebContents used to initialize the authentication. It is not displayed
// and not owned by browser window. This WebContents is observed by
// `this`. When this value becomes nullptr, this means that the browser tab
diff --git a/chromium/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc b/chromium/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc
index d2322bcd205..98fbef9f164 100644
--- a/chromium/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/identity/web_auth_flow_browsertest.cc
@@ -8,10 +8,8 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
-#include "base/test/test_future.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/time/time.h"
-#include "chrome/browser/extensions/api/identity/test_scoped_should_animate_web_auth_flow_info_bar.h"
#include "chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
@@ -21,11 +19,9 @@
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/common/chrome_features.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/keep_alive_registry/keep_alive_types.h"
#include "components/keep_alive_registry/scoped_keep_alive.h"
-#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/back_forward_cache_util.h"
#include "content/public/test/browser_test.h"
@@ -78,7 +74,6 @@ class WebAuthFlowBrowserTest : public InProcessBrowserTest {
void StartWebAuthFlow(
const GURL& url,
- WebAuthFlow::Partition partition = WebAuthFlow::LAUNCH_WEB_AUTH_FLOW,
WebAuthFlow::Mode mode = WebAuthFlow::Mode::INTERACTIVE,
Profile* profile = nullptr,
WebAuthFlow::AbortOnLoad abort_on_load_for_non_interactive =
@@ -89,7 +84,7 @@ class WebAuthFlowBrowserTest : public InProcessBrowserTest {
profile = browser()->profile();
web_auth_flow_ = std::make_unique<WebAuthFlow>(
- &mock_web_auth_flow_delegate_, profile, url, mode, partition,
+ &mock_web_auth_flow_delegate_, profile, url, mode,
/*user_gesture=*/true, abort_on_load_for_non_interactive,
timeout_for_non_interactive);
@@ -120,17 +115,8 @@ class WebAuthFlowBrowserTest : public InProcessBrowserTest {
scoped_refptr<base::TestMockTimeTaskRunner> timeout_task_runner_;
};
-class WebAuthFlowInBrowserTabParamBrowserTest
- : public WebAuthFlowBrowserTest,
- public testing::WithParamInterface<bool> {
+class WebAuthFlowInBrowserTabParamBrowserTest : public WebAuthFlowBrowserTest {
public:
- WebAuthFlowInBrowserTabParamBrowserTest() {
- scoped_feature_list_.InitWithFeatureState(
- features::kWebAuthFlowInBrowserTab, use_tab_feature_enabled());
- }
-
- bool use_tab_feature_enabled() { return GetParam(); }
-
bool JsRedirectToUrl(const GURL& url) {
content::TestNavigationObserver redirect_observer(url);
redirect_observer.WatchExistingWebContents();
@@ -142,12 +128,9 @@ class WebAuthFlowInBrowserTabParamBrowserTest
}
return result;
}
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
};
-IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowInBrowserTabParamBrowserTest,
OnAuthFlowURLChangeCalled) {
const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
@@ -163,7 +146,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
navigation_observer.WaitForNavigationFinished();
}
-IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowInBrowserTabParamBrowserTest,
OnAuthFlowFailureChangeCalled) {
// Navigate to a url that doesn't exist.
const GURL error_url = embedded_test_server()->GetURL("/error");
@@ -182,7 +165,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// Tests that the flow launched in silent mode with default parameters will
// terminate immediately with the "interacation required" error if the page
// loads and does not navigate to the redirect URL.
-IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowInBrowserTabParamBrowserTest,
OnAuthFlowFailureCalledInteractionRequired) {
const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
@@ -195,8 +178,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// In SILENT mode, DidStopLoading() will force the auth flow to fail if it has
// not already redirected, because we did not specify a timeout.
EXPECT_CALL(mock(), OnAuthFlowFailure(WebAuthFlow::INTERACTION_REQUIRED));
- StartWebAuthFlow(auth_url, WebAuthFlow::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::SILENT);
+ StartWebAuthFlow(auth_url, WebAuthFlow::SILENT);
navigation_observer.Wait();
}
@@ -205,7 +187,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// `abortOnLoadForNonInteractive` set to `false` will terminate with the
// "interaction required" after a specified timeout if the page loads and does
// not navigate to the redirect URL.
-IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowInBrowserTabParamBrowserTest,
OnAuthFlowInteractionRequiredWithTimeout) {
const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
@@ -218,8 +200,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// In SILENT mode, DidStopLoading() will wait for our specified 50ms timeout
// before calling OnAuthFlowFailure.
EXPECT_CALL(mock(), OnAuthFlowFailure).Times(0);
- StartWebAuthFlow(auth_url, WebAuthFlow::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::SILENT, /*profile=*/nullptr,
+ StartWebAuthFlow(auth_url, WebAuthFlow::SILENT, /*profile=*/nullptr,
WebAuthFlow::AbortOnLoad::kNo,
/*timeout_for_non_interactive=*/base::Milliseconds(50));
navigation_observer.Wait();
@@ -239,7 +220,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// `abortOnLoadForNonInteractive` set to `false` will terminate with the
// "interaction required" error after a default timeout if the page loads and
// does not navigate to the redirect URL.
-IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowInBrowserTabParamBrowserTest,
OnAuthFlowInteractionRequiredWithDefaultTimeout) {
const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
@@ -252,8 +233,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// In SILENT mode, DidStopLoading() will wait for the default 1 minute timeout
// before calling OnAuthFlowFailure.
EXPECT_CALL(mock(), OnAuthFlowFailure).Times(0);
- StartWebAuthFlow(auth_url, WebAuthFlow::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::SILENT, /*profile=*/nullptr,
+ StartWebAuthFlow(auth_url, WebAuthFlow::SILENT, /*profile=*/nullptr,
WebAuthFlow::AbortOnLoad::kNo);
navigation_observer.Wait();
testing::Mock::VerifyAndClearExpectations(&mock());
@@ -274,7 +254,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// set will terminate with the "timed out" error after a timeout if the page
// fails to load (distinct from the flow failing to navigate to the redirect URL
// in time).
-IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowInBrowserTabParamBrowserTest,
OnAuthFlowPageLoadTimeout) {
const GURL auth_url = embedded_test_server()->GetURL("/hung-after-headers");
@@ -287,8 +267,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// In SILENT mode, DidStopLoading() will wait for our specified 50ms timeout
// before calling OnAuthFlowFailure.
EXPECT_CALL(mock(), OnAuthFlowFailure).Times(0);
- StartWebAuthFlow(auth_url, WebAuthFlow::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::SILENT, /*profile=*/nullptr,
+ StartWebAuthFlow(auth_url, WebAuthFlow::SILENT, /*profile=*/nullptr,
WebAuthFlow::AbortOnLoad::kYes,
/*timeout_for_non_interactive=*/base::Milliseconds(50));
// Wait for navigation to the failing page to start first.
@@ -310,7 +289,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// `abortOnLoadForNonInteractive` set to `false` and
// `timeoutMsForNonInteractive` set will succeed if it navigates to the redirect
// URL before the timeout.
-IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowInBrowserTabParamBrowserTest,
OnAuthFlowRedirectBeforeTimeout) {
const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
@@ -323,8 +302,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// In SILENT mode, DidStopLoading() will wait for our specified 50ms timeout
// before calling OnAuthFlowFailure.
EXPECT_CALL(mock(), OnAuthFlowFailure).Times(0);
- StartWebAuthFlow(auth_url, WebAuthFlow::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::SILENT, /*profile=*/nullptr,
+ StartWebAuthFlow(auth_url, WebAuthFlow::SILENT, /*profile=*/nullptr,
WebAuthFlow::AbortOnLoad::kNo,
/*timeout_for_non_interactive=*/base::Milliseconds(50));
@@ -344,7 +322,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// Tests that the loaded auth page can redirect multiple times and fails only
// after the timeout.
-IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowInBrowserTabParamBrowserTest,
OnAuthFlowMultipleRedirects) {
const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
@@ -357,8 +335,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
// In SILENT mode, DidStopLoading() will wait for our specified 50ms timeout
// before calling OnAuthFlowFailure.
EXPECT_CALL(mock(), OnAuthFlowFailure).Times(0);
- StartWebAuthFlow(auth_url, WebAuthFlow::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::SILENT, /*profile=*/nullptr,
+ StartWebAuthFlow(auth_url, WebAuthFlow::SILENT, /*profile=*/nullptr,
WebAuthFlow::AbortOnLoad::kNo,
/*timeout_for_non_interactive=*/base::Milliseconds(50));
@@ -396,126 +373,6 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowInBrowserTabParamBrowserTest,
timeout_task_runner()->FastForwardBy(base::Milliseconds(30));
}
-INSTANTIATE_TEST_SUITE_P(
- ,
- WebAuthFlowInBrowserTabParamBrowserTest,
- testing::Bool(),
- [](const testing::TestParamInfo<
- WebAuthFlowInBrowserTabParamBrowserTest::ParamType>& info) {
- return base::StrCat(
- {info.param ? "With" : "Without", "WebAuthFlowInBrowserTab"});
- });
-
-class WebAuthFlowGuestPartitionParamTest
- : public WebAuthFlowBrowserTest,
- public testing::WithParamInterface<
- std::tuple<bool, WebAuthFlow::Partition>> {
- public:
- WebAuthFlowGuestPartitionParamTest() {
- std::vector<base::test::FeatureRef> enabled_features;
- std::vector<base::test::FeatureRef> disabled_features;
-
- persist_storage_feature_enabled()
- ? enabled_features.push_back(kPersistentStorageForWebAuthFlow)
- : disabled_features.push_back(kPersistentStorageForWebAuthFlow);
-
- // Explicitly disable the `kWebAuthFlowInBrowserTab` feature as it is
- // incompatible with the Guest Partition tests and
- // `kPersistentStorageForWebAuthFlow`.
- disabled_features.push_back(features::kWebAuthFlowInBrowserTab);
-
- scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
- }
-
- bool persist_storage_feature_enabled() { return std::get<0>(GetParam()); }
-
- WebAuthFlow::Partition partition() { return std::get<1>(GetParam()); }
-
- void LoadWebAuthFlow() {
- const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
-
- // Observer for waiting until a navigation to a url has finished.
- content::TestNavigationObserver navigation_observer(auth_url);
- navigation_observer.StartWatchingNewWebContents();
-
- StartWebAuthFlow(auth_url, partition());
- EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
-
- navigation_observer.WaitForNavigationFinished();
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-// Tests that the partition returned by `WebAuthFlow::GetGuestPartition()`
-// matches the one used by the webview.
-IN_PROC_BROWSER_TEST_P(WebAuthFlowGuestPartitionParamTest, GetGuestPartition) {
- LoadWebAuthFlow();
-
- // Set a test cookie on the page.
- ASSERT_TRUE(
- content::ExecJs(web_contents(), "document.cookie = \"testCookie=1\""));
-
- // Verify that the cookie was added to the guest partition.
- base::test::TestFuture<const net::CookieList&> get_cookies_future;
- web_auth_flow()
- ->GetGuestPartition()
- ->GetCookieManagerForBrowserProcess()
- ->GetAllCookies(get_cookies_future.GetCallback());
- const net::CookieList cookies = get_cookies_future.Get();
- ASSERT_EQ(1u, cookies.size());
- EXPECT_EQ("testCookie", cookies[0].Name());
- EXPECT_EQ("1", cookies[0].Value());
-}
-
-IN_PROC_BROWSER_TEST_P(WebAuthFlowGuestPartitionParamTest,
- PRE_PersistenceTest) {
- LoadWebAuthFlow();
- // Set a test cookie on the page.
- ASSERT_TRUE(content::ExecJs(
- web_contents(), "document.cookie = \"testCookie=1; max-age=3600\""));
-}
-
-IN_PROC_BROWSER_TEST_P(WebAuthFlowGuestPartitionParamTest, PersistenceTest) {
- LoadWebAuthFlow();
-
- base::test::TestFuture<const net::CookieList&> get_cookies_future;
- web_auth_flow()
- ->GetGuestPartition()
- ->GetCookieManagerForBrowserProcess()
- ->GetAllCookies(get_cookies_future.GetCallback());
- const net::CookieList cookies = get_cookies_future.Get();
-
- // Verify that the cookie set in the previous test is persisted for the
- // webAuthFlow if the feature is enabled.
- // Read from the cookie store directly rather than execute a script on the
- // auth page because the page URL changes between test (test server doesn't
- // have a fixed port).
- if (persist_storage_feature_enabled() &&
- partition() == WebAuthFlow::LAUNCH_WEB_AUTH_FLOW) {
- ASSERT_EQ(1u, cookies.size());
- EXPECT_EQ("testCookie", cookies[0].Name());
- EXPECT_EQ("1", cookies[0].Value());
- } else {
- EXPECT_EQ(0u, cookies.size());
- }
-}
-
-INSTANTIATE_TEST_SUITE_P(
- ,
- WebAuthFlowGuestPartitionParamTest,
- testing::Combine(testing::Bool(),
- testing::Values(WebAuthFlow::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::GET_AUTH_TOKEN)),
- [](const testing::TestParamInfo<
- WebAuthFlowGuestPartitionParamTest::ParamType>& info) {
- return base::StrCat(
- {std::get<0>(info.param) ? "FeatureOn" : "FeatureOff",
- std::get<1>(info.param) == WebAuthFlow::LAUNCH_WEB_AUTH_FLOW
- ? "WebAuthFlow"
- : "GetAuthToken"});
- });
class WebAuthFlowFencedFrameTest
: public WebAuthFlowInBrowserTabParamBrowserTest {
public:
@@ -527,7 +384,7 @@ class WebAuthFlowFencedFrameTest
content::test::FencedFrameTestHelper fenced_frame_helper_;
};
-IN_PROC_BROWSER_TEST_P(WebAuthFlowFencedFrameTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowFencedFrameTest,
FencedFrameNavigationSuccess) {
const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
@@ -554,7 +411,7 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowFencedFrameTest,
embedded_test_server()->GetURL("/fenced_frames/title1.html")));
}
-IN_PROC_BROWSER_TEST_P(WebAuthFlowFencedFrameTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowFencedFrameTest,
FencedFrameNavigationFailure) {
const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
@@ -582,27 +439,6 @@ IN_PROC_BROWSER_TEST_P(WebAuthFlowFencedFrameTest,
embedded_test_server()->GetURL("/error"), net::Error::ERR_FAILED));
}
-INSTANTIATE_TEST_SUITE_P(,
- WebAuthFlowFencedFrameTest,
- testing::Bool(),
- [](const testing::TestParamInfo<
- WebAuthFlowFencedFrameTest::ParamType>& info) {
- return base::StrCat({info.param ? "With" : "Without",
- "WebAuthFlowInBrowserTab"});
- });
-
-class WebAuthFlowWithBrowserTabBrowserTest : public WebAuthFlowBrowserTest {
- public:
- WebAuthFlowWithBrowserTabBrowserTest() {
- // By default the feature param is {{"browser_tab_mode", "popup_window"}}.
- scoped_feature_list_.InitAndEnableFeature(
- features::kWebAuthFlowInBrowserTab);
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
// This test is in two parts:
// - First create a WebAuthFlow in interactive mode that will create a new tab
// with the auth_url.
@@ -611,15 +447,14 @@ class WebAuthFlowWithBrowserTabBrowserTest : public WebAuthFlowBrowserTest {
//
// These two tests are combined into one in order not to re-test the tab
// creation twice.
-IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowBrowserTest,
InteractivePopupWindowCreatedWithAuthURL_ThenCloseTab) {
const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
content::TestNavigationObserver navigation_observer(auth_url);
navigation_observer.StartWatchingNewWebContents();
EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
- StartWebAuthFlow(auth_url, WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::Mode::INTERACTIVE);
+ StartWebAuthFlow(auth_url, WebAuthFlow::Mode::INTERACTIVE);
const char extension_name[] = "extension_name";
web_auth_flow()->SetShouldShowInfoBar(extension_name);
@@ -650,15 +485,14 @@ IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
}
IN_PROC_BROWSER_TEST_F(
- WebAuthFlowWithBrowserTabBrowserTest,
+ WebAuthFlowBrowserTest,
InteractivePopupWindowCreatedWithAuthURL_NavigationInURLDoesNotBreakTheFlow) {
const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
content::TestNavigationObserver navigation_observer(auth_url);
navigation_observer.StartWatchingNewWebContents();
EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
- StartWebAuthFlow(auth_url, WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::Mode::INTERACTIVE);
+ StartWebAuthFlow(auth_url, WebAuthFlow::Mode::INTERACTIVE);
web_auth_flow()->SetShouldShowInfoBar("extension name");
navigation_observer.Wait();
@@ -683,13 +517,6 @@ IN_PROC_BROWSER_TEST_F(
// Simulate an internal navigation, such as an authentication that needs an
// input of username and password on two different pages/urls.
GURL new_url = embedded_test_server()->GetURL("/title2.html");
- // Below a first navigation will be done, then going back on the initial auth
- // page, in the popup window mode the error should not trigger and the auth
- // flow should stay alive.
- EXPECT_CALL(mock(),
- OnAuthFlowFailure(WebAuthFlow::Failure::USER_NAVIGATED_AWAY))
- .Times(0);
-
EXPECT_CALL(mock(), OnAuthFlowURLChange(new_url));
ASSERT_TRUE(content::NavigateToURL(web_contents(), new_url));
@@ -713,7 +540,7 @@ IN_PROC_BROWSER_TEST_F(
}
IN_PROC_BROWSER_TEST_F(
- WebAuthFlowWithBrowserTabBrowserTest,
+ WebAuthFlowBrowserTest,
InteractiveNoBrowser_WebAuthCreatesBrowserWithPopupWindow) {
Profile* profile = browser()->profile();
// Simulates an extension being opened, in order for the profile not to be
@@ -730,8 +557,7 @@ IN_PROC_BROWSER_TEST_F(
navigation_observer.StartWatchingNewWebContents();
EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
- StartWebAuthFlow(auth_url, WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::Mode::INTERACTIVE, profile);
+ StartWebAuthFlow(auth_url, WebAuthFlow::Mode::INTERACTIVE, profile);
navigation_observer.Wait();
@@ -746,7 +572,7 @@ IN_PROC_BROWSER_TEST_F(
// This is a regression test for crbug/1445824, makes sure the opened popup
// window does not trigger Session restore.
-IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowBrowserTest,
InteractiveNoBrowser_NotActivatingSessionRestore) {
Profile* profile = browser()->profile();
@@ -767,8 +593,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
navigation_observer.StartWatchingNewWebContents();
EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
- StartWebAuthFlow(auth_url, WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::Mode::INTERACTIVE, profile);
+ StartWebAuthFlow(auth_url, WebAuthFlow::Mode::INTERACTIVE, profile);
navigation_observer.Wait();
// Makes sure only one browser is created and profile is not trying to restore
@@ -785,8 +610,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
auth_url);
}
-IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
- SilentNewTabNotCreated) {
+IN_PROC_BROWSER_TEST_F(WebAuthFlowBrowserTest, SilentNewTabNotCreated) {
TabStripModel* tabs = browser()->tab_strip_model();
int initial_tab_count = tabs->count();
@@ -797,8 +621,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
EXPECT_CALL(mock(),
OnAuthFlowFailure(WebAuthFlow::Failure::INTERACTION_REQUIRED));
EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
- StartWebAuthFlow(auth_url, WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::Mode::SILENT);
+ StartWebAuthFlow(auth_url, WebAuthFlow::Mode::SILENT);
navigation_observer.Wait();
@@ -806,15 +629,14 @@ IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
EXPECT_EQ(tabs->count(), initial_tab_count);
}
-IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowBrowserTest,
InteractiveNewTabCreatedWithAuthURL_NoInfoBarByDefault) {
const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
content::TestNavigationObserver navigation_observer(auth_url);
navigation_observer.StartWatchingNewWebContents();
EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
- StartWebAuthFlow(auth_url, WebAuthFlow::Partition::GET_AUTH_TOKEN,
- WebAuthFlow::Mode::INTERACTIVE);
+ StartWebAuthFlow(auth_url, WebAuthFlow::Mode::INTERACTIVE);
navigation_observer.Wait();
@@ -830,7 +652,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
EXPECT_FALSE(infobar_delegate);
}
-IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
+IN_PROC_BROWSER_TEST_F(WebAuthFlowBrowserTest,
PopupWindowOpened_ThenCloseWindow) {
size_t initial_browser_count = chrome::GetTotalBrowserCount();
@@ -839,8 +661,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
navigation_observer.StartWatchingNewWebContents();
EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
- StartWebAuthFlow(auth_url, WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::Mode::INTERACTIVE);
+ StartWebAuthFlow(auth_url, WebAuthFlow::Mode::INTERACTIVE);
navigation_observer.Wait();
@@ -865,7 +686,7 @@ IN_PROC_BROWSER_TEST_F(WebAuthFlowWithBrowserTabBrowserTest,
}
IN_PROC_BROWSER_TEST_F(
- WebAuthFlowWithBrowserTabBrowserTest,
+ WebAuthFlowBrowserTest,
Interactive_MarkedForDeletionProfileNotAllowedToCreatePopupWindow) {
// Marking active profile for deletion.
MarkProfileDirectoryForDeletion(browser()->profile()->GetPath());
@@ -880,78 +701,8 @@ IN_PROC_BROWSER_TEST_F(
// should return an error.
EXPECT_CALL(mock(),
OnAuthFlowFailure(WebAuthFlow::Failure::CANNOT_CREATE_WINDOW));
- StartWebAuthFlow(auth_url, WebAuthFlow::Partition::GET_AUTH_TOKEN,
- WebAuthFlow::Mode::INTERACTIVE);
+ StartWebAuthFlow(auth_url, WebAuthFlow::Mode::INTERACTIVE);
navigation_observer.Wait();
}
-class WebAuthFlowWithBrowserTabInNewTabBrowserTest
- : public WebAuthFlowBrowserTest {
- public:
- WebAuthFlowWithBrowserTabInNewTabBrowserTest() {
- // Enables feature with New tab mode.
- scoped_feature_list_.InitAndEnableFeatureWithParameters(
- features::kWebAuthFlowInBrowserTab, {{"browser_tab_mode", "new_tab"}});
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-IN_PROC_BROWSER_TEST_F(
- WebAuthFlowWithBrowserTabInNewTabBrowserTest,
- InteractiveNewTabCreatedWithAuthURL_ThenChangeURLBeforeAuthResult) {
- const GURL auth_url = embedded_test_server()->GetURL("/title1.html");
- content::TestNavigationObserver navigation_observer(auth_url);
- navigation_observer.StartWatchingNewWebContents();
-
- EXPECT_CALL(mock(), OnAuthFlowURLChange(auth_url));
- // Remove the animation mainly for the deleting part as it could create
- // flakiness when checking for the deletion of the info bar.
- TestScopedShouldAnimateWebAuthFlowInfoBar should_animate(false);
- StartWebAuthFlow(auth_url, WebAuthFlow::Partition::LAUNCH_WEB_AUTH_FLOW,
- WebAuthFlow::Mode::INTERACTIVE);
- web_auth_flow()->SetShouldShowInfoBar("extension name");
-
- navigation_observer.Wait();
-
- //---------------------------------------------------------------------
- // Browser-initiated URL change in the opened tab before completing the auth
- // flow should trigger an auth flow failure.
- //---------------------------------------------------------------------
- testing::Mock::VerifyAndClearExpectations(&mock());
-
- // Keeping a reference to the info bar delegate to check later.
- base::WeakPtr<WebAuthFlowInfoBarDelegate> auth_info_bar =
- web_auth_flow()->GetInfoBarDelegateForTesting();
- ASSERT_TRUE(auth_info_bar);
-
- Browser* newtab_browser = chrome::FindBrowserWithWebContents(web_contents());
- EXPECT_EQ(browser(), newtab_browser);
- TabStripModel* tabs = newtab_browser->tab_strip_model();
-
- // Simulating a non user navigation, it shouldn't break the flow.
- GURL internal_url = embedded_test_server()->GetURL("/title2.html");
- EXPECT_CALL(mock(), OnAuthFlowURLChange(internal_url));
- EXPECT_CALL(mock(), OnAuthFlowFailure(testing::_)).Times(0);
- ASSERT_TRUE(content::NavigateToURLFromRenderer(web_contents(), internal_url));
- EXPECT_TRUE(web_auth_flow());
- EXPECT_TRUE(auth_info_bar);
- testing::Mock::VerifyAndClearExpectations(&mock());
-
- // Simulating user manually navigating to another URL.
- GURL browsing_url = embedded_test_server()->GetURL("/simple.html");
- EXPECT_CALL(mock(),
- OnAuthFlowFailure(WebAuthFlow::Failure::USER_NAVIGATED_AWAY));
- ASSERT_TRUE(content::NavigateToURL(web_contents(), browsing_url));
-
- // New tab is not expected to be closed, it is now used for navigation and
- // not part of the flow anymore.
- EXPECT_FALSE(web_contents());
- EXPECT_FALSE(web_auth_flow());
- EXPECT_EQ(tabs->GetActiveWebContents()->GetLastCommittedURL(), browsing_url);
- // Infobar should be closed on navigation.
- EXPECT_FALSE(auth_info_bar);
-}
-
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.cc b/chromium/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.cc
index c9ad487f7e1..a84f713fd5c 100644
--- a/chromium/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.cc
+++ b/chromium/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.cc
@@ -16,9 +16,6 @@
namespace extensions {
-absl::optional<bool> WebAuthFlowInfoBarDelegate::should_animate_for_testing_ =
- absl::nullopt;
-
base::WeakPtr<WebAuthFlowInfoBarDelegate> WebAuthFlowInfoBarDelegate::Create(
content::WebContents* web_contents,
const std::string& extension_name) {
@@ -67,12 +64,4 @@ void WebAuthFlowInfoBarDelegate::CloseInfoBar() {
infobar()->RemoveSelf();
}
-bool WebAuthFlowInfoBarDelegate::ShouldAnimate() const {
- if (should_animate_for_testing_.has_value()) {
- return should_animate_for_testing_.value();
- }
-
- return ConfirmInfoBarDelegate::ShouldAnimate();
-}
-
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h b/chromium/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h
index 15429e47fb3..88eee975166 100644
--- a/chromium/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h
+++ b/chromium/chrome/browser/extensions/api/identity/web_auth_flow_info_bar_delegate.h
@@ -8,7 +8,6 @@
#include "components/infobars/core/confirm_infobar_delegate.h"
#include "base/memory/weak_ptr.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
namespace content {
class WebContents;
@@ -16,8 +15,6 @@ class WebContents;
namespace extensions {
-class TestScopedShouldAnimateWebAuthFlowInfoBar;
-
// Infobar used by extension auth flow `chrome.identity.launchWebAuthFlow()`
// when authentication is done through a Browser Tab. A browser tab is opened
// when needing action from the user in this flow.
@@ -40,19 +37,13 @@ class WebAuthFlowInfoBarDelegate : public ConfirmInfoBarDelegate {
// ConfirmInfoBarDelegate:
std::u16string GetMessageText() const override;
int GetButtons() const override;
- bool ShouldAnimate() const override;
// Closes the info bar this delegate is associated with.
void CloseInfoBar();
private:
- friend TestScopedShouldAnimateWebAuthFlowInfoBar;
-
explicit WebAuthFlowInfoBarDelegate(const std::string& extension_name);
- // Only controlled by `TestScopedShouldAnimateWebAuthFlowInfoBar`.
- static absl::optional<bool> should_animate_for_testing_;
-
const std::string extension_name_;
base::WeakPtrFactory<WebAuthFlowInfoBarDelegate> weak_factory_{this};
diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.cc b/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.cc
index ac96347fa34..80ae9c39a8f 100644
--- a/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.cc
+++ b/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.cc
@@ -13,6 +13,7 @@
#include "chromeos/lacros/lacros_service.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/event_router.h"
+#include "extensions/common/extension_id.h"
namespace image_writer_api = extensions::api::image_writer_private;
@@ -113,7 +114,7 @@ class ImageWriterControllerLacros::ImageWriterClientLacros
// Note: |this| is deleted at this point.
}
- const std::string extension_id_;
+ const ExtensionId extension_id_;
// Both pointers of |browser_context_| and |controller_| are guaranteed
// to be valid for the lifetime of this class, as destruction of either
// BrowserContext or ImageWriterControllerLacros will result in synchronous
diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/operation_manager.cc b/chromium/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
index 614302e4896..b0734b96152 100644
--- a/chromium/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
+++ b/chromium/chrome/browser/extensions/api/image_writer_private/operation_manager.cc
@@ -25,7 +25,6 @@
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_host.h"
-#include "extensions/browser/notification_types.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos_unittest.cc b/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos_unittest.cc
index 870709971da..adc0b2b3d3a 100644
--- a/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos_unittest.cc
@@ -102,7 +102,7 @@ class RemovableStorageProviderChromeOsUnitTest : public testing::Test {
}
content::BrowserTaskEnvironment task_environment_;
- raw_ptr<ash::disks::MockDiskMountManager, ExperimentalAsh>
+ raw_ptr<ash::disks::MockDiskMountManager, DanglingUntriaged | ExperimentalAsh>
disk_mount_manager_mock_;
scoped_refptr<StorageDeviceList> devices_;
};
diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_mac.cc b/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_mac.cc
index 3add088c13c..1ed76b28bcd 100644
--- a/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_mac.cc
+++ b/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_mac.cc
@@ -11,8 +11,8 @@
#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
#include <stdint.h>
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_cftyperef.h"
+#include "base/apple/foundation_util.h"
+#include "base/apple/scoped_cftyperef.h"
#include "base/mac/scoped_ioobject.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/sys_string_conversions.h"
@@ -27,7 +27,7 @@ RemovableStorageProvider::PopulateDeviceList() {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
// Match only writable whole-disks.
- base::ScopedCFTypeRef<CFMutableDictionaryRef> matching(
+ base::apple::ScopedCFTypeRef<CFMutableDictionaryRef> matching(
IOServiceMatching(kIOMediaClass));
CFDictionaryAddValue(matching, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
CFDictionaryAddValue(matching, CFSTR(kIOMediaWritableKey), kCFBooleanTrue);
@@ -54,7 +54,7 @@ RemovableStorageProvider::PopulateDeviceList() {
if (!is_suitable)
continue;
- base::ScopedCFTypeRef<CFMutableDictionaryRef> dict;
+ base::apple::ScopedCFTypeRef<CFMutableDictionaryRef> dict;
if (IORegistryEntryCreateCFProperties(disk_obj, dict.InitializeInto(),
kCFAllocatorDefault,
0) != KERN_SUCCESS) {
@@ -62,12 +62,10 @@ RemovableStorageProvider::PopulateDeviceList() {
continue;
}
- base::ScopedCFTypeRef<CFDictionaryRef> characteristics(
+ base::apple::ScopedCFTypeRef<CFDictionaryRef> characteristics(
static_cast<CFDictionaryRef>(IORegistryEntrySearchCFProperty(
- disk_obj,
- kIOServicePlane,
- CFSTR(kIOPropertyDeviceCharacteristicsKey),
- kCFAllocatorDefault,
+ disk_obj, kIOServicePlane,
+ CFSTR(kIOPropertyDeviceCharacteristicsKey), kCFAllocatorDefault,
kIORegistryIterateParents | kIORegistryIterateRecursively)));
if (!characteristics) {
@@ -75,11 +73,11 @@ RemovableStorageProvider::PopulateDeviceList() {
continue;
}
- CFStringRef cf_vendor = base::mac::GetValueFromDictionary<CFStringRef>(
+ CFStringRef cf_vendor = base::apple::GetValueFromDictionary<CFStringRef>(
characteristics, CFSTR(kIOPropertyVendorNameKey));
std::string vendor = base::SysCFStringRefToUTF8(cf_vendor);
- CFStringRef cf_model = base::mac::GetValueFromDictionary<CFStringRef>(
+ CFStringRef cf_model = base::apple::GetValueFromDictionary<CFStringRef>(
characteristics, CFSTR(kIOPropertyProductNameKey));
std::string model = base::SysCFStringRefToUTF8(cf_model);
diff --git a/chromium/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chromium/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index 6bd29e79444..e36c0a59364 100644
--- a/chromium/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chromium/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -26,6 +26,7 @@
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/process_manager.h"
#include "extensions/common/manifest_handlers/background_info.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/ime/ash/component_extension_ime_manager.h"
#include "ui/base/ime/ash/extension_ime_util.h"
#include "ui/base/ime/ash/ime_keymap.h"
@@ -854,7 +855,7 @@ class ImeObserverChromeOS
}
}
- std::string extension_id_;
+ extensions::ExtensionId extension_id_;
raw_ptr<Profile, DanglingUntriaged> profile_;
};
@@ -919,7 +920,9 @@ bool InputImeEventRouter::RegisterImeExtension(
std::string(), // TODO(uekawa): Set short name.
layout, languages,
false, // 3rd party IMEs are always not for login.
- component.options_page_url, component.input_view_url));
+ component.options_page_url, component.input_view_url,
+ // Not applicable to 3rd-party IMEs.
+ /*handwriting_language=*/absl::nullopt));
}
}
diff --git a/chromium/chrome/browser/extensions/api/input_ime/input_ime_apitest_chromeos.cc b/chromium/chrome/browser/extensions/api/input_ime/input_ime_apitest_chromeos.cc
index 5b09ea8f979..ab6c7b226b8 100644
--- a/chromium/chrome/browser/extensions/api/input_ime/input_ime_apitest_chromeos.cc
+++ b/chromium/chrome/browser/extensions/api/input_ime/input_ime_apitest_chromeos.cc
@@ -39,7 +39,7 @@ IN_PROC_BROWSER_TEST_F(InputImeApiTest, Basic) {
"_ext_ime_ilanclmaeigfpnmdlgelmhkpkegdioiptest"};
ash::input_method::InputMethodManager::Get()
->GetActiveIMEState()
- ->SetEnabledExtensionImes(&extension_ime_ids);
+ ->SetEnabledExtensionImes(extension_ime_ids);
ASSERT_TRUE(RunExtensionTest("input_ime")) << message_;
}
diff --git a/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc b/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
index d4c0e987adc..f2731f32ddf 100644
--- a/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc
@@ -341,11 +341,6 @@ LanguageSettingsPrivateEnableLanguageFunction::Run() {
std::string chrome_language = language_code;
language::ToChromeLanguageSynonym(&chrome_language);
- if (base::Contains(languages, chrome_language)) {
- LOG(ERROR) << "Language " << chrome_language << " already enabled";
- return RespondNow(NoArguments());
- }
-
translate_prefs->AddToLanguageList(language_code, /*force_blocked=*/false);
return RespondNow(NoArguments());
@@ -372,15 +367,7 @@ LanguageSettingsPrivateDisableLanguageFunction::Run() {
std::string chrome_language = language_code;
language::ToChromeLanguageSynonym(&chrome_language);
- if (!base::Contains(languages, chrome_language)) {
- LOG(ERROR) << "Language " << chrome_language << " not enabled";
- return RespondNow(NoArguments());
- }
-
translate_prefs->RemoveFromLanguageList(language_code);
- if (language_code == translate_prefs->GetRecentTargetLanguage()) {
- translate_prefs->ResetRecentTargetLanguage();
- }
return RespondNow(NoArguments());
}
diff --git a/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc b/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc
index bf355ff4813..a35e53d2a8e 100644
--- a/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc
@@ -31,6 +31,7 @@
#include "extensions/browser/api_test_utils.h"
#include "extensions/browser/event_router_factory.h"
#include "extensions/browser/extension_prefs.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_features.h"
@@ -463,14 +464,17 @@ class TestInputMethodManager : public input_method::MockInputMethodManager {
std::string layout("us");
InputMethodDescriptor extension_ime(
GetExtensionImeId(), "ExtensionIme", "", layout, {"vi"},
- false /* is_login_keyboard */, GURL(), GURL());
+ false /* is_login_keyboard */, GURL(), GURL(),
+ /*handwriting_language=*/absl::nullopt);
InputMethodDescriptor component_extension_ime(
GetComponentExtensionImeId(), "ComponentExtensionIme", "", layout,
- {"en-US", "en"}, false /* is_login_keyboard */, GURL(), GURL());
+ {"en-US", "en"}, false /* is_login_keyboard */, GURL(), GURL(),
+ /*handwriting_language=*/absl::nullopt);
InputMethodDescriptor arc_ime(GetArcImeId(), "ArcIme", "", layout,
{ash::extension_ime_util::kArcImeLanguage},
false /* is_login_keyboard */, GURL(),
- GURL());
+ GURL(),
+ /*handwriting_language=*/absl::nullopt);
input_methods_ = {extension_ime, component_extension_ime, arc_ime};
}
diff --git a/chromium/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc b/chromium/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
index f5ea98249a1..98847287ab3 100644
--- a/chromium/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
+++ b/chromium/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
@@ -9,7 +9,6 @@
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
-#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -63,65 +62,20 @@
#include "extensions/common/api/management.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_urls.h"
-#include "services/data_decoder/public/cpp/data_decoder.h"
#include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
#include "third_party/blink/public/mojom/window_features/window_features.mojom.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/components/arc/arc_util.h"
-#include "ash/components/arc/mojom/intent_helper.mojom.h"
-#include "ash/components/arc/session/arc_bridge_service.h"
-#include "ash/components/arc/session/arc_service_manager.h"
-#include "chrome/browser/ash/app_list/arc/arc_app_utils.h"
-#include "chrome/browser/ash/arc/arc_util.h"
#include "chrome/browser/ash/login/demo_mode/demo_session.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace {
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-const char kPlayIntentPrefix[] =
- "https://play.google.com/store/apps/details?id=";
-const char kChromeWebStoreReferrer[] = "&referrer=chrome_web_store";
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-
-using InstallAndroidAppCallback =
- extensions::ManagementAPIDelegate::InstallAndroidAppCallback;
-using AndroidAppInstallStatusCallback =
- extensions::ManagementAPIDelegate::AndroidAppInstallStatusCallback;
using InstallOrLaunchWebAppCallback =
extensions::ManagementAPIDelegate::InstallOrLaunchWebAppCallback;
using InstallOrLaunchWebAppResult =
extensions::ManagementAPIDelegate::InstallOrLaunchWebAppResult;
using InstallableCheckResult = web_app::InstallableCheckResult;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-void OnDidCheckForIntentToPlayStore(const std::string& intent,
- InstallAndroidAppCallback callback,
- bool installable) {
- if (!installable) {
- std::move(callback).Run(false);
- return;
- }
-
- auto* arc_service_manager = arc::ArcServiceManager::Get();
- if (!arc_service_manager) {
- std::move(callback).Run(false);
- return;
- }
-
- auto* instance = ARC_GET_INSTANCE_FOR_METHOD(
- arc_service_manager->arc_bridge_service()->intent_helper(), HandleUrl);
- if (!instance) {
- std::move(callback).Run(false);
- return;
- }
-
- instance->HandleUrl(intent, arc::kPlayStorePackage);
- std::move(callback).Run(true);
-}
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-
class ManagementSetEnabledFunctionInstallPromptDelegate
: public extensions::InstallPromptDelegate {
public:
@@ -266,7 +220,7 @@ class ChromeAppForLinkDelegate : public extensions::AppForLinkDelegate {
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
- auto web_app_info = std::make_unique<WebAppInstallInfo>();
+ auto web_app_info = std::make_unique<web_app::WebAppInstallInfo>();
web_app_info->title = base::UTF8ToUTF16(title);
web_app_info->start_url = launch_url;
web_app_info->display_mode = web_app::DisplayMode::kBrowser;
@@ -491,18 +445,6 @@ extensions::LaunchType ChromeManagementAPIDelegate::GetLaunchType(
return extensions::GetLaunchType(prefs, extension);
}
-void ChromeManagementAPIDelegate::
- GetPermissionWarningsByManifestFunctionDelegate(
- extensions::ManagementGetPermissionWarningsByManifestFunction* function,
- const std::string& manifest_str) const {
- data_decoder::DataDecoder::ParseJsonIsolated(
- manifest_str,
- base::BindOnce(
- &extensions::ManagementGetPermissionWarningsByManifestFunction::
- OnParse,
- function));
-}
-
std::unique_ptr<extensions::InstallPromptDelegate>
ChromeManagementAPIDelegate::SetEnabledFunctionDelegate(
content::WebContents* web_contents,
@@ -612,66 +554,6 @@ void ChromeManagementAPIDelegate::InstallOrLaunchReplacementWebApp(
std::move(callback), std::move(web_contents)));
}
-bool ChromeManagementAPIDelegate::CanContextInstallAndroidApps(
- content::BrowserContext* context) const {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- return arc::IsArcAllowedForProfile(Profile::FromBrowserContext(context));
-#else
- return false;
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-}
-
-void ChromeManagementAPIDelegate::CheckAndroidAppInstallStatus(
- const std::string& package_name,
- AndroidAppInstallStatusCallback callback) const {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- auto* arc_service_manager = arc::ArcServiceManager::Get();
- if (!arc_service_manager) {
- std::move(callback).Run(false);
- return;
- }
-
- auto* instance = ARC_GET_INSTANCE_FOR_METHOD(
- arc_service_manager->arc_bridge_service()->app(), IsInstallable);
- if (!instance) {
- std::move(callback).Run(false);
- return;
- }
-
- instance->IsInstallable(package_name, std::move(callback));
-#else
- std::move(callback).Run(false);
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-}
-
-void ChromeManagementAPIDelegate::InstallReplacementAndroidApp(
- const std::string& package_name,
- InstallAndroidAppCallback callback) const {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- std::string intent =
- base::StrCat({kPlayIntentPrefix, package_name, kChromeWebStoreReferrer});
-
- auto* arc_service_manager = arc::ArcServiceManager::Get();
- if (!arc_service_manager) {
- std::move(callback).Run(false);
- return;
- }
-
- auto* instance = ARC_GET_INSTANCE_FOR_METHOD(
- arc_service_manager->arc_bridge_service()->app(), IsInstallable);
- if (!instance) {
- std::move(callback).Run(false);
- return;
- }
-
- instance->IsInstallable(
- package_name, base::BindOnce(&OnDidCheckForIntentToPlayStore, intent,
- std::move(callback)));
-#else
- std::move(callback).Run(false);
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-}
-
void ChromeManagementAPIDelegate::EnableExtension(
content::BrowserContext* context,
const std::string& extension_id) const {
diff --git a/chromium/chrome/browser/extensions/api/management/chrome_management_api_delegate.h b/chromium/chrome/browser/extensions/api/management/chrome_management_api_delegate.h
index d6f29588886..91da4eb8e88 100644
--- a/chromium/chrome/browser/extensions/api/management/chrome_management_api_delegate.h
+++ b/chromium/chrome/browser/extensions/api/management/chrome_management_api_delegate.h
@@ -23,9 +23,6 @@ class ChromeManagementAPIDelegate : public extensions::ManagementAPIDelegate {
extensions::LaunchType GetLaunchType(
const extensions::ExtensionPrefs* prefs,
const extensions::Extension* extension) const override;
- void GetPermissionWarningsByManifestFunctionDelegate(
- extensions::ManagementGetPermissionWarningsByManifestFunction* function,
- const std::string& manifest_str) const override;
std::unique_ptr<extensions::InstallPromptDelegate> SetEnabledFunctionDelegate(
content::WebContents* web_contents,
content::BrowserContext* browser_context,
@@ -53,15 +50,6 @@ class ChromeManagementAPIDelegate : public extensions::ManagementAPIDelegate {
const GURL& web_app_url,
ManagementAPIDelegate::InstallOrLaunchWebAppCallback callback)
const override;
- bool CanContextInstallAndroidApps(
- content::BrowserContext* context) const override;
- void CheckAndroidAppInstallStatus(
- const std::string& package_name,
- ManagementAPIDelegate::AndroidAppInstallStatusCallback callback)
- const override;
- void InstallReplacementAndroidApp(
- const std::string& package_name,
- ManagementAPIDelegate::InstallAndroidAppCallback callback) const override;
void EnableExtension(content::BrowserContext* context,
const std::string& extension_id) const override;
void DisableExtension(
diff --git a/chromium/chrome/browser/extensions/api/management/management_api_browsertest.cc b/chromium/chrome/browser/extensions/api/management/management_api_browsertest.cc
index 7bbe060e189..e7877539aa5 100644
--- a/chromium/chrome/browser/extensions/api/management/management_api_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/management/management_api_browsertest.cc
@@ -32,7 +32,6 @@
#include "extensions/browser/extension_host_test_helper.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/notification_types.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/extension_id.h"
#include "extensions/test/extension_test_message_listener.h"
diff --git a/chromium/chrome/browser/extensions/api/management/management_api_unittest.cc b/chromium/chrome/browser/extensions/api/management/management_api_unittest.cc
index 57cf8c624f9..1ac7fbf7ae7 100644
--- a/chromium/chrome/browser/extensions/api/management/management_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/management/management_api_unittest.cc
@@ -865,9 +865,6 @@ class TestManagementAPIDelegate : public ManagementAPIDelegate {
const Extension* extension) const override {
return LaunchType::LAUNCH_TYPE_DEFAULT;
}
- void GetPermissionWarningsByManifestFunctionDelegate(
- ManagementGetPermissionWarningsByManifestFunction* function,
- const std::string& manifest_str) const override {}
std::unique_ptr<InstallPromptDelegate> SetEnabledFunctionDelegate(
content::WebContents* web_contents,
content::BrowserContext* browser_context,
@@ -905,6 +902,7 @@ class TestManagementAPIDelegate : public ManagementAPIDelegate {
void SetLaunchType(content::BrowserContext* context,
const std::string& extension_id,
LaunchType launch_type) const override {}
+
std::unique_ptr<AppForLinkDelegate> GenerateAppForLinkFunctionDelegate(
ManagementGenerateAppForLinkFunction* function,
content::BrowserContext* context,
@@ -920,16 +918,6 @@ class TestManagementAPIDelegate : public ManagementAPIDelegate {
content::BrowserContext* context,
const GURL& web_app_url,
InstallOrLaunchWebAppCallback callback) const override {}
- bool CanContextInstallAndroidApps(
- content::BrowserContext* context) const override {
- return true;
- }
- void CheckAndroidAppInstallStatus(
- const std::string& package_name,
- AndroidAppInstallStatusCallback callback) const override {}
- void InstallReplacementAndroidApp(
- const std::string& package_name,
- InstallAndroidAppCallback callback) const override {}
GURL GetIconURL(const Extension* extension,
int icon_size,
ExtensionIconSet::MatchType match,
diff --git a/chromium/chrome/browser/extensions/api/management/management_apitest.cc b/chromium/chrome/browser/extensions/api/management/management_apitest.cc
index f620dc0e9dc..5f6e396ca92 100644
--- a/chromium/chrome/browser/extensions/api/management/management_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/management/management_apitest.cc
@@ -7,7 +7,6 @@
#include "base/auto_reset.h"
#include "base/strings/stringprintf.h"
#include "base/test/gtest_tags.h"
-#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/extensions/extension_apitest.h"
@@ -27,7 +26,6 @@
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
-#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_constants.h"
#include "content/public/test/browser_test.h"
@@ -198,32 +196,6 @@ IN_PROC_BROWSER_TEST_P(ExtensionManagementApiTest, GenerateAppForLink) {
ASSERT_TRUE(RunExtensionTest("management/generate_app_for_link"));
}
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-class GenerateAppForLinkWithLacrosWebAppsApiTest
- : public ExtensionManagementApiTest {
- public:
- GenerateAppForLinkWithLacrosWebAppsApiTest() {
- features_.InitAndEnableFeature(features::kWebAppsCrosapi);
- }
-
- private:
- base::test::ScopedFeatureList features_;
-};
-
-INSTANTIATE_TEST_SUITE_P(PersistentBackground,
- GenerateAppForLinkWithLacrosWebAppsApiTest,
- ::testing::Values(ContextType::kPersistentBackground));
-INSTANTIATE_TEST_SUITE_P(ServiceWorker,
- GenerateAppForLinkWithLacrosWebAppsApiTest,
- ::testing::Values(ContextType::kServiceWorker));
-
-IN_PROC_BROWSER_TEST_P(GenerateAppForLinkWithLacrosWebAppsApiTest,
- GenerateAppForLink) {
- web_app::test::WaitUntilReady(web_app::WebAppProvider::GetForTest(profile()));
- ASSERT_TRUE(RunExtensionTest("management/generate_app_for_link_lacros"));
-}
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-
class InstallReplacementWebAppApiTest : public ExtensionManagementApiTest {
public:
InstallReplacementWebAppApiTest()
@@ -388,42 +360,6 @@ IN_PROC_BROWSER_TEST_P(InstallReplacementWebAppApiTest, InstallableWebApp) {
}
#endif
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-class InstallReplacementWebAppWithLacrosWebAppsApiTest
- : public InstallReplacementWebAppApiTest {
- public:
- InstallReplacementWebAppWithLacrosWebAppsApiTest() {
- features_.InitAndEnableFeature(features::kWebAppsCrosapi);
- }
-
- private:
- base::test::ScopedFeatureList features_;
-};
-
-INSTANTIATE_TEST_SUITE_P(PersistentBackground,
- InstallReplacementWebAppWithLacrosWebAppsApiTest,
- ::testing::Values(ContextType::kPersistentBackground));
-INSTANTIATE_TEST_SUITE_P(ServiceWorker,
- InstallReplacementWebAppWithLacrosWebAppsApiTest,
- ::testing::Values(ContextType::kServiceWorker));
-
-IN_PROC_BROWSER_TEST_P(InstallReplacementWebAppWithLacrosWebAppsApiTest,
- InstallableWebApp) {
- static constexpr char kGoodWebAppURL[] =
- "/management/install_replacement_web_app/acceptable_web_app/index.html";
- static constexpr char kBackground[] =
- R"(chrome.test.runWithUserGesture(function() {
- chrome.management.installReplacementWebApp(function() {
- chrome.test.assertLastError(
- 'Web apps can\'t be installed in the current user profile.');
- chrome.test.notifyPass();
- });
- });)";
-
- RunTest(kManifest, kGoodWebAppURL, kBackground, true /* from_webstore */);
-}
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
// TODO(crbug.com/1288199): Run these tests on Chrome OS with both Ash and
// Lacros processes active.
diff --git a/chromium/chrome/browser/extensions/api/mdns/mdns_api.cc b/chromium/chrome/browser/extensions/api/mdns/mdns_api.cc
index 85c074cf1a5..49f16877a8e 100644
--- a/chromium/chrome/browser/extensions/api/mdns/mdns_api.cc
+++ b/chromium/chrome/browser/extensions/api/mdns/mdns_api.cc
@@ -241,10 +241,10 @@ void MDnsAPI::WriteToConsole(const std::string& service_type,
extensions::ExtensionHost* host =
extensions::ProcessManager::Get(browser_context_)
->GetBackgroundHostForExtension(extension_id);
- content::RenderFrameHost* rfh =
+ content::RenderFrameHost* render_frame_host =
host ? host->host_contents()->GetPrimaryMainFrame() : nullptr;
- if (rfh) {
- rfh->AddMessageToConsole(level, logged_message);
+ if (render_frame_host) {
+ render_frame_host->AddMessageToConsole(level, logged_message);
}
}
}
diff --git a/chromium/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc b/chromium/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc
index d062790716a..b4f1776306d 100644
--- a/chromium/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc
+++ b/chromium/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc
@@ -119,10 +119,10 @@ std::unique_ptr<MessagePort> ChromeMessagingDelegate::CreateReceiverForTab(
bool include_child_frames =
receiver_frame_id == -1 && receiver_document_id.empty();
- content::RenderFrameHost* receiver_rfh = nullptr;
+ content::RenderFrameHost* receiver_render_frame_host = nullptr;
if (include_child_frames) {
// The target is the active outermost main frame of the WebContents.
- receiver_rfh = receiver_contents->GetPrimaryMainFrame();
+ receiver_render_frame_host = receiver_contents->GetPrimaryMainFrame();
} else if (!receiver_document_id.empty()) {
ExtensionApiFrameIdMap::DocumentId document_id =
ExtensionApiFrameIdMap::DocumentIdFromString(receiver_document_id);
@@ -131,28 +131,30 @@ std::unique_ptr<MessagePort> ChromeMessagingDelegate::CreateReceiverForTab(
if (!document_id)
return nullptr;
- receiver_rfh =
+ receiver_render_frame_host =
ExtensionApiFrameIdMap::Get()->GetRenderFrameHostByDocumentId(
document_id);
// If both |document_id| and |receiver_frame_id| are provided they
// should find the same RenderFrameHost, if not return early.
if (receiver_frame_id != -1 &&
- ExtensionApiFrameIdMap::GetRenderFrameHostById(
- receiver_contents, receiver_frame_id) != receiver_rfh) {
+ ExtensionApiFrameIdMap::GetRenderFrameHostById(receiver_contents,
+ receiver_frame_id) !=
+ receiver_render_frame_host) {
return nullptr;
}
} else {
DCHECK_GT(receiver_frame_id, -1);
- receiver_rfh = ExtensionApiFrameIdMap::GetRenderFrameHostById(
+ receiver_render_frame_host = ExtensionApiFrameIdMap::GetRenderFrameHostById(
receiver_contents, receiver_frame_id);
}
- if (!receiver_rfh)
+ if (!receiver_render_frame_host) {
return nullptr;
+ }
return std::make_unique<ExtensionMessagePort>(
- channel_delegate, receiver_port_id, extension_id, receiver_rfh,
- include_child_frames);
+ channel_delegate, receiver_port_id, extension_id,
+ receiver_render_frame_host, include_child_frames);
}
std::unique_ptr<MessagePort>
diff --git a/chromium/chrome/browser/extensions/api/messaging/messaging_apitest.cc b/chromium/chrome/browser/extensions/api/messaging/messaging_apitest.cc
index 139a2e1facf..0a04d003a92 100644
--- a/chromium/chrome/browser/extensions/api/messaging/messaging_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/messaging/messaging_apitest.cc
@@ -39,6 +39,7 @@
#include "components/infobars/content/content_infobar_manager.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/service_worker_context.h"
#include "content/public/browser/storage_partition.h"
@@ -335,6 +336,18 @@ class ExternallyConnectableMessagingTest : public MessagingApiTest {
return static_cast<Result>(result);
}
+ Result CanUseSendMessagePromise(const Extension* extension) {
+ content::RenderFrameHost* frame = browser()
+ ->tab_strip_model()
+ ->GetActiveWebContents()
+ ->GetPrimaryMainFrame();
+ std::string command =
+ content::JsReplace("assertions.canUseSendMessagePromise($1, $2)",
+ extension->id(), extension->is_platform_app());
+ int result = content::EvalJs(frame, command).ExtractInt();
+ return static_cast<Result>(result);
+ }
+
testing::AssertionResult AreAnyNonWebApisDefinedForMainFrame() {
return AreAnyNonWebApisDefinedForFrame(browser()
->tab_strip_model()
@@ -655,6 +668,18 @@ IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
EXPECT_FALSE(AreAnyNonWebApisDefinedForMainFrame());
}
+// Tests that an externally connectable web page context can use the promise
+// based form of sendMessage.
+IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
+ SendMessagePromiseSignatureExposed) {
+ // Install the web connectable extension.
+ scoped_refptr<const Extension> chromium_connectable =
+ LoadChromiumConnectableExtension();
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), chromium_org_url()));
+ EXPECT_EQ(OK, CanUseSendMessagePromise(chromium_connectable.get()));
+}
+
// See http://crbug.com/297866
IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
DISABLED_BackgroundPageClosesOnMessageReceipt) {
diff --git a/chromium/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc b/chromium/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
index c64f72ca057..2e1268e6972 100644
--- a/chromium/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
@@ -69,8 +69,7 @@ IN_PROC_BROWSER_TEST_F(NativeMessagingApiTestBase, UserLevelSendNativeMessage) {
#if BUILDFLAG(IS_WIN)
// On Windows, a new codepath is used to directly launch .EXE-based Native
// Hosts. This codepath allows launching of Native Hosts even when cmd.exe is
-// disabled, or if the path to the host contains a character that prevents
-// cmd.exe from successfully launching it (e.g. "&" in this test).
+// disabled or misconfigured.
class NativeMessagingLaunchExeTest : public NativeMessagingApiTestBase,
public testing::WithParamInterface<bool> {
public:
@@ -90,23 +89,33 @@ INSTANTIATE_TEST_SUITE_P(NativeMessagingLaunchExe,
NativeMessagingLaunchExeTest,
testing::Bool());
-IN_PROC_BROWSER_TEST_P(NativeMessagingLaunchExeTest, SendNativeMessageWinExe) {
- ASSERT_NO_FATAL_FAILURE(test_host_.RegisterTestExeHost(/*user_level=*/false));
+IN_PROC_BROWSER_TEST_P(NativeMessagingLaunchExeTest,
+ UserLevelSendNativeMessageWinExe) {
+ ASSERT_NO_FATAL_FAILURE(test_host_.RegisterTestExeHost(
+ "native_messaging_test_echo_host.exe", /*user_level=*/true));
- // The extension works properly only if the host launches successfully, which
- // requires the kLaunchWindowsNativeHostsDirectly feature to be enabled.
- ASSERT_EQ(IsDirectLaunchEnabled(),
- RunExtensionTest("native_messaging_send_native_message_exe"));
+ ASSERT(RunExtensionTest("native_messaging_send_native_message_exe"));
}
+// The Host's filename deliberately contains the character '&' which causes the
+// Host to fail to launch if cmd.exe is used as an intermediary between the
+// extension and the host executable, unless extra quotes are used.
+// crbug.com/335558
IN_PROC_BROWSER_TEST_P(NativeMessagingLaunchExeTest,
- UserLevelSendNativeMessageWinExe) {
- ASSERT_NO_FATAL_FAILURE(test_host_.RegisterTestExeHost(/*user_level=*/true));
+ SendNativeMessageWinExeAmpersand) {
+ ASSERT_NO_FATAL_FAILURE(test_host_.RegisterTestExeHost(
+ "native_messaging_test_echo_&_host.exe", /*user_level=*/false));
+
+ ASSERT(RunExtensionTest("native_messaging_send_native_message_exe"));
+}
+
+// Make sure that a filename with a space is supported.
+IN_PROC_BROWSER_TEST_P(NativeMessagingLaunchExeTest,
+ SendNativeMessageWinExeSpace) {
+ ASSERT_NO_FATAL_FAILURE(test_host_.RegisterTestExeHost(
+ "native_messaging_test_echo_ _host.exe", /*user_level=*/false));
- // The extension works properly only if the host launches successfully, which
- // requires the kLaunchWindowsNativeHostsDirectly feature to be enabled.
- ASSERT_EQ(IsDirectLaunchEnabled(),
- RunExtensionTest("native_messaging_send_native_message_exe"));
+ ASSERT(RunExtensionTest("native_messaging_send_native_message_exe"));
}
#endif
diff --git a/chromium/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc b/chromium/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc
index 719f64b9f2d..7d1bfe22b01 100644
--- a/chromium/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc
@@ -116,7 +116,7 @@ class ExtensionSupportsConnectionFromNativeAppTest : public ::testing::Test {
content::BrowserTaskEnvironment task_environment_;
bool has_listener_result_ = true;
TestingProfile profile_;
- std::string extension_id_;
+ ExtensionId extension_id_;
};
TEST_F(ExtensionSupportsConnectionFromNativeAppTest, Success) {
diff --git a/chromium/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc b/chromium/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc
index 3861f5e1c6e..6ff032ba83c 100644
--- a/chromium/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc
+++ b/chromium/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc
@@ -130,7 +130,9 @@ void ScopedTestNativeMessagingHost::RegisterTestHost(bool user_level) {
#if BUILDFLAG(IS_WIN)
// On Windows, a new codepath is used to directly launch .EXE-based Native
// Hosts.
-void ScopedTestNativeMessagingHost::RegisterTestExeHost(bool user_level) {
+void ScopedTestNativeMessagingHost::RegisterTestExeHost(
+ std::string_view filename,
+ bool user_level) {
base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -142,12 +144,7 @@ void ScopedTestNativeMessagingHost::RegisterTestExeHost(bool user_level) {
// Unlike in the |RegisterTestHost| case above, we must leave the Host
// .exe where it was built, because the Host will fail to run from the
// temp_dir_ if is_component_build is set for the build.
- //
- // The Host's filename deliberately contains the character '&' which causes
- // the Host to fail to launch if cmd.exe is used as an intermediary between
- // the extension and the host executable. crbug.com/335558
- base::FilePath host_path =
- binary_dir.AppendASCII("native_messaging_test_echo_&_host.exe");
+ base::FilePath host_path = binary_dir.AppendASCII(filename);
ASSERT_NO_FATAL_FAILURE(WriteTestNativeHostManifest(
temp_dir_.GetPath(), kHostExeName, host_path, user_level, false));
}
diff --git a/chromium/chrome/browser/extensions/api/messaging/native_messaging_test_util.h b/chromium/chrome/browser/extensions/api/messaging/native_messaging_test_util.h
index 525fc3e1b4f..007cf5d05a0 100644
--- a/chromium/chrome/browser/extensions/api/messaging/native_messaging_test_util.h
+++ b/chromium/chrome/browser/extensions/api/messaging/native_messaging_test_util.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_EXTENSIONS_API_MESSAGING_NATIVE_MESSAGING_TEST_UTIL_H_
#include <memory>
+#include <string_view>
#include "base/files/scoped_temp_dir.h"
#include "build/build_config.h"
@@ -47,9 +48,8 @@ class ScopedTestNativeMessagingHost {
void RegisterTestHost(bool user_level);
#if BUILDFLAG(IS_WIN)
- // Register the Windows-only |native_messaging_test_echo_host.exe| Native
- // Host.
- void RegisterTestExeHost(bool user_level);
+ // Register the Windows-only Native Host exe.
+ void RegisterTestExeHost(std::string_view filename, bool user_level);
#endif
const base::FilePath& temp_dir() { return temp_dir_.GetPath(); }
diff --git a/chromium/chrome/browser/extensions/api/messaging/native_process_launcher_win.cc b/chromium/chrome/browser/extensions/api/messaging/native_process_launcher_win.cc
index 20680fbf140..5de3521d4d3 100644
--- a/chromium/chrome/browser/extensions/api/messaging/native_process_launcher_win.cc
+++ b/chromium/chrome/browser/extensions/api/messaging/native_process_launcher_win.cc
@@ -145,7 +145,7 @@ base::Process LaunchNativeHostViaCmd(const std::wstring& command,
L"COMSPEC", base::WriteInto(&comspec, comspec_length), comspec_length);
std::wstring wrapped_command = base::StringPrintf(
- L"%ls /d /c %ls < %ls > %ls", comspec.c_str(), command.c_str(),
+ L"%ls /d /s /c \"%ls\" < %ls > %ls", comspec.c_str(), command.c_str(),
in_pipe_name.c_str(), out_pipe_name.c_str());
return base::LaunchProcess(wrapped_command, options);
diff --git a/chromium/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc b/chromium/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
index 42dba0f0ca1..cf27fcf9bbd 100644
--- a/chromium/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc
@@ -11,6 +11,7 @@
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind.h"
+#include "base/test/test_future.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "components/onc/onc_constants.h"
@@ -53,11 +54,8 @@
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
-#include "chromeos/crosapi/mojom/test_controller.mojom-test-utils.h"
#include "chromeos/crosapi/mojom/test_controller.mojom.h"
#include "chromeos/lacros/lacros_service.h"
-
-using crosapi::mojom::ShillClientTestInterfaceAsyncWaiter;
#endif
// This tests the Chrome OS implementation of the networkingPrivate API
@@ -510,11 +508,12 @@ class NetworkingPrivateChromeOSApiTestLacros
LOG(ERROR) << "Unsupported ash version.";
return false;
}
- crosapi::mojom::TestControllerAsyncWaiter test_controller_waiter{
- service->GetRemote<crosapi::mojom::TestController>().get()};
- test_controller_waiter.BindShillClientTestInterface(
- shill_test_.BindNewPipeAndPassReceiver());
+ base::test::TestFuture<void> future;
+ service->GetRemote<crosapi::mojom::TestController>()
+ ->BindShillClientTestInterface(shill_test_.BindNewPipeAndPassReceiver(),
+ future.GetCallback());
+ EXPECT_TRUE(future.Wait());
ConfigFakeNetwork();
@@ -533,74 +532,89 @@ class NetworkingPrivateChromeOSApiTestLacros
return "";
}
- crosapi::mojom::TestControllerAsyncWaiter test_controller_waiter{
- service->GetRemote<crosapi::mojom::TestController>().get()};
-
- std::string userhash;
- test_controller_waiter.GetSanitizedActiveUsername(&userhash);
- return userhash;
+ base::test::TestFuture<const std::string&> future;
+ service->GetRemote<crosapi::mojom::TestController>()
+ ->GetSanitizedActiveUsername(future.GetCallback());
+ return future.Take();
}
void AddDevice(const std::string& device_path,
const std::string& type,
const std::string& name) override {
- ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
- .AddDevice(device_path, type, name);
+ base::test::TestFuture<void> future;
+ shill_test_->AddDevice(device_path, type, name, future.GetCallback());
+ ASSERT_TRUE(future.Wait());
}
void SetDeviceProperty(const std::string& device_path,
const std::string& name,
const base::Value& value) override {
- ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
- .SetDeviceProperty(device_path, name, value.Clone(),
- /*notify_changed=*/true);
+ base::test::TestFuture<void> future;
+ shill_test_->SetDeviceProperty(device_path, name, value.Clone(),
+ /*notify_changed=*/true,
+ future.GetCallback());
+ ASSERT_TRUE(future.Wait());
}
void SetSimLocked(const std::string& device_path, bool enabled) override {
- ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
- .SetSimLocked(device_path, enabled);
+ base::test::TestFuture<void> future;
+ shill_test_->SetSimLocked(device_path, enabled, future.GetCallback());
+ ASSERT_TRUE(future.Wait());
}
void ClearDevices() override {
- ShillClientTestInterfaceAsyncWaiter(shill_test_.get()).ClearDevices();
+ base::test::TestFuture<void> future;
+ shill_test_->ClearDevices(future.GetCallback());
+ ASSERT_TRUE(future.Wait());
}
void AddService(const std::string& service_path,
const std::string& name,
const std::string& type,
const std::string& state) override {
- ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
- .AddService(service_path, service_path + "_guid", name, type, state,
- true /* add_to_visible */);
+ base::test::TestFuture<void> future;
+ shill_test_->AddService(service_path, service_path + "_guid", name, type,
+ state, true /* add_to_visible */,
+ future.GetCallback());
+ ASSERT_TRUE(future.Wait());
}
void ClearServices() override {
- ShillClientTestInterfaceAsyncWaiter(shill_test_.get()).ClearServices();
+ base::test::TestFuture<void> future;
+ shill_test_->ClearServices(future.GetCallback());
+ ASSERT_TRUE(future.Wait());
}
void SetServiceProperty(const std::string& service_path,
const std::string& property,
const base::Value& value) override {
- ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
- .SetServiceProperty(service_path, property, value.Clone());
+ base::test::TestFuture<void> future;
+ shill_test_->SetServiceProperty(service_path, property, value.Clone(),
+ future.GetCallback());
+ ASSERT_TRUE(future.Wait());
}
void AddIPConfig(const std::string& ip_config_path,
base::Value::Dict properties) override {
- ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
- .AddIPConfig(ip_config_path, base::Value(std::move(properties)));
+ base::test::TestFuture<void> future;
+ shill_test_->AddIPConfig(ip_config_path, base::Value(std::move(properties)),
+ future.GetCallback());
+ ASSERT_TRUE(future.Wait());
}
void AddProfile(const std::string& profile_path,
const std::string& userhash) override {
- ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
- .AddProfile(profile_path, userhash);
+ base::test::TestFuture<void> future;
+ shill_test_->AddProfile(profile_path, userhash, future.GetCallback());
+ ASSERT_TRUE(future.Wait());
}
void AddServiceToProfile(const std::string& profile_path,
const std::string& service_path) override {
- ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
- .AddServiceToProfile(profile_path, service_path);
+ base::test::TestFuture<void> future;
+ shill_test_->AddServiceToProfile(profile_path, service_path,
+ future.GetCallback());
+ ASSERT_TRUE(future.Wait());
}
std::string GetSharedProfilePath() override {
diff --git a/chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.cc b/chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.cc
index ab06550c58b..173bb0edf07 100644
--- a/chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.cc
+++ b/chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.cc
@@ -39,11 +39,11 @@ ExtensionNotificationDisplayHelperFactory::
ExtensionNotificationDisplayHelperFactory::
~ExtensionNotificationDisplayHelperFactory() = default;
-KeyedService*
-ExtensionNotificationDisplayHelperFactory::BuildServiceInstanceFor(
- content::BrowserContext* context) const {
+std::unique_ptr<KeyedService> ExtensionNotificationDisplayHelperFactory::
+ BuildServiceInstanceForBrowserContext(
+ content::BrowserContext* context) const {
Profile* profile = Profile::FromBrowserContext(context);
- return new ExtensionNotificationDisplayHelper(profile);
+ return std::make_unique<ExtensionNotificationDisplayHelper>(profile);
}
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.h b/chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.h
index 1f726c1262f..d31b3040d97 100644
--- a/chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.h
+++ b/chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.h
@@ -30,7 +30,7 @@ class ExtensionNotificationDisplayHelperFactory
protected:
// Overridden from BrowserContextKeyedServiceFactory.
- KeyedService* BuildServiceInstanceFor(
+ std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const override;
private:
diff --git a/chromium/chrome/browser/extensions/api/notifications/extension_notification_handler_unittest.cc b/chromium/chrome/browser/extensions/api/notifications/extension_notification_handler_unittest.cc
index ea75249bd7f..d9b0f852288 100644
--- a/chromium/chrome/browser/extensions/api/notifications/extension_notification_handler_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/notifications/extension_notification_handler_unittest.cc
@@ -48,7 +48,7 @@ class TestExtensionNotificationHandler : public ExtensionNotificationHandler {
}
private:
- std::string extension_id_;
+ ExtensionId extension_id_;
std::string event_name_;
size_t param_count_;
};
diff --git a/chromium/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc b/chromium/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc
index 682ba13ad4d..58be93e34f2 100644
--- a/chromium/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc
+++ b/chromium/chrome/browser/extensions/api/omnibox/omnibox_api_interactive_test.cc
@@ -26,6 +26,7 @@
#include "components/omnibox/browser/autocomplete_input.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "components/omnibox/browser/autocomplete_result.h"
+#include "components/omnibox/browser/omnibox_controller.h"
#include "components/omnibox/browser/omnibox_edit_model.h"
#include "components/omnibox/browser/omnibox_view.h"
#include "content/public/test/browser_test.h"
@@ -130,7 +131,7 @@ class OmniboxApiTest : public ExtensionApiTest,
Browser* browser) {
return GetLocationBar(browser)
->GetOmniboxView()
- ->model()
+ ->controller()
->autocomplete_controller();
}
};
diff --git a/chromium/chrome/browser/extensions/api/page_capture/page_capture_api.cc b/chromium/chrome/browser/extensions/api/page_capture/page_capture_api.cc
index 0dbcb52167b..d532c4a1aff 100644
--- a/chromium/chrome/browser/extensions/api/page_capture/page_capture_api.cc
+++ b/chromium/chrome/browser/extensions/api/page_capture/page_capture_api.cc
@@ -20,7 +20,6 @@
#include "content/public/browser/web_contents.h"
#include "content/public/common/mhtml_generation_params.h"
#include "extensions/browser/extension_util.h"
-#include "extensions/common/extension_messages.h"
#include "extensions/common/permissions/permissions_data.h"
using content::BrowserThread;
@@ -116,30 +115,7 @@ bool PageCaptureSaveAsMHTMLFunction::CanCaptureCurrentPage(std::string* error) {
return can_capture_page;
}
-bool PageCaptureSaveAsMHTMLFunction::OnMessageReceived(
- const IPC::Message& message) {
- if (message.type() != ExtensionHostMsg_ResponseAck::ID)
- return false;
-
- int message_request_id;
- base::PickleIterator iter(message);
- if (!iter.ReadInt(&message_request_id)) {
- NOTREACHED() << "malformed extension message";
- return true;
- }
-
- if (message_request_id != request_id())
- return false;
-
- // The extension process has processed the response and has created a
- // reference to the blob, it is safe for us to go away.
- Release(); // Balanced in Run()
-
- return true;
-}
-
-void PageCaptureSaveAsMHTMLFunction::OnServiceWorkerAck() {
- DCHECK(is_from_service_worker());
+void PageCaptureSaveAsMHTMLFunction::OnResponseAck() {
// The extension process has processed the response and has created a
// reference to the blob, it is safe for us to go away.
// This instance may be deleted after this call, so no code goes after
@@ -238,7 +214,7 @@ void PageCaptureSaveAsMHTMLFunction::ReturnSuccess(int file_size) {
base::Value::Dict response;
response.Set("mhtmlFilePath", mhtml_path_.AsUTF8Unsafe());
response.Set("mhtmlFileLength", file_size);
- response.Set("requestId", request_id());
+ response.Set("requestId", request_uuid().AsLowercaseString());
// Add a reference, extending the lifespan of this extension function until
// the response has been received by the renderer. This function generates a
@@ -248,8 +224,7 @@ void PageCaptureSaveAsMHTMLFunction::ReturnSuccess(int file_size) {
// renderer has it's reference, so we can release ours.
// TODO(crbug.com/1050887): Potential memory leak here.
AddRef(); // Balanced in either OnMessageReceived()
- if (is_from_service_worker())
- AddWorkerResponseTarget();
+ AddResponseTarget();
Respond(WithArguments(std::move(response)));
}
diff --git a/chromium/chrome/browser/extensions/api/page_capture/page_capture_api.h b/chromium/chrome/browser/extensions/api/page_capture/page_capture_api.h
index ac5d18d2b81..cf8ef0643d5 100644
--- a/chromium/chrome/browser/extensions/api/page_capture/page_capture_api.h
+++ b/chromium/chrome/browser/extensions/api/page_capture/page_capture_api.h
@@ -39,13 +39,11 @@ class PageCaptureSaveAsMHTMLFunction : public ExtensionFunction {
};
static void SetTestDelegate(TestDelegate* delegate);
- // ExtensionFunction:
- void OnServiceWorkerAck() override;
-
private:
+ // ExtensionFunction:
~PageCaptureSaveAsMHTMLFunction() override;
ResponseAction Run() override;
- bool OnMessageReceived(const IPC::Message& message) override;
+ void OnResponseAck() override;
// Returns whether or not the extension has permission to capture the current
// page. Sets |*error| to an error value on failure.
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc b/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc
index 3f0d9413528..29a779743fe 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc
@@ -172,7 +172,7 @@ api::passwords_private::PasswordCheckState ConvertPasswordCheckState(
std::string FormatElapsedTime(base::Time time) {
const base::TimeDelta elapsed_time = base::Time::Now() - time;
if (elapsed_time < base::Minutes(1))
- return l10n_util::GetStringUTF8(IDS_SETTINGS_PASSWORDS_JUST_NOW);
+ return l10n_util::GetStringUTF8(IDS_PASSWORD_MANAGER_UI_JUST_NOW);
return base::UTF16ToUTF8(TimeFormat::SimpleWithMonthAndYear(
TimeFormat::FORMAT_ELAPSED, TimeFormat::LENGTH_LONG, elapsed_time, true));
@@ -293,7 +293,7 @@ PasswordCheckDelegate::GetCredentialsWithReusedPassword() {
bool PasswordCheckDelegate::MuteInsecureCredential(
const api::passwords_private::PasswordUiEntry& credential) {
// Try to obtain the original CredentialUIEntry. Return false if fails.
- const CredentialUIEntry* entry = FindMatchingEntry(credential);
+ const CredentialUIEntry* entry = id_generator_->TryGetKey(credential.id);
if (!entry)
return false;
@@ -303,25 +303,13 @@ bool PasswordCheckDelegate::MuteInsecureCredential(
bool PasswordCheckDelegate::UnmuteInsecureCredential(
const api::passwords_private::PasswordUiEntry& credential) {
// Try to obtain the original CredentialUIEntry. Return false if fails.
- const CredentialUIEntry* entry = FindMatchingEntry(credential);
+ const CredentialUIEntry* entry = id_generator_->TryGetKey(credential.id);
if (!entry)
return false;
return insecure_credentials_manager_.UnmuteCredential(*entry);
}
-// Records that a change password flow was started for |credential|.
-void PasswordCheckDelegate::RecordChangePasswordFlowStarted(
- const api::passwords_private::PasswordUiEntry& credential) {
- // If the |credential| does not have a |change_password_url|, skip it.
- if (!credential.change_password_url)
- return;
-
- GetPasswordChangeSuccessTracker()->OnManualChangePasswordFlowStarted(
- GURL(*credential.change_password_url), credential.username,
- PasswordChangeSuccessTracker::EntryPoint::kLeakCheckInSettings);
-}
-
void PasswordCheckDelegate::StartPasswordCheck(
StartPasswordCheckCallback callback) {
// If the delegate isn't initialized yet, enqueue the callback and return
@@ -347,12 +335,9 @@ void PasswordCheckDelegate::StartPasswordAnalyses(
insecure_credentials_manager_.StartWeakCheck(base::BindOnce(
&PasswordCheckDelegate::RecordAndNotifyAboutCompletedWeakPasswordCheck,
weak_ptr_factory_.GetWeakPtr()));
- if (base::FeatureList::IsEnabled(
- password_manager::features::kPasswordManagerRedesign)) {
- insecure_credentials_manager_.StartReuseCheck(
- base::BindOnce(&PasswordCheckDelegate::NotifyPasswordCheckStatusChanged,
- weak_ptr_factory_.GetWeakPtr()));
- }
+ insecure_credentials_manager_.StartReuseCheck(
+ base::BindOnce(&PasswordCheckDelegate::NotifyPasswordCheckStatusChanged,
+ weak_ptr_factory_.GetWeakPtr()));
auto progress = base::MakeRefCounted<PasswordCheckProgress>();
for (const auto& password : saved_passwords_presenter_->GetSavedPasswords())
progress->IncrementCounts(password);
@@ -366,16 +351,6 @@ void PasswordCheckDelegate::StartPasswordAnalyses(
bulk_leak_check_service_adapter_.GetBulkLeakCheckState());
}
-void PasswordCheckDelegate::StopPasswordCheck() {
- if (!is_initialized_) {
- for (auto&& callback : std::exchange(start_check_callbacks_, {}))
- std::move(callback).Run(State::kIdle);
- return;
- }
-
- bulk_leak_check_service_adapter_.StopBulkLeakCheck();
-}
-
api::passwords_private::PasswordCheckStatus
PasswordCheckDelegate::GetPasswordCheckStatus() const {
api::passwords_private::PasswordCheckStatus result;
@@ -481,22 +456,6 @@ void PasswordCheckDelegate::OnCredentialDone(
}
}
-const CredentialUIEntry* PasswordCheckDelegate::FindMatchingEntry(
- const api::passwords_private::PasswordUiEntry& credential) const {
- const CredentialUIEntry* entry = id_generator_->TryGetKey(credential.id);
- if (!entry)
- return nullptr;
-
- if (credential.urls.signon_realm != entry->GetFirstSignonRealm() ||
- credential.username != base::UTF16ToUTF8(entry->username) ||
- (credential.password &&
- *credential.password != base::UTF16ToUTF8(entry->password))) {
- return nullptr;
- }
-
- return entry;
-}
-
void PasswordCheckDelegate::
RecordAndNotifyAboutCompletedCompromisedPasswordCheck() {
profile_->GetPrefs()->SetDouble(
@@ -534,10 +493,7 @@ api::passwords_private::PasswordUiEntry
PasswordCheckDelegate::ConstructInsecureCredentialUiEntry(
CredentialUIEntry entry) {
api::passwords_private::PasswordUiEntry api_credential;
- api_credential.is_android_credential =
- password_manager::IsValidAndroidFacetURI(entry.GetFirstSignonRealm());
api_credential.username = base::UTF16ToUTF8(entry.username);
- api_credential.urls = CreateUrlCollectionFromCredential(entry);
api_credential.stored_in = StoreSetFromCredential(entry);
api_credential.compromised_info = CreateCompromiseInfo(entry);
absl::optional<GURL> change_password_url = entry.GetChangePasswordURL();
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.h b/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.h
index 630d8861872..8c144fddc8d 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.h
+++ b/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.h
@@ -76,18 +76,12 @@ class PasswordCheckDelegate
bool UnmuteInsecureCredential(
const api::passwords_private::PasswordUiEntry& credential);
- // Records that a change password flow was started for `credential`.
- void RecordChangePasswordFlowStarted(
- const api::passwords_private::PasswordUiEntry& credential);
-
// Checks that all preconditions for running a password check are fulfilled
// and, once that is the case, launches the password check. Invokes `callback`
// once a check is running or the request was stopped via
// `StopPasswordCheck()`.
void StartPasswordCheck(
StartPasswordCheckCallback callback = base::DoNothing());
- // Stops checking for insecure passwords.
- void StopPasswordCheck();
// Returns the current status of the password check.
api::passwords_private::PasswordCheckStatus GetPasswordCheckStatus() const;
@@ -113,14 +107,6 @@ class PasswordCheckDelegate
void OnCredentialDone(const password_manager::LeakCheckCredential& credential,
password_manager::IsLeaked is_leaked) override;
- // Tries to find the matching CredentialUIEntry for |credential|. It
- // performs a look-up in |id_generator_| using |credential.id|. If a matching
- // value exists it also verifies that signon realm, username and when possible
- // password match. Returns a pointer to the matching CredentialUIEntry on
- // success or nullptr otherwise.
- const password_manager::CredentialUIEntry* FindMatchingEntry(
- const api::passwords_private::PasswordUiEntry& credential) const;
-
// Starts the analyses of whether credentials are compromised and/or weak.
// Assumes that `StartPasswordCheck()` was called prior.
void StartPasswordAnalyses(StartPasswordCheckCallback callback);
@@ -168,7 +154,7 @@ class PasswordCheckDelegate
// List of callbacks that were passed to `StartPasswordCheck()` prior to the
// delegate being initialized. These will be run when either initialization
- // finishes, or `StopPasswordCheck()` gets invoked before hand.
+ // finishes.
std::vector<StartPasswordCheckCallback> start_check_callbacks_;
// Remembers the progress of the ongoing check. Null if no check is currently
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc b/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc
index aa9f3a7fa25..2c1b03607c7 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc
@@ -33,7 +33,7 @@
#include "chrome/test/base/testing_profile.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/password_manager/content/browser/password_change_success_tracker_factory.h"
-#include "components/password_manager/core/browser/affiliation/mock_affiliation_service.h"
+#include "components/password_manager/core/browser/affiliation/fake_affiliation_service.h"
#include "components/password_manager/core/browser/bulk_leak_check_service.h"
#include "components/password_manager/core/browser/leak_detection/bulk_leak_check.h"
#include "components/password_manager/core/browser/leak_detection/leak_detection_delegate_interface.h"
@@ -89,9 +89,9 @@ constexpr char16_t kWeakPassword2[] = u"111111";
constexpr char kGoogleAccounts[] = "https://accounts.google.com";
using api::passwords_private::CompromisedInfo;
+using api::passwords_private::DomainInfo;
using api::passwords_private::PasswordCheckStatus;
using api::passwords_private::PasswordUiEntry;
-using api::passwords_private::UrlCollection;
using password_manager::BulkLeakCheckDelegateInterface;
using password_manager::BulkLeakCheckService;
using password_manager::InsecureType;
@@ -241,12 +241,6 @@ PasswordForm MakeSavedAndroidPassword(
return form;
}
-auto ExpectUrls(const std::string& formatted_origin,
- const std::string& detailed_origin) {
- return AllOf(Field(&UrlCollection::shown, formatted_origin),
- Field(&UrlCollection::link, detailed_origin));
-}
-
// Creates matcher for a given compromised info.
auto ExpectCompromisedInfo(
base::TimeDelta elapsed_time_since_compromise,
@@ -262,21 +256,15 @@ auto ExpectCompromisedInfo(
}
// Creates matcher for a given compromised credential
-auto ExpectCredential(const std::string& formatted_origin,
- const std::string& detailed_origin,
- const absl::optional<std::string>& change_password_url,
+auto ExpectCredential(const absl::optional<std::string>& change_password_url,
const std::u16string& username) {
return AllOf(
Field(&PasswordUiEntry::username, base::UTF16ToASCII(username)),
- Field(&PasswordUiEntry::urls,
- ExpectUrls(formatted_origin, detailed_origin)),
Field(&PasswordUiEntry::change_password_url, change_password_url));
}
// Creates matcher for a given compromised credential
auto ExpectCompromisedCredential(
- const std::string& formatted_origin,
- const std::string& detailed_origin,
const absl::optional<std::string>& change_password_url,
const std::u16string& username,
base::TimeDelta elapsed_time_since_compromise,
@@ -291,12 +279,10 @@ auto ExpectCompromisedCredential(
return AllOf(
Field(&PasswordUiEntry::username, base::UTF16ToASCII(username)),
change_password_url_field_matcher,
- Field(&PasswordUiEntry::urls,
- ExpectUrls(formatted_origin, detailed_origin)),
Field(&PasswordUiEntry::compromised_info,
Optional(ExpectCompromisedInfo(elapsed_time_since_compromise,
- elapsed_time_since_compromise_str,
- compromise_types))));
+ elapsed_time_since_compromise_str,
+ compromise_types))));
}
class PasswordCheckDelegateTest : public ::testing::Test {
@@ -349,7 +335,7 @@ class PasswordCheckDelegateTest : public ::testing::Test {
raw_ptr<syncer::TestSyncService> sync_service_ =
CreateAndUseSyncService(&profile_);
IdGenerator credential_id_generator_;
- password_manager::MockAffiliationService affiliation_service_;
+ password_manager::FakeAffiliationService affiliation_service_;
SavedPasswordsPresenter presenter_{&affiliation_service_, store_,
account_store_};
PasswordCheckDelegate delegate_{&profile_, &presenter_,
@@ -370,13 +356,10 @@ TEST_F(PasswordCheckDelegateTest, GetInsecureCredentialsFillsFieldsCorrectly) {
EXPECT_THAT(
delegate().GetInsecureCredentials(),
UnorderedElementsAre(
- ExpectCredential("example.com", "https://example.com/",
- "https://example.com/.well-known/change-password",
+ ExpectCredential("https://example.com/.well-known/change-password",
kUsername1),
- ExpectCredential(
- "Example App",
- "https://play.google.com/store/apps/details?id=com.example.app",
- "https://example.com/.well-known/change-password", kUsername2)));
+ ExpectCredential("https://example.com/.well-known/change-password",
+ kUsername2)));
}
// Verify that computation of weak credentials notifies observers.
@@ -404,7 +387,6 @@ TEST_F(PasswordCheckDelegateTest, WeakCheckWhenUserSignedOut) {
EXPECT_THAT(
delegate().GetInsecureCredentials(),
ElementsAre(ExpectCredential(
- "example.com", "https://example.com/",
"https://example.com/.well-known/change-password", kUsername1)));
EXPECT_EQ(api::passwords_private::PASSWORD_CHECK_STATE_SIGNED_OUT,
delegate().GetPasswordCheckStatus().state);
@@ -435,25 +417,25 @@ TEST_F(PasswordCheckDelegateTest, GetInsecureCredentialsHandlesTimes) {
EXPECT_THAT(
delegate().GetInsecureCredentials(),
ElementsAre(ExpectCompromisedCredential(
- "example.com", "https://example.com/",
"https://example.com/.well-known/change-password",
kUsername1, base::Seconds(59), "Just now",
- {api::passwords_private::COMPROMISE_TYPE_LEAKED}),
+ {api::passwords_private::COMPROMISE_TYPE_LEAKED,
+ api::passwords_private::COMPROMISE_TYPE_REUSED}),
ExpectCompromisedCredential(
- "example.com", "https://example.com/",
"https://example.com/.well-known/change-password",
kUsername2, base::Seconds(60), "1 minute ago",
- {api::passwords_private::COMPROMISE_TYPE_LEAKED}),
+ {api::passwords_private::COMPROMISE_TYPE_LEAKED,
+ api::passwords_private::COMPROMISE_TYPE_REUSED}),
ExpectCompromisedCredential(
- "example.org", "http://www.example.org/",
"http://www.example.org/.well-known/change-password",
kUsername1, base::Days(100), "3 months ago",
- {api::passwords_private::COMPROMISE_TYPE_LEAKED}),
+ {api::passwords_private::COMPROMISE_TYPE_LEAKED,
+ api::passwords_private::COMPROMISE_TYPE_REUSED}),
ExpectCompromisedCredential(
- "example.org", "http://www.example.org/",
"http://www.example.org/.well-known/change-password",
kUsername2, base::Days(800), "2 years ago",
- {api::passwords_private::COMPROMISE_TYPE_LEAKED})));
+ {api::passwords_private::COMPROMISE_TYPE_LEAKED,
+ api::passwords_private::COMPROMISE_TYPE_REUSED})));
}
// Verifies that both leaked and phished credentials are ordered correctly
@@ -485,27 +467,27 @@ TEST_F(PasswordCheckDelegateTest,
EXPECT_THAT(delegate().GetInsecureCredentials(),
UnorderedElementsAre(
ExpectCompromisedCredential(
- "example.com", "https://example.com/",
"https://example.com/.well-known/change-password",
kUsername1, base::Minutes(1), "1 minute ago",
{api::passwords_private::COMPROMISE_TYPE_LEAKED,
- api::passwords_private::COMPROMISE_TYPE_PHISHED}),
+ api::passwords_private::COMPROMISE_TYPE_PHISHED,
+ api::passwords_private::COMPROMISE_TYPE_REUSED}),
ExpectCompromisedCredential(
- "example.org", "http://www.example.org/",
"http://www.example.org/.well-known/change-password",
kUsername1, base::Minutes(3), "3 minutes ago",
- {api::passwords_private::COMPROMISE_TYPE_PHISHED}),
+ {api::passwords_private::COMPROMISE_TYPE_PHISHED,
+ api::passwords_private::COMPROMISE_TYPE_REUSED}),
ExpectCompromisedCredential(
- "example.org", "http://www.example.org/",
"http://www.example.org/.well-known/change-password",
kUsername2, base::Minutes(4), "4 minutes ago",
{api::passwords_private::COMPROMISE_TYPE_LEAKED,
- api::passwords_private::COMPROMISE_TYPE_PHISHED}),
+ api::passwords_private::COMPROMISE_TYPE_PHISHED,
+ api::passwords_private::COMPROMISE_TYPE_REUSED}),
ExpectCompromisedCredential(
- "example.com", "https://example.com/",
"https://example.com/.well-known/change-password",
kUsername2, base::Minutes(2), "2 minutes ago",
- {api::passwords_private::COMPROMISE_TYPE_LEAKED})));
+ {api::passwords_private::COMPROMISE_TYPE_LEAKED,
+ api::passwords_private::COMPROMISE_TYPE_REUSED})));
}
TEST_F(PasswordCheckDelegateTest, GetInsecureCredentialsInjectsAndroid) {
@@ -527,25 +509,22 @@ TEST_F(PasswordCheckDelegateTest, GetInsecureCredentialsInjectsAndroid) {
// Verify that the compromised credentials match what is stored in the
// password store.
- EXPECT_THAT(
- delegate().GetInsecureCredentials(),
- UnorderedElementsAre(
- ExpectCompromisedCredential(
- "Example App",
- "https://play.google.com/store/apps/details?id=com.example.app",
- "https://example.com/.well-known/change-password", kUsername2,
- base::Days(3), "3 days ago",
- {api::passwords_private::COMPROMISE_TYPE_PHISHED}),
- ExpectCompromisedCredential(
- "app.example.com",
- "https://play.google.com/store/apps/details?id=com.example.app",
- absl::nullopt, kUsername1, base::Days(4), "4 days ago",
- {api::passwords_private::COMPROMISE_TYPE_PHISHED}),
- ExpectCompromisedCredential(
- "example.com", "https://example.com/",
- "https://example.com/.well-known/change-password", kUsername1,
- base::Minutes(5), "5 minutes ago",
- {api::passwords_private::COMPROMISE_TYPE_LEAKED})));
+ EXPECT_THAT(delegate().GetInsecureCredentials(),
+ UnorderedElementsAre(
+ ExpectCompromisedCredential(
+ "https://example.com/.well-known/change-password",
+ kUsername2, base::Days(3), "3 days ago",
+ {api::passwords_private::COMPROMISE_TYPE_PHISHED,
+ api::passwords_private::COMPROMISE_TYPE_REUSED}),
+ ExpectCompromisedCredential(
+ absl::nullopt, kUsername1, base::Days(4), "4 days ago",
+ {api::passwords_private::COMPROMISE_TYPE_PHISHED,
+ api::passwords_private::COMPROMISE_TYPE_REUSED}),
+ ExpectCompromisedCredential(
+ "https://example.com/.well-known/change-password",
+ kUsername1, base::Minutes(5), "5 minutes ago",
+ {api::passwords_private::COMPROMISE_TYPE_LEAKED,
+ api::passwords_private::COMPROMISE_TYPE_REUSED})));
}
// Test that a change to compromised credential notifies observers.
@@ -681,68 +660,6 @@ TEST_F(PasswordCheckDelegateTest, UnmuteInsecureCredentialIdMismatch) {
EXPECT_FALSE(delegate().UnmuteInsecureCredential(credential));
}
-TEST_F(PasswordCheckDelegateTest, RecordChangePasswordFlowStarted) {
- // Create an insecure credential.
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
- RunUntilIdle();
-
- PasswordUiEntry credential =
- std::move(delegate().GetInsecureCredentials().at(0));
- ASSERT_EQ(base::UTF16ToASCII(kUsername1), credential.username);
-
- EXPECT_CALL(
- password_change_success_tracker(),
- OnManualChangePasswordFlowStarted(
- GURL(*credential.change_password_url), credential.username,
- PasswordChangeSuccessTracker::EntryPoint::kLeakCheckInSettings));
-
- delegate().RecordChangePasswordFlowStarted(credential);
-}
-
-TEST_F(PasswordCheckDelegateTest,
- RecordChangePasswordFlowStartedForAppWithWebRealm) {
- // Create an insecure credential.
- PasswordForm form = MakeSavedAndroidPassword(kExampleApp, kUsername2,
- "Example App", kExampleCom);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
- RunUntilIdle();
-
- PasswordUiEntry credential =
- std::move(delegate().GetInsecureCredentials().at(0));
- ASSERT_EQ(base::UTF16ToASCII(kUsername2), credential.username);
-
- EXPECT_CALL(
- password_change_success_tracker(),
- OnManualChangePasswordFlowStarted(
- GURL(*credential.change_password_url), credential.username,
- PasswordChangeSuccessTracker::EntryPoint::kLeakCheckInSettings));
-
- delegate().RecordChangePasswordFlowStarted(credential);
-}
-
-TEST_F(PasswordCheckDelegateTest,
- RecordChangePasswordFlowStartedForAppWithoutWebRealm) {
- // Create an insecure credential.
- PasswordForm form = MakeSavedAndroidPassword(kExampleApp, kUsername1, "", "");
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
- RunUntilIdle();
-
- PasswordUiEntry credential =
- std::move(delegate().GetInsecureCredentials().at(0));
- ASSERT_EQ(base::UTF16ToASCII(kUsername1), credential.username);
-
- // Since no password change link exists, we expect no call to the tracker.
- EXPECT_CALL(password_change_success_tracker(),
- OnManualChangePasswordFlowStarted)
- .Times(0);
-
- delegate().RecordChangePasswordFlowStarted(credential);
-}
-
// Tests that we don't create an entry in the database if there is no matching
// saved password.
TEST_F(PasswordCheckDelegateTest, OnLeakFoundDoesNotCreateCredential) {
@@ -916,21 +833,6 @@ TEST_F(PasswordCheckDelegateTest, GetPasswordCheckStatusCount) {
EXPECT_EQ(*status.total_number_of_passwords, 2);
}
-// Verifies that the case where the check is canceled is reported correctly.
-TEST_F(PasswordCheckDelegateTest, GetPasswordCheckStatusCanceled) {
- identity_test_env().MakeAccountAvailable(kTestEmail);
- store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1));
- RunUntilIdle();
-
- delegate().StartPasswordCheck();
- EXPECT_EQ(api::passwords_private::PASSWORD_CHECK_STATE_RUNNING,
- delegate().GetPasswordCheckStatus().state);
-
- delegate().StopPasswordCheck();
- EXPECT_EQ(api::passwords_private::PASSWORD_CHECK_STATE_CANCELED,
- delegate().GetPasswordCheckStatus().state);
-}
-
// Verifies that the case where the user is offline is reported correctly.
TEST_F(PasswordCheckDelegateTest, GetPasswordCheckStatusOffline) {
identity_test_env().MakeAccountAvailable(kTestEmail);
@@ -1085,24 +987,6 @@ TEST_F(PasswordCheckDelegateTest, OnCredentialDoneUpdatesProgress) {
EXPECT_EQ(0, *status->remaining_in_queue);
}
-// Tests that StopPasswordCheck() invokes pending callbacks before
-// initialization finishes.
-TEST_F(PasswordCheckDelegateTest,
- StopPasswordCheckRespondsCancelsBeforeInitialization) {
- MockStartPasswordCheckCallback callback1;
- MockStartPasswordCheckCallback callback2;
- delegate().StartPasswordCheck(callback1.Get());
- delegate().StartPasswordCheck(callback2.Get());
-
- EXPECT_CALL(callback1, Run(BulkLeakCheckService::State::kIdle));
- EXPECT_CALL(callback2, Run(BulkLeakCheckService::State::kIdle));
- delegate().StopPasswordCheck();
-
- Mock::VerifyAndClearExpectations(&callback1);
- Mock::VerifyAndClearExpectations(&callback2);
- RunUntilIdle();
-}
-
// Tests that pending callbacks get invoked once initialization finishes.
TEST_F(PasswordCheckDelegateTest,
StartPasswordCheckRunsCallbacksAfterInitialization) {
@@ -1117,7 +1001,7 @@ TEST_F(PasswordCheckDelegateTest,
// Use a local delegate instead of |delegate()| so that the Password Store can
// be set-up prior to constructing the object.
- password_manager::MockAffiliationService affiliation_service;
+ password_manager::FakeAffiliationService affiliation_service;
SavedPasswordsPresenter new_presenter(&affiliation_service, &store(),
/*account_store=*/nullptr);
PasswordCheckDelegate delegate = CreateDelegate(&new_presenter);
@@ -1162,10 +1046,6 @@ TEST_F(PasswordCheckDelegateTest, WellKnownChangePasswordUrl_androidrealm) {
// credentials.
TEST_F(PasswordCheckDelegateTest,
GetCredentialsWithReusedPasswordFillsFieldsCorrectly) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- password_manager::features::kPasswordManagerRedesign);
-
store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1));
store().AddLogin(MakeSavedPassword(kExampleCom, kUsername2, kWeakPassword2));
store().AddLogin(MakeSavedAndroidPassword(
@@ -1186,34 +1066,23 @@ TEST_F(PasswordCheckDelegateTest,
Field(&api::passwords_private::PasswordUiEntryList::entries,
UnorderedElementsAre(
ExpectCredential(
- "example.com", "https://example.com/",
"https://example.com/.well-known/change-password",
kUsername2),
ExpectCredential(
- "Example App",
- "https://play.google.com/store/apps/"
- "details?id=com.example.app",
"https://example.com/.well-known/change-password",
kUsername1))),
Field(&api::passwords_private::PasswordUiEntryList::entries,
UnorderedElementsAre(
ExpectCredential(
- "example.com", "https://example.com/",
"https://example.com/.well-known/change-password",
kUsername1),
ExpectCredential(
- "Example App",
- "https://play.google.com/store/apps/"
- "details?id=com.example.app",
"https://example.com/.well-known/change-password",
kUsername2)))));
}
TEST_F(PasswordCheckDelegateTest,
GetCredentialsWithReusedPasswordAvoidsSingleReuse) {
- base::test::ScopedFeatureList scoped_feature_list(
- password_manager::features::kPasswordManagerRedesign);
-
store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1));
store().AddLogin(MakeSavedPassword(kExampleApp, kUsername2, kWeakPassword1));
RunUntilIdle();
@@ -1230,3 +1099,4 @@ TEST_F(PasswordCheckDelegateTest,
}
} // namespace extensions
+ \ No newline at end of file
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc
index 181e9e81ac8..7ee1928a92f 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc
@@ -49,29 +49,6 @@ PasswordsPrivateRecordPasswordsPageAccessInSettingsFunction::Run() {
return RespondNow(NoArguments());
}
-// PasswordsPrivateChangeSavedPasswordFunction
-ResponseAction PasswordsPrivateChangeSavedPasswordFunction::Run() {
- if (!GetDelegate(browser_context())) {
- return RespondNow(Error(kNoDelegateError));
- }
-
- auto parameters =
- api::passwords_private::ChangeSavedPassword::Params::Create(args());
- EXTENSION_FUNCTION_VALIDATE(parameters);
-
- auto new_id = GetDelegate(browser_context())
- ->ChangeSavedPassword(parameters->id, parameters->params);
- if (new_id.has_value()) {
- return RespondNow(ArgumentList(
- api::passwords_private::ChangeSavedPassword::Results::Create(
- new_id.value())));
- }
- return RespondNow(Error(
- "Could not change the password. Either the password is empty, the user "
- "is not authenticated or no matching password could be found for the "
- "id."));
-}
-
// PasswordsPrivateChangeCredentialFunction
ResponseAction PasswordsPrivateChangeCredentialFunction::Run() {
if (!GetDelegate(browser_context())) {
@@ -208,19 +185,11 @@ ResponseAction PasswordsPrivateGetSavedPasswordListFunction::Run() {
return RespondNow(Error(kNoDelegateError));
}
- // GetList() can immediately call GotList() (which would Respond() before
- // RespondLater()). So we post a task to preserve order.
- base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
- FROM_HERE,
- base::BindOnce(&PasswordsPrivateGetSavedPasswordListFunction::GetList,
- this));
- return RespondLater();
-}
-
-void PasswordsPrivateGetSavedPasswordListFunction::GetList() {
GetDelegate(browser_context())
->GetSavedPasswordsList(base::BindOnce(
&PasswordsPrivateGetSavedPasswordListFunction::GotList, this));
+
+ return did_respond() ? AlreadyResponded() : RespondLater();
}
void PasswordsPrivateGetSavedPasswordListFunction::GotList(
@@ -246,19 +215,11 @@ ResponseAction PasswordsPrivateGetPasswordExceptionListFunction::Run() {
return RespondNow(Error(kNoDelegateError));
}
- // GetList() can immediately call GotList() (which would Respond() before
- // RespondLater()). So we post a task to preserve order.
- base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
- FROM_HERE,
- base::BindOnce(&PasswordsPrivateGetPasswordExceptionListFunction::GetList,
- this));
- return RespondLater();
-}
-
-void PasswordsPrivateGetPasswordExceptionListFunction::GetList() {
GetDelegate(browser_context())
->GetPasswordExceptionsList(base::BindOnce(
&PasswordsPrivateGetPasswordExceptionListFunction::GotList, this));
+
+ return did_respond() ? AlreadyResponded() : RespondLater();
}
void PasswordsPrivateGetPasswordExceptionListFunction::GotList(
@@ -282,6 +243,45 @@ ResponseAction PasswordsPrivateMovePasswordsToAccountFunction::Run() {
return RespondNow(NoArguments());
}
+// PasswordsPrivateFetchFamilyMembersFunction
+ResponseAction PasswordsPrivateFetchFamilyMembersFunction::Run() {
+ if (!GetDelegate(browser_context())) {
+ return RespondNow(Error(kNoDelegateError));
+ }
+
+ GetDelegate(browser_context())
+ ->FetchFamilyMembers(base::BindOnce(
+ &PasswordsPrivateFetchFamilyMembersFunction::FamilyFetchCompleted,
+ this));
+
+ // `FamilyFetchCompleted()` might respond before we reach this point.
+ return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+// PasswordsPrivateSharePasswordFunction
+ResponseAction PasswordsPrivateSharePasswordFunction::Run() {
+ if (!GetDelegate(browser_context())) {
+ return RespondNow(Error(kNoDelegateError));
+ }
+
+ // TODO(crbug/1445526): Respond with an error if arguments are not valid
+ // (password doesn't exist, auth validity expired, recipient doesn't have
+ // public key or user_id).
+
+ auto parameters =
+ api::passwords_private::SharePassword::Params::Create(args());
+ EXTENSION_FUNCTION_VALIDATE(parameters);
+ GetDelegate(browser_context())
+ ->SharePassword(parameters->id, parameters->recipients);
+ return RespondNow(NoArguments());
+}
+
+void PasswordsPrivateFetchFamilyMembersFunction::FamilyFetchCompleted(
+ const api::passwords_private::FamilyFetchResults& result) {
+ Respond(ArgumentList(
+ api::passwords_private::FetchFamilyMembers::Results::Create(result)));
+}
+
// PasswordsPrivateImportPasswordsFunction
ResponseAction PasswordsPrivateImportPasswordsFunction::Run() {
if (!GetDelegate(browser_context())) {
@@ -371,16 +371,6 @@ void PasswordsPrivateExportPasswordsFunction::ExportRequestCompleted(
Respond(Error(error));
}
-// PasswordsPrivateCancelExportPasswordsFunction
-ResponseAction PasswordsPrivateCancelExportPasswordsFunction::Run() {
- if (!GetDelegate(browser_context())) {
- return RespondNow(Error(kNoDelegateError));
- }
-
- GetDelegate(browser_context())->CancelExportPasswords();
- return RespondNow(NoArguments());
-}
-
// PasswordsPrivateRequestExportProgressStatusFunction
ResponseAction PasswordsPrivateRequestExportProgressStatusFunction::Run() {
if (!GetDelegate(browser_context())) {
@@ -491,25 +481,6 @@ ResponseAction PasswordsPrivateUnmuteInsecureCredentialFunction::Run() {
return RespondNow(NoArguments());
}
-// PasswordsPrivateRecordChangePasswordFlowStartedFunction:
-PasswordsPrivateRecordChangePasswordFlowStartedFunction::
- ~PasswordsPrivateRecordChangePasswordFlowStartedFunction() = default;
-
-ResponseAction PasswordsPrivateRecordChangePasswordFlowStartedFunction::Run() {
- if (!GetDelegate(browser_context())) {
- return RespondNow(Error(kNoDelegateError));
- }
-
- auto parameters =
- api::passwords_private::RecordChangePasswordFlowStarted::Params::Create(
- args());
- EXTENSION_FUNCTION_VALIDATE(parameters);
-
- GetDelegate(browser_context())
- ->RecordChangePasswordFlowStarted(parameters->credential);
- return RespondNow(NoArguments());
-}
-
// PasswordsPrivateStartPasswordCheckFunction:
PasswordsPrivateStartPasswordCheckFunction::
~PasswordsPrivateStartPasswordCheckFunction() = default;
@@ -535,19 +506,6 @@ void PasswordsPrivateStartPasswordCheckFunction::OnStarted(
: Error("Starting password check failed."));
}
-// PasswordsPrivateStopPasswordCheckFunction:
-PasswordsPrivateStopPasswordCheckFunction::
- ~PasswordsPrivateStopPasswordCheckFunction() = default;
-
-ResponseAction PasswordsPrivateStopPasswordCheckFunction::Run() {
- if (!GetDelegate(browser_context())) {
- return RespondNow(Error(kNoDelegateError));
- }
-
- GetDelegate(browser_context())->StopPasswordCheck();
- return RespondNow(NoArguments());
-}
-
// PasswordsPrivateGetPasswordCheckStatusFunction:
PasswordsPrivateGetPasswordCheckStatusFunction::
~PasswordsPrivateGetPasswordCheckStatusFunction() = default;
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.h b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.h
index 97f445d33f8..66ff906714b 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.h
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.h
@@ -29,18 +29,6 @@ class PasswordsPrivateRecordPasswordsPageAccessInSettingsFunction
ResponseAction Run() override;
};
-class PasswordsPrivateChangeSavedPasswordFunction : public ExtensionFunction {
- public:
- DECLARE_EXTENSION_FUNCTION("passwordsPrivate.changeSavedPassword",
- PASSWORDSPRIVATE_CHANGESAVEDPASSWORD)
-
- protected:
- ~PasswordsPrivateChangeSavedPasswordFunction() override = default;
-
- // ExtensionFunction overrides.
- ResponseAction Run() override;
-};
-
class PasswordsPrivateChangeCredentialFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("passwordsPrivate.changeCredential",
@@ -136,7 +124,6 @@ class PasswordsPrivateGetSavedPasswordListFunction : public ExtensionFunction {
ResponseAction Run() override;
private:
- void GetList();
void GotList(const PasswordsPrivateDelegate::UiEntries& entries);
};
@@ -165,7 +152,6 @@ class PasswordsPrivateGetPasswordExceptionListFunction
ResponseAction Run() override;
private:
- void GetList();
void GotList(const PasswordsPrivateDelegate::ExceptionEntries& entries);
};
@@ -182,6 +168,34 @@ class PasswordsPrivateMovePasswordsToAccountFunction
ResponseAction Run() override;
};
+class PasswordsPrivateFetchFamilyMembersFunction : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("passwordsPrivate.fetchFamilyMembers",
+ PASSWORDSPRIVATE_FETCHFAMILYMEMBERS)
+
+ protected:
+ ~PasswordsPrivateFetchFamilyMembersFunction() override = default;
+
+ // ExtensionFunction overrides.
+ ResponseAction Run() override;
+
+ private:
+ void FamilyFetchCompleted(
+ const api::passwords_private::FamilyFetchResults& results);
+};
+
+class PasswordsPrivateSharePasswordFunction : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("passwordsPrivate.sharePassword",
+ PASSWORDSPRIVATE_SHAREPASSWORD)
+
+ protected:
+ ~PasswordsPrivateSharePasswordFunction() override = default;
+
+ // ExtensionFunction overrides.
+ ResponseAction Run() override;
+};
+
class PasswordsPrivateImportPasswordsFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("passwordsPrivate.importPasswords",
@@ -240,18 +254,6 @@ class PasswordsPrivateExportPasswordsFunction : public ExtensionFunction {
void ExportRequestCompleted(const std::string& error);
};
-class PasswordsPrivateCancelExportPasswordsFunction : public ExtensionFunction {
- public:
- DECLARE_EXTENSION_FUNCTION("passwordsPrivate.cancelExportPasswords",
- PASSWORDSPRIVATE_CANCELEXPORTPASSWORDS)
-
- protected:
- ~PasswordsPrivateCancelExportPasswordsFunction() override = default;
-
- // ExtensionFunction overrides.
- ResponseAction Run() override;
-};
-
class PasswordsPrivateRequestExportProgressStatusFunction
: public ExtensionFunction {
public:
@@ -344,19 +346,6 @@ class PasswordsPrivateUnmuteInsecureCredentialFunction
ResponseAction Run() override;
};
-class PasswordsPrivateRecordChangePasswordFlowStartedFunction
- : public ExtensionFunction {
- public:
- DECLARE_EXTENSION_FUNCTION("passwordsPrivate.recordChangePasswordFlowStarted",
- PASSWORDSPRIVATE_RECORDCHANGEPASSWORDFLOWSTARTED)
-
- protected:
- ~PasswordsPrivateRecordChangePasswordFlowStartedFunction() override;
-
- // ExtensionFunction overrides.
- ResponseAction Run() override;
-};
-
class PasswordsPrivateStartPasswordCheckFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("passwordsPrivate.startPasswordCheck",
@@ -372,18 +361,6 @@ class PasswordsPrivateStartPasswordCheckFunction : public ExtensionFunction {
void OnStarted(password_manager::BulkLeakCheckService::State state);
};
-class PasswordsPrivateStopPasswordCheckFunction : public ExtensionFunction {
- public:
- DECLARE_EXTENSION_FUNCTION("passwordsPrivate.stopPasswordCheck",
- PASSWORDSPRIVATE_STOPPASSWORDCHECK)
-
- protected:
- ~PasswordsPrivateStopPasswordCheckFunction() override;
-
- // ExtensionFunction overrides.
- ResponseAction Run() override;
-};
-
class PasswordsPrivateGetPasswordCheckStatusFunction
: public ExtensionFunction {
public:
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc
index 2eb6374b579..adfe50b7d8a 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc
@@ -41,12 +41,7 @@ namespace {
class PasswordsPrivateApiTest : public ExtensionApiTest {
public:
- PasswordsPrivateApiTest() {
- scoped_feature_list_.InitWithFeatures(
- {password_manager::features::kPasswordManagerRedesign,
- password_manager::features::kPasswordsGrouping},
- {});
- }
+ PasswordsPrivateApiTest() = default;
PasswordsPrivateApiTest(const PasswordsPrivateApiTest&) = delete;
PasswordsPrivateApiTest& operator=(const PasswordsPrivateApiTest&) = delete;
@@ -80,6 +75,14 @@ class PasswordsPrivateApiTest : public ExtensionApiTest {
return test_delegate_->ImportPasswordsTriggered();
}
+ bool fetch_family_members_was_triggered() {
+ return test_delegate_->FetchFamilyMembersTriggered();
+ }
+
+ bool share_password_was_triggered() {
+ return test_delegate_->SharePasswordTriggered();
+ }
+
bool continue_import_was_triggered() {
return test_delegate_->ContinueImportTriggered();
}
@@ -92,18 +95,10 @@ class PasswordsPrivateApiTest : public ExtensionApiTest {
return test_delegate_->ExportPasswordsTriggered();
}
- bool cancelExportPasswordsWasTriggered() {
- return test_delegate_->CancelExportPasswordsTriggered();
- }
-
bool start_password_check_triggered() {
return test_delegate_->StartPasswordCheckTriggered();
}
- bool stop_password_check_triggered() {
- return test_delegate_->StopPasswordCheckTriggered();
- }
-
void set_start_password_check_state(
password_manager::BulkLeakCheckService::State state) {
test_delegate_->SetStartPasswordCheckState(state);
@@ -127,10 +122,6 @@ class PasswordsPrivateApiTest : public ExtensionApiTest {
test_delegate_->SetIsAccountStoreDefault(is_default);
}
- const std::string& last_change_flow_url() {
- return test_delegate_->last_change_flow_url();
- }
-
const std::vector<int>& last_moved_passwords() const {
return test_delegate_->last_moved_passwords();
}
@@ -148,7 +139,6 @@ class PasswordsPrivateApiTest : public ExtensionApiTest {
}
private:
- base::test::ScopedFeatureList scoped_feature_list_;
scoped_refptr<TestPasswordsPrivateDelegate> test_delegate_;
};
@@ -187,28 +177,6 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, AddPasswordWhenOperationFails) {
EXPECT_TRUE(RunPasswordsSubtest("addPasswordWhenOperationFails")) << message_;
}
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, ChangeSavedPasswordSucceeds) {
- EXPECT_TRUE(RunPasswordsSubtest("changeSavedPasswordSucceeds")) << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- ChangeSavedPasswordWithIncorrectIdFails) {
- EXPECT_TRUE(RunPasswordsSubtest("changeSavedPasswordWithIncorrectIdFails"))
- << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- ChangeSavedPasswordWithEmptyPasswordFails) {
- EXPECT_TRUE(RunPasswordsSubtest("changeSavedPasswordWithEmptyPasswordFails"))
- << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- ChangeSavedPasswordWithNoteSucceeds) {
- EXPECT_TRUE(RunPasswordsSubtest("ChangeSavedPasswordWithNoteSucceeds"))
- << message_;
-}
-
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
ChangeCredentialChangePassword) {
EXPECT_TRUE(RunPasswordsSubtest("changeCredentialChangePassword"))
@@ -267,6 +235,18 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetPasswordExceptionList) {
EXPECT_TRUE(RunPasswordsSubtest("getPasswordExceptionList")) << message_;
}
+IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, FetchFamilyMembers) {
+ EXPECT_FALSE(fetch_family_members_was_triggered());
+ EXPECT_TRUE(RunPasswordsSubtest("fetchFamilyMembers")) << message_;
+ EXPECT_TRUE(fetch_family_members_was_triggered());
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, SharePassword) {
+ EXPECT_FALSE(share_password_was_triggered());
+ EXPECT_TRUE(RunPasswordsSubtest("sharePassword")) << message_;
+ EXPECT_TRUE(share_password_was_triggered());
+}
+
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, ImportPasswords) {
EXPECT_FALSE(importPasswordsWasTriggered());
EXPECT_TRUE(RunPasswordsSubtest("importPasswords")) << message_;
@@ -291,12 +271,6 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, ExportPasswords) {
EXPECT_TRUE(exportPasswordsWasTriggered());
}
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, CancelExportPasswords) {
- EXPECT_FALSE(cancelExportPasswordsWasTriggered());
- EXPECT_TRUE(RunPasswordsSubtest("cancelExportPasswords")) << message_;
- EXPECT_TRUE(cancelExportPasswordsWasTriggered());
-}
-
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, RequestExportProgressStatus) {
EXPECT_TRUE(RunPasswordsSubtest("requestExportProgressStatus")) << message_;
}
@@ -339,21 +313,6 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, UnmuteInsecureCredentialFails) {
EXPECT_TRUE(RunPasswordsSubtest("unmuteInsecureCredentialFails")) << message_;
}
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- RecordChangePasswordFlowStarted) {
- EXPECT_TRUE(RunPasswordsSubtest("recordChangePasswordFlowStarted"))
- << message_;
- EXPECT_EQ(last_change_flow_url(),
- "https://example.com/.well-known/change-password");
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- RecordChangePasswordFlowStartedAppNoUrl) {
- EXPECT_TRUE(RunPasswordsSubtest("recordChangePasswordFlowStartedAppNoUrl"))
- << message_;
- EXPECT_EQ(last_change_flow_url(), "");
-}
-
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, StartPasswordCheck) {
set_start_password_check_state(
password_manager::BulkLeakCheckService::State::kRunning);
@@ -370,12 +329,6 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, StartPasswordCheckFailed) {
EXPECT_TRUE(start_password_check_triggered());
}
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, StopPasswordCheck) {
- EXPECT_FALSE(stop_password_check_triggered());
- EXPECT_TRUE(RunPasswordsSubtest("stopPasswordCheck")) << message_;
- EXPECT_TRUE(stop_password_check_triggered());
-}
-
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetPasswordCheckStatus) {
EXPECT_TRUE(RunPasswordsSubtest("getPasswordCheckStatus")) << message_;
}
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h
index 99c902c270c..5eced39ce00 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h
@@ -38,6 +38,11 @@ class PasswordsPrivateDelegate
using ImportResultsCallback =
base::OnceCallback<void(const api::passwords_private::ImportResults&)>;
+ using FetchFamilyResultsCallback = base::OnceCallback<void(
+ const api::passwords_private::FamilyFetchResults&)>;
+
+ using ShareRecipients = std::vector<api::passwords_private::RecipientInfo>;
+
using PlaintextPasswordCallback =
base::OnceCallback<void(absl::optional<std::u16string>)>;
@@ -87,15 +92,6 @@ class PasswordsPrivateDelegate
bool use_account_store,
content::WebContents* web_contents) = 0;
- // Changes the username and password corresponding to |ids|.
- // |ids|: The ids for the password entries being updated.
- // |params|: The struct which holds the new username, password and note.
- // Returns the ids if the change was successful (can be the same ids if the
- // username and the password didn't change), nullopt otherwise.
- virtual absl::optional<int> ChangeSavedPassword(
- int id,
- const api::passwords_private::ChangeSavedPasswordParams& params) = 0;
-
// Updates a credential. Not all attributes can be updated.
// |credential|: The credential to be updated. Matched to an existing
// credential by id.
@@ -154,6 +150,15 @@ class PasswordsPrivateDelegate
virtual void MovePasswordsToAccount(const std::vector<int>& ids,
content::WebContents* web_contents) = 0;
+ // Fetches family members of the current user for the password sharing flow.
+ // |callback|: Used to communicate the status of a request to fetch family
+ // members, as well as the data returned in the response.
+ virtual void FetchFamilyMembers(FetchFamilyResultsCallback callback) = 0;
+
+ // Sends sharing invitations for a credential with given |id| to the
+ // |recipients|.
+ virtual void SharePassword(int id, const ShareRecipients& recipients) = 0;
+
// Trigger the password import procedure, allowing the user to select a file
// containing passwords to import.
// |to_store|: destination store (Device or Account) for imported passwords.
@@ -186,9 +191,6 @@ class PasswordsPrivateDelegate
base::OnceCallback<void(const std::string&)> callback,
content::WebContents* web_contents) = 0;
- // Cancel any ongoing export.
- virtual void CancelExportPasswords() = 0;
-
// Get the most recent progress status.
virtual api::passwords_private::ExportProgressStatus
GetExportProgressStatus() = 0;
@@ -225,15 +227,9 @@ class PasswordsPrivateDelegate
virtual bool UnmuteInsecureCredential(
const api::passwords_private::PasswordUiEntry& credential) = 0;
- // Records that a change password flow was started for |credential|.
- virtual void RecordChangePasswordFlowStarted(
- const api::passwords_private::PasswordUiEntry& credential) = 0;
-
// Requests to start a check for insecure passwords. Invokes |callback|
// once a check is running or the request was stopped via StopPasswordCheck().
virtual void StartPasswordCheck(StartPasswordCheckCallback callback) = 0;
- // Stops a check for insecure passwords.
- virtual void StopPasswordCheck() = 0;
// Returns the current status of the password check.
virtual api::passwords_private::PasswordCheckStatus
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.cc
index 8543dddf70a..399c04f1457 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.cc
@@ -23,36 +23,23 @@ using content::BrowserContext;
PasswordsPrivateDelegateProxy::PasswordsPrivateDelegateProxy(
BrowserContext* browser_context)
- : browser_context_(browser_context) {
- if (base::FeatureList::IsEnabled(
- password_manager::features::kPasswordManagerRedesign)) {
- return;
- }
- scoped_instance_ = base::MakeRefCounted<PasswordsPrivateDelegateImpl>(
- static_cast<Profile*>(browser_context_));
-}
+ : browser_context_(browser_context) {}
PasswordsPrivateDelegateProxy::PasswordsPrivateDelegateProxy(
BrowserContext* browser_context,
scoped_refptr<PasswordsPrivateDelegate> delegate)
- : browser_context_(browser_context), scoped_instance_(std::move(delegate)) {
- weak_instance_ = scoped_instance_->AsWeakPtr();
+ : browser_context_(browser_context) {
+ weak_instance_ = delegate->AsWeakPtr();
}
PasswordsPrivateDelegateProxy::~PasswordsPrivateDelegateProxy() = default;
void PasswordsPrivateDelegateProxy::Shutdown() {
browser_context_ = nullptr;
weak_instance_ = nullptr;
- scoped_instance_ = nullptr;
}
scoped_refptr<PasswordsPrivateDelegate>
PasswordsPrivateDelegateProxy::GetOrCreateDelegate() {
- if (!base::FeatureList::IsEnabled(
- password_manager::features::kPasswordManagerRedesign)) {
- return scoped_instance_;
- }
-
if (weak_instance_) {
return scoped_refptr<PasswordsPrivateDelegate>(weak_instance_.get());
}
@@ -66,11 +53,7 @@ PasswordsPrivateDelegateProxy::GetOrCreateDelegate() {
scoped_refptr<PasswordsPrivateDelegate>
PasswordsPrivateDelegateProxy::GetDelegate() {
- if (base::FeatureList::IsEnabled(
- password_manager::features::kPasswordManagerRedesign)) {
- return scoped_refptr<PasswordsPrivateDelegate>(weak_instance_.get());
- }
- return scoped_instance_;
+ return scoped_refptr<PasswordsPrivateDelegate>(weak_instance_.get());
}
// static
@@ -109,9 +92,10 @@ PasswordsPrivateDelegateFactory::PasswordsPrivateDelegateFactory()
PasswordsPrivateDelegateFactory::~PasswordsPrivateDelegateFactory() = default;
-KeyedService* PasswordsPrivateDelegateFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+PasswordsPrivateDelegateFactory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* profile) const {
- return new PasswordsPrivateDelegateProxy(profile);
+ return std::make_unique<PasswordsPrivateDelegateProxy>(profile);
}
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h
index 2303b8ea9db..49e0e0f9056 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h
@@ -44,9 +44,6 @@ class PasswordsPrivateDelegateProxy : public KeyedService {
raw_ptr<content::BrowserContext> browser_context_ = nullptr;
base::WeakPtr<PasswordsPrivateDelegate> weak_instance_;
- // TODO(crbug.com/1412348): Remove this after the feature is enabled by
- // default.
- scoped_refptr<PasswordsPrivateDelegate> scoped_instance_;
};
// Factory for creating PasswordPrivateDelegates.
@@ -65,7 +62,7 @@ class PasswordsPrivateDelegateFactory : public ProfileKeyedServiceFactory {
~PasswordsPrivateDelegateFactory() override;
// BrowserContextKeyedServiceFactory implementation.
- KeyedService* BuildServiceInstanceFor(
+ std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
content::BrowserContext* profile) const override;
};
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
index 5c87121acf7..b1a28a5a678 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc
@@ -23,6 +23,7 @@
#include "chrome/browser/password_manager/account_password_store_factory.h"
#include "chrome/browser/password_manager/affiliation_service_factory.h"
#include "chrome/browser/password_manager/chrome_password_manager_client.h"
+#include "chrome/browser/password_manager/password_sender_service_factory.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
@@ -40,16 +41,20 @@
#include "chrome/browser/web_applications/web_app_install_params.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/webauthn/passkey_model_factory.h"
+#include "chrome/common/channel_info.h"
#include "chrome/common/extensions/api/passwords_private.h"
#include "chrome/grit/generated_resources.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/keyed_service/core/service_access_type.h"
#include "components/password_manager/core/browser/affiliation/affiliation_utils.h"
+#include "components/password_manager/core/browser/features/password_features.h"
#include "components/password_manager/core/browser/password_access_authenticator.h"
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_manager_features_util.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/browser/password_sync_util.h"
+#include "components/password_manager/core/browser/sharing/password_sender_service.h"
+#include "components/password_manager/core/browser/sharing/recipients_fetcher_impl.h"
#include "components/password_manager/core/browser/ui/credential_ui_entry.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/prefs/pref_service.h"
@@ -58,6 +63,7 @@
#include "components/sync/service/sync_service.h"
#include "components/url_formatter/elide_url.h"
#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
@@ -86,6 +92,7 @@ namespace {
using password_manager::CredentialFacet;
using password_manager::CredentialUIEntry;
+using password_manager::FetchFamilyMembersRequestStatus;
// The error message returned to the UI when Chrome refuses to start multiple
// exports.
@@ -417,35 +424,6 @@ bool PasswordsPrivateDelegateImpl::AddPassword(
return success;
}
-absl::optional<int> PasswordsPrivateDelegateImpl::ChangeSavedPassword(
- int id,
- const api::passwords_private::ChangeSavedPasswordParams& params) {
- const CredentialUIEntry* original_credential =
- credential_id_generator_.TryGetKey(id);
- if (!original_credential) {
- return absl::nullopt;
- }
-
- CredentialUIEntry updated_credential = *original_credential;
- updated_credential.username = base::UTF8ToUTF16(params.username);
- updated_credential.password = base::UTF8ToUTF16(params.password);
- if (params.note) {
- updated_credential.note = base::UTF8ToUTF16(*params.note);
- }
- switch (saved_passwords_presenter_.EditSavedCredentials(*original_credential,
- updated_credential)) {
- case password_manager::SavedPasswordsPresenter::EditResult::kSuccess:
- case password_manager::SavedPasswordsPresenter::EditResult::kNothingChanged:
- break;
- case password_manager::SavedPasswordsPresenter::EditResult::kNotFound:
- case password_manager::SavedPasswordsPresenter::EditResult::kAlreadyExisits:
- case password_manager::SavedPasswordsPresenter::EditResult::kEmptyPassword:
- return absl::nullopt;
- }
-
- return credential_id_generator_.GenerateId(std::move(updated_credential));
-}
-
bool PasswordsPrivateDelegateImpl::ChangeCredential(
const api::passwords_private::PasswordUiEntry& credential) {
const CredentialUIEntry* original_credential =
@@ -581,6 +559,49 @@ void PasswordsPrivateDelegateImpl::OsReauthCall(
#endif
}
+void PasswordsPrivateDelegateImpl::OnFetchingFamilyMembersCompleted(
+ FetchFamilyResultsCallback callback,
+ std::vector<password_manager::RecipientInfo> family_members,
+ FetchFamilyMembersRequestStatus request_status) {
+ api::passwords_private::FamilyFetchResults results;
+ switch (request_status) {
+ case FetchFamilyMembersRequestStatus::kUnknown:
+ case FetchFamilyMembersRequestStatus::kNetworkError:
+ case FetchFamilyMembersRequestStatus::kPendingRequest:
+ results.status = api::passwords_private::FamilyFetchStatus::
+ FAMILY_FETCH_STATUS_UNKNOWN_ERROR;
+ break;
+ case FetchFamilyMembersRequestStatus::kSuccess:
+ results.status = api::passwords_private::FamilyFetchStatus::
+ FAMILY_FETCH_STATUS_SUCCESS;
+ break;
+ case FetchFamilyMembersRequestStatus::kNoFamily:
+ results.status = api::passwords_private::FamilyFetchStatus::
+ FAMILY_FETCH_STATUS_NO_MEMBERS;
+ }
+ if (request_status == FetchFamilyMembersRequestStatus::kSuccess) {
+ for (const password_manager::RecipientInfo& family_member :
+ family_members) {
+ api::passwords_private::RecipientInfo recipient_info;
+ recipient_info.user_id = family_member.user_id;
+ recipient_info.email = family_member.email;
+ recipient_info.display_name = family_member.user_name;
+ recipient_info.profile_image_url = family_member.profile_image_url;
+
+ if (!family_member.public_key.key.empty()) {
+ recipient_info.is_eligible = true;
+ api::passwords_private::PublicKey public_key;
+ public_key.value = family_member.public_key.key;
+ public_key.version = family_member.public_key.key_version;
+ recipient_info.public_key = std::move(public_key);
+ }
+
+ results.family_members.push_back(std::move(recipient_info));
+ }
+ }
+ std::move(callback).Run(results);
+}
+
void PasswordsPrivateDelegateImpl::OsReauthTimeoutCall() {
#if !BUILDFLAG(IS_LINUX)
PasswordsPrivateEventRouter* router =
@@ -611,17 +632,14 @@ void PasswordsPrivateDelegateImpl::SetCredentials(
CreatePasswordUiEntryFromCredentialUiEntry(std::move(credential)));
}
}
- if (base::FeatureList::IsEnabled(
- password_manager::features::kPasswordsGrouping)) {
- for (CredentialUIEntry& credential :
- saved_passwords_presenter_.GetBlockedSites()) {
- api::passwords_private::ExceptionEntry current_exception_entry;
- current_exception_entry.urls =
- CreateUrlCollectionFromCredential(credential);
- current_exception_entry.id =
- credential_id_generator_.GenerateId(std::move(credential));
- current_exceptions_.push_back(std::move(current_exception_entry));
- }
+ for (CredentialUIEntry& credential :
+ saved_passwords_presenter_.GetBlockedSites()) {
+ api::passwords_private::ExceptionEntry current_exception_entry;
+ current_exception_entry.urls =
+ CreateUrlCollectionFromCredential(credential);
+ current_exception_entry.id =
+ credential_id_generator_.GenerateId(std::move(credential));
+ current_exceptions_.push_back(std::move(current_exception_entry));
}
if (current_entries_initialized_) {
@@ -677,6 +695,49 @@ void PasswordsPrivateDelegateImpl::MovePasswordsToAccount(
kExplicitlyTriggeredForMultiplePasswordsInSettings);
}
+void PasswordsPrivateDelegateImpl::FetchFamilyMembers(
+ FetchFamilyResultsCallback callback) {
+ if (!sharing_password_recipients_fetcher_) {
+ sharing_password_recipients_fetcher_ =
+ std::make_unique<password_manager::RecipientsFetcherImpl>(
+ chrome::GetChannel(),
+ profile_->GetDefaultStoragePartition()
+ ->GetURLLoaderFactoryForBrowserProcess(),
+ IdentityManagerFactory::GetForProfile(profile_));
+ }
+ sharing_password_recipients_fetcher_->FetchFamilyMembers(base::BindOnce(
+ &PasswordsPrivateDelegateImpl::OnFetchingFamilyMembersCompleted,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void PasswordsPrivateDelegateImpl::SharePassword(
+ int id,
+ const ShareRecipients& recipients) {
+ const CredentialUIEntry* entry = credential_id_generator_.TryGetKey(id);
+ if (!entry) {
+ return;
+ }
+
+ std::vector<password_manager::PasswordForm> corresponding_credentials =
+ saved_passwords_presenter_.GetCorrespondingPasswordForms(*entry);
+ if (corresponding_credentials.empty()) {
+ return;
+ }
+
+ password_manager::PasswordSenderService* password_sender_service =
+ PasswordSenderServiceFactory::GetForProfile(profile_);
+ for (const api::passwords_private::RecipientInfo& recipient_info :
+ recipients) {
+ CHECK(recipient_info.public_key.has_value());
+ password_manager::PublicKey public_key;
+ public_key.key = recipient_info.public_key.value().value;
+ public_key.key_version = recipient_info.public_key.value().version;
+ password_sender_service->SendPasswords(
+ corresponding_credentials, {.user_id = recipient_info.user_id,
+ .public_key = std::move(public_key)});
+ }
+}
+
void PasswordsPrivateDelegateImpl::ImportPasswords(
api::passwords_private::PasswordStoreSet to_store,
ImportResultsCallback results_callback,
@@ -742,10 +803,6 @@ void PasswordsPrivateDelegateImpl::ExportPasswords(
std::move(accepted_callback), web_contents));
}
-void PasswordsPrivateDelegateImpl::CancelExportPasswords() {
- password_manager_porter_->CancelExport();
-}
-
api::passwords_private::ExportProgressStatus
PasswordsPrivateDelegateImpl::GetExportProgressStatus() {
return ConvertStatus(password_manager_porter_->GetExportProgressStatus());
@@ -795,20 +852,11 @@ bool PasswordsPrivateDelegateImpl::UnmuteInsecureCredential(
return password_check_delegate_.UnmuteInsecureCredential(credential);
}
-void PasswordsPrivateDelegateImpl::RecordChangePasswordFlowStarted(
- const api::passwords_private::PasswordUiEntry& credential) {
- password_check_delegate_.RecordChangePasswordFlowStarted(credential);
-}
-
void PasswordsPrivateDelegateImpl::StartPasswordCheck(
StartPasswordCheckCallback callback) {
password_check_delegate_.StartPasswordCheck(std::move(callback));
}
-void PasswordsPrivateDelegateImpl::StopPasswordCheck() {
- password_check_delegate_.StopPasswordCheck();
-}
-
api::passwords_private::PasswordCheckStatus
PasswordsPrivateDelegateImpl::GetPasswordCheckStatus() {
return password_check_delegate_.GetPasswordCheckStatus();
@@ -1082,43 +1130,32 @@ api::passwords_private::PasswordUiEntry
PasswordsPrivateDelegateImpl::CreatePasswordUiEntryFromCredentialUiEntry(
CredentialUIEntry credential) {
api::passwords_private::PasswordUiEntry entry;
- if (base::FeatureList::IsEnabled(
- password_manager::features::kPasswordsGrouping)) {
- entry.affiliated_domains =
- std::vector<api::passwords_private::DomainInfo>();
- base::ranges::transform(
- credential.GetAffiliatedDomains(),
- std::back_inserter(entry.affiliated_domains.value()),
- [](const CredentialUIEntry::DomainInfo& domain) {
- api::passwords_private::DomainInfo domainInfo;
- domainInfo.name = domain.name;
- domainInfo.url = domain.url.spec();
- domainInfo.signon_realm = domain.signon_realm;
- return domainInfo;
- });
- }
+ base::ranges::transform(credential.GetAffiliatedDomains(),
+ std::back_inserter(entry.affiliated_domains),
+ [](const CredentialUIEntry::DomainInfo& domain) {
+ api::passwords_private::DomainInfo domain_info;
+ domain_info.name = domain.name;
+ domain_info.url = domain.url.spec();
+ domain_info.signon_realm = domain.signon_realm;
+ return domain_info;
+ });
entry.is_passkey = !credential.passkey_credential_id.empty();
- entry.urls = extensions::CreateUrlCollectionFromCredential(credential);
entry.username = base::UTF16ToUTF8(credential.username);
if (entry.is_passkey) {
entry.display_name = base::UTF16ToUTF8(credential.user_display_name);
}
entry.stored_in = extensions::StoreSetFromCredential(credential);
- entry.is_android_credential = password_manager::IsValidAndroidFacetURI(
- credential.GetFirstSignonRealm());
if (!credential.federation_origin.opaque()) {
std::u16string formatted_origin =
url_formatter::FormatOriginForSecurityDisplay(
credential.federation_origin,
url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);
- if (base::FeatureList::IsEnabled(
- password_manager::features::kPasswordsGrouping)) {
- entry.federation_text = base::UTF16ToUTF8(formatted_origin);
- } else {
- entry.federation_text = l10n_util::GetStringFUTF8(
- IDS_PASSWORDS_VIA_FEDERATION, formatted_origin);
- }
+ entry.federation_text = base::UTF16ToUTF8(formatted_origin);
+ }
+ absl::optional<GURL> change_password_url = credential.GetChangePasswordURL();
+ if (change_password_url.has_value()) {
+ entry.change_password_url = change_password_url->spec();
}
entry.id = credential_id_generator_.GenerateId(std::move(credential));
return entry;
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h
index c58c40cc112..fa365a225a6 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h
@@ -28,6 +28,7 @@
#include "components/password_manager/core/browser/password_access_authenticator.h"
#include "components/password_manager/core/browser/password_account_storage_settings_watcher.h"
#include "components/password_manager/core/browser/reauth_purpose.h"
+#include "components/password_manager/core/browser/sharing/recipients_fetcher.h"
#include "components/password_manager/core/browser/ui/credential_ui_entry.h"
#include "components/password_manager/core/browser/ui/export_progress_status.h"
#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
@@ -44,6 +45,10 @@ namespace web_app {
class WebAppInstallManager;
}
+namespace password_manager {
+class RecipientsFetcher;
+}
+
namespace extensions {
// Concrete PasswordsPrivateDelegate implementation.
@@ -71,9 +76,6 @@ class PasswordsPrivateDelegateImpl
const std::u16string& note,
bool use_account_store,
content::WebContents* web_contents) override;
- absl::optional<int> ChangeSavedPassword(
- int id,
- const api::passwords_private::ChangeSavedPasswordParams& params) override;
bool ChangeCredential(
const api::passwords_private::PasswordUiEntry& credential) override;
void RemoveCredential(
@@ -90,6 +92,8 @@ class PasswordsPrivateDelegateImpl
content::WebContents* web_contents) override;
void MovePasswordsToAccount(const std::vector<int>& ids,
content::WebContents* web_contents) override;
+ void FetchFamilyMembers(FetchFamilyResultsCallback callback) override;
+ void SharePassword(int id, const ShareRecipients& recipients) override;
void ImportPasswords(api::passwords_private::PasswordStoreSet to_store,
ImportResultsCallback results_callback,
content::WebContents* web_contents) override;
@@ -100,7 +104,6 @@ class PasswordsPrivateDelegateImpl
void ExportPasswords(
base::OnceCallback<void(const std::string&)> accepted_callback,
content::WebContents* web_contents) override;
- void CancelExportPasswords() override;
api::passwords_private::ExportProgressStatus GetExportProgressStatus()
override;
bool IsOptedInForAccountStorage() override;
@@ -115,10 +118,7 @@ class PasswordsPrivateDelegateImpl
const api::passwords_private::PasswordUiEntry& credential) override;
bool UnmuteInsecureCredential(
const api::passwords_private::PasswordUiEntry& credential) override;
- void RecordChangePasswordFlowStarted(
- const api::passwords_private::PasswordUiEntry& credential) override;
void StartPasswordCheck(StartPasswordCheckCallback callback) override;
- void StopPasswordCheck() override;
api::passwords_private::PasswordCheckStatus GetPasswordCheckStatus() override;
password_manager::InsecureCredentialsManager* GetInsecureCredentialsManager()
override;
@@ -147,6 +147,14 @@ class PasswordsPrivateDelegateImpl
std::unique_ptr<PasswordManagerPorterInterface> porter) {
password_manager_porter_ = std::move(porter);
}
+
+ void SetRecipientsFetcherForTesting(
+ std::unique_ptr<password_manager::RecipientsFetcher>
+ sharing_password_recipients_fetcher) {
+ sharing_password_recipients_fetcher_ =
+ std::move(sharing_password_recipients_fetcher);
+ }
+
#endif // defined(UNIT_TEST)
private:
@@ -215,6 +223,11 @@ class PasswordsPrivateDelegateImpl
password_manager::PasswordAccessAuthenticator::AuthResultCallback
callback);
+ void OnFetchingFamilyMembersCompleted(
+ FetchFamilyResultsCallback callback,
+ std::vector<password_manager::RecipientInfo> recipients_info,
+ password_manager::FetchFamilyMembersRequestStatus request_status);
+
// Records user action and emits histogram values for retrieving |entry|.
void EmitHistogramsForCredentialAccess(
const password_manager::CredentialUIEntry& entry,
@@ -284,6 +297,9 @@ class PasswordsPrivateDelegateImpl
web_app::WebAppInstallManagerObserver>
install_manager_observation_{this};
+ std::unique_ptr<password_manager::RecipientsFetcher>
+ sharing_password_recipients_fetcher_;
+
base::WeakPtrFactory<PasswordsPrivateDelegateImpl> weak_ptr_factory_{this};
};
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc
index 50bb05d5bd1..424682ae852 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc
@@ -10,7 +10,9 @@
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
+#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
+#include "base/rand_util.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
@@ -28,7 +30,9 @@
#include "chrome/browser/password_manager/affiliation_service_factory.h"
#include "chrome/browser/password_manager/chrome_password_manager_client.h"
#include "chrome/browser/password_manager/password_manager_test_util.h"
+#include "chrome/browser/password_manager/password_sender_service_factory.h"
#include "chrome/browser/sync/sync_service_factory.h"
+#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
@@ -48,6 +52,7 @@
#include "components/keyed_service/core/keyed_service.h"
#include "components/password_manager/content/browser/password_manager_log_router_factory.h"
#include "components/password_manager/core/browser/affiliation/fake_affiliation_service.h"
+#include "components/password_manager/core/browser/features/password_features.h"
#include "components/password_manager/core/browser/insecure_credentials_table.h"
#include "components/password_manager/core/browser/mock_password_feature_manager.h"
#include "components/password_manager/core/browser/password_form.h"
@@ -55,11 +60,16 @@
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/reauth_purpose.h"
+#include "components/password_manager/core/browser/sharing/mock_password_sender_service.h"
+#include "components/password_manager/core/browser/sharing/password_sharing_recipients_downloader.h"
+#include "components/password_manager/core/browser/sharing/recipients_fetcher_impl.h"
#include "components/password_manager/core/browser/test_password_store.h"
#include "components/password_manager/core/browser/ui/import_results.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/signin/public/base/signin_metrics.h"
+#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/sync/base/features.h"
+#include "components/sync/protocol/password_sharing_recipients.pb.h"
#include "components/sync/test/test_sync_service.h"
#include "components/webauthn/core/browser/test_passkey_model.h"
#include "content/public/browser/browser_context.h"
@@ -80,12 +90,21 @@
using MockReauthCallback = base::MockCallback<
password_manager::PasswordAccessAuthenticator::ReauthCallback>;
+using extensions::api::passwords_private::FamilyFetchResults;
+using extensions::api::passwords_private::RecipientInfo;
+using password_manager::PasswordForm;
+using password_manager::PasswordRecipient;
using password_manager::ReauthPurpose;
using password_manager::TestPasswordStore;
using ::testing::_;
+using ::testing::AllOf;
+using ::testing::ElementsAre;
using ::testing::Eq;
+using ::testing::Field;
+using ::testing::IsEmpty;
using ::testing::IsNull;
using ::testing::Ne;
+using ::testing::Optional;
using ::testing::Return;
using ::testing::SizeIs;
using ::testing::StrictMock;
@@ -94,6 +113,16 @@ namespace extensions {
namespace {
constexpr char kHistogramName[] = "PasswordManager.AccessPasswordInSettings";
+constexpr char kSharingRecipientId1[] = "user id 1";
+constexpr char kSharingRecipientKeyValue1[] = "key 1";
+constexpr char kSharingRecipientKeyValue2[] = "key 2";
+constexpr char kSharingRecipientId2[] = "user id 2";
+constexpr char kSharingRecipientDisplayName1[] = "User One";
+constexpr char kSharingRecipientDisplayName2[] = "User Two";
+constexpr char kSharingRecipientEmail1[] = "user1@example.com";
+constexpr char kSharingRecipientEmail2[] = "user2@example.com";
+constexpr char kSharingRecipientProfileImageUrl1[] = "image1.example.com";
+constexpr char kSharingRecipientProfileImageUrl2[] = "image2.example.com";
using MockPlaintextPasswordCallback =
base::MockCallback<PasswordsPrivateDelegate::PlaintextPasswordCallback>;
@@ -111,7 +140,7 @@ class MockPasswordManagerPorter : public PasswordManagerPorterInterface {
MOCK_METHOD(void,
Import,
(content::WebContents * web_contents,
- password_manager::PasswordForm::Store to_store,
+ PasswordForm::Store to_store,
ImportResultsCallback results_callback),
(override));
MOCK_METHOD(void,
@@ -133,7 +162,7 @@ class FakePasswordManagerPorter : public PasswordManagerPorterInterface {
}
void Import(content::WebContents* web_contents,
- password_manager::PasswordForm::Store to_store,
+ PasswordForm::Store to_store,
ImportResultsCallback results_callback) override {
password_manager::ImportResults results;
results.status = import_results_status_;
@@ -199,7 +228,7 @@ class MockPasswordManagerClient : public ChromePasswordManagerClient {
private:
explicit MockPasswordManagerClient(content::WebContents* web_contents)
- : ChromePasswordManagerClient(web_contents, nullptr) {}
+ : ChromePasswordManagerClient(web_contents) {}
password_manager::MockPasswordFeatureManager mock_password_feature_manager_;
scoped_refptr<device_reauth::MockDeviceAuthenticator>
@@ -289,11 +318,10 @@ std::unique_ptr<KeyedService> BuildPasswordsPrivateEventRouter(
PasswordsPrivateEventRouter::Create(context));
}
-password_manager::PasswordForm CreateSampleForm(
- password_manager::PasswordForm::Store store =
- password_manager::PasswordForm::Store::kProfileStore,
+PasswordForm CreateSampleForm(
+ PasswordForm::Store store = PasswordForm::Store::kProfileStore,
const std::u16string& username = u"test@gmail.com") {
- password_manager::PasswordForm form;
+ PasswordForm form;
form.signon_realm = "https://abc1.com";
form.url = GURL("https://abc1.com");
form.username_value = username;
@@ -315,19 +343,19 @@ sync_pb::WebauthnCredentialSpecifics CreatePasskey() {
MATCHER_P(PasswordUiEntryDataEquals, expected, "") {
return testing::Value(expected.get().is_passkey, arg.is_passkey) &&
- testing::Value(expected.get().urls.link, arg.urls.link) &&
+ testing::Value(expected.get().affiliated_domains[0].signon_realm,
+ arg.affiliated_domains[0].signon_realm) &&
testing::Value(expected.get().username, arg.username) &&
testing::Value(expected.get().display_name, arg.display_name) &&
- testing::Value(expected.get().stored_in, arg.stored_in) &&
- testing::Value(expected.get().is_android_credential,
- arg.is_android_credential);
+ testing::Value(expected.get().stored_in, arg.stored_in);
}
} // namespace
class PasswordsPrivateDelegateImplTest : public WebAppTest {
public:
- PasswordsPrivateDelegateImplTest() = default;
+ PasswordsPrivateDelegateImplTest()
+ : WebAppTest(WebAppTest::WithTestUrlLoaderFactory()) {}
PasswordsPrivateDelegateImplTest(const PasswordsPrivateDelegateImplTest&) =
delete;
@@ -339,7 +367,7 @@ class PasswordsPrivateDelegateImplTest : public WebAppTest {
void SetUp() override;
// Sets up a testing password store and fills it with |forms|.
- void SetUpPasswordStores(std::vector<password_manager::PasswordForm> forms);
+ void SetUpPasswordStores(std::vector<PasswordForm> forms);
// Sets up a testing EventRouter with a production
// PasswordsPrivateEventRouter.
@@ -355,6 +383,16 @@ class PasswordsPrivateDelegateImplTest : public WebAppTest {
PasswordsPrivateDelegate::UiEntries GetCredentials(
PasswordsPrivateDelegate& delegate);
+ // Returns a test `WebContents` with an initialized Autofill client, which is
+ // needed for PasswordManager client to work properly.
+ std::unique_ptr<content::WebContents> CreateWebContents() {
+ std::unique_ptr<content::WebContents> web_contents =
+ content::WebContentsTester::CreateTestWebContents(profile(),
+ /*instance=*/nullptr);
+ autofill::ChromeAutofillClient::CreateForWebContents(web_contents.get());
+ return web_contents;
+ }
+
protected:
raw_ptr<extensions::TestEventRouter, DanglingUntriaged> event_router_ =
nullptr;
@@ -391,11 +429,17 @@ void PasswordsPrivateDelegateImplTest::SetUp() {
[](content::BrowserContext*) -> std::unique_ptr<KeyedService> {
return std::make_unique<webauthn::TestPasskeyModel>();
}));
+
+ PasswordSenderServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+ profile(), base::BindRepeating([](content::BrowserContext*)
+ -> std::unique_ptr<KeyedService> {
+ return std::make_unique<password_manager::MockPasswordSenderService>();
+ }));
}
void PasswordsPrivateDelegateImplTest::SetUpPasswordStores(
- std::vector<password_manager::PasswordForm> forms) {
- for (const password_manager::PasswordForm& form : forms) {
+ std::vector<PasswordForm> forms) {
+ for (const PasswordForm& form : forms) {
if (form.IsUsingAccountStore())
account_store_->AddLogin(form);
else if (form.IsUsingProfileStore())
@@ -450,10 +494,10 @@ TEST_F(PasswordsPrivateDelegateImplTest,
PasswordsDuplicatedInStoresAreRepresentedAsSingleEntity) {
auto delegate = CreateDelegate();
- password_manager::PasswordForm account_password =
- CreateSampleForm(password_manager::PasswordForm::Store::kAccountStore);
- password_manager::PasswordForm profile_password =
- CreateSampleForm(password_manager::PasswordForm::Store::kProfileStore);
+ PasswordForm account_password =
+ CreateSampleForm(PasswordForm::Store::kAccountStore);
+ PasswordForm profile_password =
+ CreateSampleForm(PasswordForm::Store::kProfileStore);
SetUpPasswordStores({account_password, profile_password});
@@ -485,16 +529,14 @@ TEST_F(PasswordsPrivateDelegateImplTest, GetPasswordExceptionsList) {
TEST_F(PasswordsPrivateDelegateImplTest,
ExceptionsDuplicatedInStoresAreRepresentedAsSingleEntity) {
auto delegate = CreateDelegate();
- password_manager::PasswordForm account_exception;
+ PasswordForm account_exception;
account_exception.blocked_by_user = true;
account_exception.url = GURL("https://test.com");
- account_exception.in_store =
- password_manager::PasswordForm::Store::kAccountStore;
- password_manager::PasswordForm profile_exception;
+ account_exception.in_store = PasswordForm::Store::kAccountStore;
+ PasswordForm profile_exception;
profile_exception.url = GURL("https://test.com");
profile_exception.blocked_by_user = true;
- profile_exception.in_store =
- password_manager::PasswordForm::Store::kProfileStore;
+ profile_exception.in_store = PasswordForm::Store::kProfileStore;
SetUpPasswordStores({account_exception, profile_exception});
@@ -506,8 +548,7 @@ TEST_F(PasswordsPrivateDelegateImplTest,
}
TEST_F(PasswordsPrivateDelegateImplTest, AddPassword) {
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
ON_CALL(*(client->GetPasswordFeatureManager()), IsOptedInForAccountStorage)
@@ -537,13 +578,17 @@ TEST_F(PasswordsPrivateDelegateImplTest, AddPassword) {
// Check that adding passwords got reflected in the passwords list.
api::passwords_private::PasswordUiEntry expected_entry1;
- expected_entry1.urls.link = "https://example1.com/";
+ expected_entry1.affiliated_domains.emplace_back();
+ expected_entry1.affiliated_domains.back().signon_realm =
+ "https://example1.com/";
expected_entry1.username = "username1";
expected_entry1.note.emplace();
expected_entry1.stored_in =
api::passwords_private::PASSWORD_STORE_SET_ACCOUNT;
api::passwords_private::PasswordUiEntry expected_entry2;
- expected_entry2.urls.link = "http://example2.com/login";
+ expected_entry2.affiliated_domains.emplace_back();
+ expected_entry2.affiliated_domains.back().signon_realm =
+ "http://example2.com/";
expected_entry2.username = "";
expected_entry2.note = "note";
expected_entry2.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
@@ -555,8 +600,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, AddPassword) {
}
TEST_F(PasswordsPrivateDelegateImplTest, AddPasswordUpdatesDefaultStore) {
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
auto delegate = CreateDelegate();
@@ -574,8 +618,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, AddPasswordUpdatesDefaultStore) {
ON_CALL(*(client->GetPasswordFeatureManager()), IsOptedInForAccountStorage)
.WillByDefault(Return(true));
EXPECT_CALL(*(client->GetPasswordFeatureManager()),
- SetDefaultPasswordStore(
- password_manager::PasswordForm::Store::kAccountStore));
+ SetDefaultPasswordStore(PasswordForm::Store::kAccountStore));
EXPECT_TRUE(
delegate->AddPassword("example2.com", u"username2", u"password2", u"",
/*use_account_store=*/true, web_contents.get()));
@@ -590,8 +633,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, AddPasswordUpdatesDefaultStore) {
TEST_F(PasswordsPrivateDelegateImplTest,
ImportPasswordsDoesNotUpdateDefaultStore) {
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
auto delegate = CreateDelegate();
@@ -613,8 +655,7 @@ TEST_F(PasswordsPrivateDelegateImplTest,
}
TEST_F(PasswordsPrivateDelegateImplTest, ImportPasswordsUpdatesDefaultStore) {
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
auto delegate = CreateDelegate();
@@ -628,8 +669,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, ImportPasswordsUpdatesDefaultStore) {
ON_CALL(*(client->GetPasswordFeatureManager()), IsOptedInForAccountStorage)
.WillByDefault(Return(true));
EXPECT_CALL(*(client->GetPasswordFeatureManager()),
- SetDefaultPasswordStore(
- password_manager::PasswordForm::Store::kAccountStore));
+ SetDefaultPasswordStore(PasswordForm::Store::kAccountStore));
EXPECT_CALL(*mock_porter_ptr, Import).Times(1);
delegate->ImportPasswords(
api::passwords_private::PasswordStoreSet::PASSWORD_STORE_SET_ACCOUNT,
@@ -638,9 +678,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, ImportPasswordsUpdatesDefaultStore) {
TEST_F(PasswordsPrivateDelegateImplTest,
ImportPasswordsLogsImportResultsStatus) {
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(),
- /*instance=*/nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
auto delegate = CreateDelegate();
@@ -672,9 +710,7 @@ TEST_F(PasswordsPrivateDelegateImplTest,
}
TEST_F(PasswordsPrivateDelegateImplTest, TestReauthFailedOnImport) {
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(),
- /*instance=*/nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
@@ -717,9 +753,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, TestReauthFailedOnImport) {
TEST_F(PasswordsPrivateDelegateImplTest,
ContinueImportLogsImportResultsStatus) {
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(),
- /*instance=*/nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
scoped_refptr<PasswordsPrivateDelegateImpl> delegate = CreateDelegate();
@@ -760,120 +794,8 @@ TEST_F(PasswordsPrivateDelegateImplTest, ResetImporter) {
delegate->ResetImporter(/*delete_file=*/false);
}
-TEST_F(PasswordsPrivateDelegateImplTest, ChangeSavedPassword) {
- password_manager::PasswordForm sample_form = CreateSampleForm();
- SetUpPasswordStores({sample_form});
- auto delegate = CreateDelegate();
- // Spin the loop to allow PasswordStore tasks posted on the creation of
- // |delegate| to be completed.
- base::RunLoop().RunUntilIdle();
-
- // Double check that the contents of the passwords list matches our
- // expectation.
- base::MockCallback<PasswordsPrivateDelegate::UiEntriesCallback> callback;
- EXPECT_CALL(callback, Run(SizeIs(1)))
- .WillOnce([&](const PasswordsPrivateDelegate::UiEntries& passwords) {
- EXPECT_EQ(sample_form.username_value,
- base::UTF8ToUTF16(passwords[0].username));
- });
- delegate->GetSavedPasswordsList(callback.Get());
- int sample_form_id = delegate->GetIdForCredential(
- password_manager::CredentialUIEntry(sample_form));
-
- api::passwords_private::ChangeSavedPasswordParams params;
- params.password = "new_pass";
- params.username = "new_user";
- params.note = "new note";
-
- sample_form.username_value = u"new_user";
- sample_form.password_value = u"new_pass";
- int new_form_id = delegate->GetIdForCredential(
- password_manager::CredentialUIEntry(sample_form));
-
- auto result = delegate->ChangeSavedPassword(sample_form_id, params);
- EXPECT_EQ(result, new_form_id);
-
- // Spin the loop to allow PasswordStore tasks posted when changing the
- // password to be completed.
- base::RunLoop().RunUntilIdle();
-
- // Check that the changing the password got reflected in the passwords list.
- // `note` field should not be filled when `GetSavedPasswordsList` is called.
- EXPECT_CALL(callback, Run(SizeIs(1)))
- .WillOnce([](const PasswordsPrivateDelegate::UiEntries& passwords) {
- EXPECT_THAT(passwords[0].username, Eq("new_user"));
- EXPECT_THAT(passwords[0].note, Eq(absl::nullopt));
- });
- delegate->GetSavedPasswordsList(callback.Get());
-}
-
-TEST_F(PasswordsPrivateDelegateImplTest, ChangeSavedPasswordInBothStores) {
- password_manager::PasswordForm profile_form = CreateSampleForm();
- password_manager::PasswordForm account_form = profile_form;
- account_form.in_store = password_manager::PasswordForm::Store::kAccountStore;
- SetUpPasswordStores({profile_form, account_form});
-
- auto delegate = CreateDelegate();
- // Spin the loop to allow PasswordStore tasks posted on the creation of
- // |delegate| to be completed.
- base::RunLoop().RunUntilIdle();
-
- int profile_form_id = delegate->GetIdForCredential(
- password_manager::CredentialUIEntry(profile_form));
- int account_form_id = delegate->GetIdForCredential(
- password_manager::CredentialUIEntry(account_form));
-
- ASSERT_EQ(profile_form_id, account_form_id);
-
- api::passwords_private::ChangeSavedPasswordParams params;
- params.password = "new_pass";
- params.username = "new_user";
-
- profile_form.username_value = u"new_user";
- profile_form.password_value = u"new_pass";
- int new_profile_form_id = delegate->GetIdForCredential(
- password_manager::CredentialUIEntry(profile_form));
- account_form.username_value = u"new_user";
- account_form.password_value = u"new_pass";
- int new_account_form_id = delegate->GetIdForCredential(
- password_manager::CredentialUIEntry(account_form));
-
- ASSERT_EQ(new_profile_form_id, new_account_form_id);
-
- EXPECT_EQ(new_profile_form_id,
- delegate->ChangeSavedPassword(profile_form_id, params));
-}
-
-TEST_F(PasswordsPrivateDelegateImplTest, ChangeSavedPasswordInAccountStore) {
- password_manager::PasswordForm profile_form = CreateSampleForm();
- profile_form.password_value = u"different_pass";
- password_manager::PasswordForm account_form = CreateSampleForm();
- account_form.in_store = password_manager::PasswordForm::Store::kAccountStore;
- SetUpPasswordStores({profile_form, account_form});
-
- auto delegate = CreateDelegate();
- // Spin the loop to allow PasswordStore tasks posted on the creation of
- // |delegate| to be completed.
- base::RunLoop().RunUntilIdle();
-
- int account_form_id = delegate->GetIdForCredential(
- password_manager::CredentialUIEntry(account_form));
-
- api::passwords_private::ChangeSavedPasswordParams params;
- params.password = "new_pass";
- params.username = "new_user";
-
- account_form.username_value = u"new_user";
- account_form.password_value = u"new_pass";
- int new_account_form_id = delegate->GetIdForCredential(
- password_manager::CredentialUIEntry(account_form));
-
- auto result = delegate->ChangeSavedPassword(account_form_id, params);
- EXPECT_THAT(result, new_account_form_id);
-}
-
TEST_F(PasswordsPrivateDelegateImplTest, ChangeCredential_Password) {
- password_manager::PasswordForm sample_form = CreateSampleForm();
+ PasswordForm sample_form = CreateSampleForm();
SetUpPasswordStores({sample_form});
auto delegate = CreateDelegate();
// Spin the loop to allow PasswordStore tasks posted on the creation of
@@ -904,9 +826,9 @@ TEST_F(PasswordsPrivateDelegateImplTest, ChangeCredential_Password) {
TEST_F(PasswordsPrivateDelegateImplTest,
ChangeCredential_PasswordInBothStores) {
- password_manager::PasswordForm profile_form = CreateSampleForm();
- password_manager::PasswordForm account_form = profile_form;
- account_form.in_store = password_manager::PasswordForm::Store::kAccountStore;
+ PasswordForm profile_form = CreateSampleForm();
+ PasswordForm account_form = profile_form;
+ account_form.in_store = PasswordForm::Store::kAccountStore;
SetUpPasswordStores({profile_form, account_form});
auto delegate = CreateDelegate();
@@ -938,10 +860,10 @@ TEST_F(PasswordsPrivateDelegateImplTest,
TEST_F(PasswordsPrivateDelegateImplTest,
ChangeCredential_PasswordInAccountStore) {
- password_manager::PasswordForm profile_form = CreateSampleForm();
+ PasswordForm profile_form = CreateSampleForm();
profile_form.password_value = u"different_pass";
- password_manager::PasswordForm account_form = CreateSampleForm();
- account_form.in_store = password_manager::PasswordForm::Store::kAccountStore;
+ PasswordForm account_form = CreateSampleForm();
+ account_form.in_store = PasswordForm::Store::kAccountStore;
SetUpPasswordStores({profile_form, account_form});
auto delegate = CreateDelegate();
@@ -988,8 +910,7 @@ TEST_F(PasswordsPrivateDelegateImplTest,
TEST_F(PasswordsPrivateDelegateImplTest, ChangeCredential_Passkey) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
- {password_manager::features::kPasswordsGrouping,
- password_manager::features::kPasswordManagerPasskeys,
+ {password_manager::features::kPasswordManagerPasskeys,
syncer::kSyncWebauthnCredentials},
/*disabled_features=*/{});
@@ -1042,7 +963,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, ChangeCredential_NotFound) {
}
TEST_F(PasswordsPrivateDelegateImplTest, ChangeCredential_EmptyPassword) {
- password_manager::PasswordForm sample_form = CreateSampleForm();
+ PasswordForm sample_form = CreateSampleForm();
SetUpPasswordStores({sample_form});
auto delegate = CreateDelegate();
// Spin the loop to allow PasswordStore tasks posted on the creation of
@@ -1060,7 +981,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, ChangeCredential_EmptyPassword) {
// Checking callback result of RequestPlaintextPassword with reason Copy.
// By implementation for Copy, callback will receive empty string.
TEST_F(PasswordsPrivateDelegateImplTest, TestCopyPasswordCallbackResult) {
- password_manager::PasswordForm form = CreateSampleForm();
+ PasswordForm form = CreateSampleForm();
SetUpPasswordStores({form});
auto delegate = CreateDelegate();
@@ -1091,8 +1012,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, TestCopyPasswordCallbackResult) {
}
TEST_F(PasswordsPrivateDelegateImplTest, TestShouldReauthForOptIn) {
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
ON_CALL(*(client->GetPasswordFeatureManager()), IsOptedInForAccountStorage)
@@ -1108,8 +1028,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, TestShouldReauthForOptIn) {
TEST_F(PasswordsPrivateDelegateImplTest,
TestShouldNotReauthForOptOutAndShouldSetPref) {
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
password_manager::MockPasswordFeatureManager* feature_manager =
@@ -1188,7 +1107,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, TestPassedReauthOnView) {
TEST_F(PasswordsPrivateDelegateImplTest,
TestPassedReauthOnRequestCredentialsDetails) {
- password_manager::PasswordForm sample_form = CreateSampleForm();
+ PasswordForm sample_form = CreateSampleForm();
sample_form.notes.emplace_back(u"best note ever",
/*date_created=*/base::Time::Now());
SetUpPasswordStores({sample_form});
@@ -1347,8 +1266,7 @@ TEST_F(PasswordsPrivateDelegateImplTest,
}
TEST_F(PasswordsPrivateDelegateImplTest, IsAccountStoreDefault) {
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
ON_CALL(*(client->GetPasswordFeatureManager()), IsOptedInForAccountStorage)
@@ -1357,26 +1275,24 @@ TEST_F(PasswordsPrivateDelegateImplTest, IsAccountStoreDefault) {
auto delegate = CreateDelegate();
EXPECT_CALL(*(client->GetPasswordFeatureManager()), GetDefaultPasswordStore)
- .WillOnce(Return(password_manager::PasswordForm::Store::kAccountStore));
+ .WillOnce(Return(PasswordForm::Store::kAccountStore));
EXPECT_TRUE(delegate->IsAccountStoreDefault(web_contents.get()));
EXPECT_CALL(*(client->GetPasswordFeatureManager()), GetDefaultPasswordStore)
- .WillOnce(Return(password_manager::PasswordForm::Store::kProfileStore));
+ .WillOnce(Return(PasswordForm::Store::kProfileStore));
EXPECT_FALSE(delegate->IsAccountStoreDefault(web_contents.get()));
}
TEST_F(PasswordsPrivateDelegateImplTest, TestMovePasswordsToAccountStore) {
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
ON_CALL(*(client->GetPasswordFeatureManager()), IsOptedInForAccountStorage)
.WillByDefault(Return(true));
auto delegate = CreateDelegate();
- password_manager::PasswordForm form1 =
- CreateSampleForm(password_manager::PasswordForm::Store::kProfileStore);
- password_manager::PasswordForm form2 = form1;
+ PasswordForm form1 = CreateSampleForm(PasswordForm::Store::kProfileStore);
+ PasswordForm form2 = form1;
form2.username_value = u"different_username";
SetUpPasswordStores({form1, form2});
@@ -1396,28 +1312,6 @@ TEST_F(PasswordsPrivateDelegateImplTest, TestMovePasswordsToAccountStore) {
1);
}
-TEST_F(PasswordsPrivateDelegateImplTest, AndroidCredential) {
- auto delegate = CreateDelegate();
-
- password_manager::PasswordForm android_form;
- android_form.signon_realm = "android://hash@example.com";
- android_form.username_value = u"test@gmail.com";
- android_form.in_store = password_manager::PasswordForm::Store::kProfileStore;
- SetUpPasswordStores({android_form});
-
- base::MockCallback<PasswordsPrivateDelegate::UiEntriesCallback> callback;
-
- api::passwords_private::PasswordUiEntry expected_entry;
- expected_entry.urls.link =
- "https://play.google.com/store/apps/details?id=example.com";
- expected_entry.username = "test@gmail.com";
- expected_entry.is_android_credential = true;
- expected_entry.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
- EXPECT_CALL(callback, Run(testing::ElementsAre(PasswordUiEntryDataEquals(
- testing::ByRef(expected_entry)))));
- delegate->GetSavedPasswordsList(callback.Get());
-}
-
TEST_F(PasswordsPrivateDelegateImplTest, VerifyCastingOfImportEntryStatus) {
static_assert(
static_cast<int>(api::passwords_private::ImportEntryStatus::
@@ -1552,8 +1446,7 @@ TEST_F(PasswordsPrivateDelegateImplTest,
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
password_manager::features::kBiometricAuthenticationForFilling);
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
client->SetDeviceAuthenticator(biometric_authenticator_);
@@ -1574,8 +1467,7 @@ TEST_F(PasswordsPrivateDelegateImplTest,
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
password_manager::features::kBiometricAuthenticationForFilling);
- std::unique_ptr<content::WebContents> web_contents =
- content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+ std::unique_ptr<content::WebContents> web_contents = CreateWebContents();
auto* client =
MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
client->SetDeviceAuthenticator(biometric_authenticator_);
@@ -1641,16 +1533,12 @@ TEST_F(PasswordsPrivateDelegateImplTest, DISABLED_ShowAddShortcutDialog) {
}
TEST_F(PasswordsPrivateDelegateImplTest, GetCredentialGroups) {
- base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
- password_manager::features::kPasswordsGrouping);
-
auto delegate = CreateDelegate();
- password_manager::PasswordForm password1 = CreateSampleForm(
- password_manager::PasswordForm::Store::kProfileStore, u"username1");
- password_manager::PasswordForm password2 = CreateSampleForm(
- password_manager::PasswordForm::Store::kProfileStore, u"username2");
+ PasswordForm password1 =
+ CreateSampleForm(PasswordForm::Store::kProfileStore, u"username1");
+ PasswordForm password2 =
+ CreateSampleForm(PasswordForm::Store::kProfileStore, u"username2");
SetUpPasswordStores({password1, password2});
@@ -1661,11 +1549,13 @@ TEST_F(PasswordsPrivateDelegateImplTest, GetCredentialGroups) {
EXPECT_EQ("https://abc1.com/favicon.ico", groups[0].icon_url);
api::passwords_private::PasswordUiEntry expected_entry1;
- expected_entry1.urls.link = "https://abc1.com/";
+ expected_entry1.affiliated_domains.emplace_back();
+ expected_entry1.affiliated_domains.back().signon_realm = "https://abc1.com";
expected_entry1.username = "username1";
expected_entry1.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
api::passwords_private::PasswordUiEntry expected_entry2;
- expected_entry2.urls.link = "https://abc1.com/";
+ expected_entry2.affiliated_domains.emplace_back();
+ expected_entry2.affiliated_domains.back().signon_realm = "https://abc1.com";
expected_entry2.username = "username2";
expected_entry2.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
EXPECT_THAT(groups[0].entries,
@@ -1693,8 +1583,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, PasswordManagerAppInstalled) {
TEST_F(PasswordsPrivateDelegateImplTest, GetPasskeyInGroups) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
- {password_manager::features::kPasswordsGrouping,
- password_manager::features::kPasswordManagerPasskeys,
+ {password_manager::features::kPasswordManagerPasskeys,
syncer::kSyncWebauthnCredentials},
/*disabled_features=*/{});
@@ -1707,8 +1596,8 @@ TEST_F(PasswordsPrivateDelegateImplTest, GetPasskeyInGroups) {
sync_pb::WebauthnCredentialSpecifics passkey = CreatePasskey();
passkey_model->AddNewPasskeyForTesting(passkey);
- password_manager::PasswordForm password = CreateSampleForm(
- password_manager::PasswordForm::Store::kProfileStore, u"username1");
+ PasswordForm password =
+ CreateSampleForm(PasswordForm::Store::kProfileStore, u"username1");
SetUpPasswordStores({password});
auto groups = delegate->GetCredentialGroups();
@@ -1718,12 +1607,14 @@ TEST_F(PasswordsPrivateDelegateImplTest, GetPasskeyInGroups) {
EXPECT_EQ("https://abc1.com/favicon.ico", groups[0].icon_url);
api::passwords_private::PasswordUiEntry expected_entry1;
- expected_entry1.urls.link = "https://abc1.com/";
+ expected_entry1.affiliated_domains.emplace_back();
+ expected_entry1.affiliated_domains.back().signon_realm = "https://abc1.com";
expected_entry1.username = "username1";
expected_entry1.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
api::passwords_private::PasswordUiEntry expected_entry2;
expected_entry2.is_passkey = true;
- expected_entry2.urls.link = "https://abc1.com/";
+ expected_entry2.affiliated_domains.emplace_back();
+ expected_entry2.affiliated_domains.back().signon_realm = "https://abc1.com";
expected_entry2.username = passkey.user_name();
expected_entry2.display_name = passkey.user_display_name();
expected_entry2.stored_in =
@@ -1738,8 +1629,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, RemovePasskey) {
base::UserActionTester user_action_tester;
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
- {password_manager::features::kPasswordsGrouping,
- password_manager::features::kPasswordManagerPasskeys,
+ {password_manager::features::kPasswordManagerPasskeys,
syncer::kSyncWebauthnCredentials},
/*disabled_features=*/{});
@@ -1774,4 +1664,352 @@ TEST_F(PasswordsPrivateDelegateImplTest, RemovePasskey) {
1);
}
+TEST_F(PasswordsPrivateDelegateImplTest, SharePasswordWithTwoRecipients) {
+ auto delegate = CreateDelegate();
+ PasswordForm password = CreateSampleForm();
+ SetUpPasswordStores({password});
+
+ PasswordsPrivateDelegate::ShareRecipients recipients;
+ api::passwords_private::RecipientInfo recipient1;
+ api::passwords_private::PublicKey public_key1;
+ public_key1.value = kSharingRecipientKeyValue1;
+ recipient1.public_key = std::move(public_key1);
+ recipient1.user_id = kSharingRecipientId1;
+ recipient1.display_name = kSharingRecipientDisplayName1;
+ recipient1.email = kSharingRecipientEmail1;
+ recipient1.profile_image_url = kSharingRecipientProfileImageUrl1;
+ recipients.push_back(std::move(recipient1));
+
+ api::passwords_private::RecipientInfo recipient2;
+ api::passwords_private::PublicKey public_key2;
+ public_key2.value = kSharingRecipientKeyValue2;
+ recipient2.public_key = std::move(public_key2);
+ recipient2.user_id = kSharingRecipientId2;
+ recipient2.display_name = kSharingRecipientDisplayName2;
+ recipient2.email = kSharingRecipientEmail2;
+ recipient2.profile_image_url = kSharingRecipientProfileImageUrl2;
+ recipients.push_back(std::move(recipient2));
+
+ password_manager::MockPasswordSenderService* password_sender_service =
+ static_cast<password_manager::MockPasswordSenderService*>(
+ PasswordSenderServiceFactory::GetForProfile(profile()));
+
+ password_manager::PublicKey expected_public_key1, expected_public_key2;
+ expected_public_key1.key = kSharingRecipientKeyValue1;
+ expected_public_key2.key = kSharingRecipientKeyValue2;
+ // There are two recipients and hence, SendPasswords() should be called twice
+ // with the same credentials for each recipient.
+ EXPECT_CALL(
+ *password_sender_service,
+ SendPasswords(
+ ElementsAre(AllOf(
+ Field(&PasswordForm::username_value, password.username_value),
+ Field(&PasswordForm::password_value, password.password_value),
+ Field(&PasswordForm::signon_realm, password.signon_realm))),
+ AllOf(Field("user id", &PasswordRecipient::user_id,
+ kSharingRecipientId1),
+ Field("public key", &PasswordRecipient::public_key,
+ expected_public_key1))));
+ EXPECT_CALL(
+ *password_sender_service,
+ SendPasswords(
+ ElementsAre(AllOf(
+ Field(&PasswordForm::username_value, password.username_value),
+ Field(&PasswordForm::password_value, password.password_value),
+ Field(&PasswordForm::signon_realm, password.signon_realm))),
+ AllOf(Field("user id", &PasswordRecipient::user_id,
+ kSharingRecipientId2),
+ Field("public key", &PasswordRecipient::public_key,
+ expected_public_key2)))
+
+ );
+
+ delegate->SharePassword(/*id=*/0, recipients);
+}
+
+TEST_F(PasswordsPrivateDelegateImplTest,
+ ShareAllPasswordsRepresentedByUiEntry) {
+ auto delegate = CreateDelegate();
+ // `password1` and `password2` share the same username and password and their
+ // origins are PSL matches. They should be represented by the same ui entry.
+ // `password3` has a different username and hence is represented by a
+ // different ui entry.
+ PasswordForm password1 =
+ CreateSampleForm(PasswordForm::Store::kProfileStore, u"username1");
+ password1.signon_realm = "https://facebook.com";
+ password1.url = GURL("https://facebook.com");
+
+ PasswordForm password2 = password1;
+ password2.signon_realm = "https://m.facebook.com";
+ password2.url = GURL("https://m.facebook.com");
+
+ PasswordForm password3 =
+ CreateSampleForm(PasswordForm::Store::kProfileStore, u"username3");
+
+ SetUpPasswordStores({password1, password2, password3});
+
+ // Credentials should have been grouped in two groups.
+ PasswordsPrivateDelegate::CredentialsGroups groups =
+ delegate->GetCredentialGroups();
+ ASSERT_EQ(groups.size(), 2U);
+ // Find the id of the ui entry that represents both facebook.com and
+ // m.facebook.com
+ int id_with_two_affiliated_domains = -1;
+ for (const api::passwords_private::CredentialGroup& group : groups) {
+ for (const api::passwords_private::PasswordUiEntry& entry : group.entries) {
+ if (entry.affiliated_domains.size() == 2) {
+ id_with_two_affiliated_domains = entry.id;
+ break;
+ }
+ }
+ }
+ ASSERT_NE(-1, id_with_two_affiliated_domains);
+
+ PasswordsPrivateDelegate::ShareRecipients recipients;
+ api::passwords_private::RecipientInfo recipient;
+ api::passwords_private::PublicKey public_key;
+ public_key.value = kSharingRecipientKeyValue1;
+ recipient.public_key = std::move(public_key);
+ recipient.user_id = kSharingRecipientId1;
+ recipient.display_name = kSharingRecipientDisplayName1;
+ recipient.email = kSharingRecipientEmail1;
+ recipient.profile_image_url = kSharingRecipientProfileImageUrl1;
+ recipients.push_back(std::move(recipient));
+
+ password_manager::MockPasswordSenderService* password_sender_service =
+ static_cast<password_manager::MockPasswordSenderService*>(
+ PasswordSenderServiceFactory::GetForProfile(profile()));
+
+ password_manager::PublicKey expected_public_key;
+ expected_public_key.key = kSharingRecipientKeyValue1;
+ // There is one recipient and hence, SendPasswords() should be called only
+ // once with the two credentials represented by this ui entry.
+ EXPECT_CALL(
+ *password_sender_service,
+ SendPasswords(
+ UnorderedElementsAre(
+ Field(&PasswordForm::signon_realm, "https://facebook.com"),
+ Field(&PasswordForm::signon_realm, "https://m.facebook.com")),
+ AllOf(Field("user id", &PasswordRecipient::user_id,
+ kSharingRecipientId1),
+ Field("public key", &PasswordRecipient::public_key,
+ expected_public_key))))
+ .Times(1);
+
+ delegate->SharePassword(/*id=*/id_with_two_affiliated_domains, recipients);
+}
+
+TEST_F(PasswordsPrivateDelegateImplTest, ShareNonExistentPassword) {
+ auto delegate = CreateDelegate();
+
+ PasswordsPrivateDelegate::ShareRecipients recipients;
+ api::passwords_private::RecipientInfo recipient;
+ recipient.user_id = kSharingRecipientId1;
+ recipients.push_back(std::move(recipient));
+
+ password_manager::MockPasswordSenderService* password_sender_service =
+ static_cast<password_manager::MockPasswordSenderService*>(
+ PasswordSenderServiceFactory::GetForProfile(profile()));
+ EXPECT_CALL(*password_sender_service, SendPasswords).Times(0);
+
+ delegate->SharePassword(/*id=*/100, recipients);
+}
+
+class PasswordsPrivateDelegateImplFetchFamilyMembersTest
+ : public PasswordsPrivateDelegateImplTest {
+ public:
+ PasswordsPrivateDelegateImplFetchFamilyMembersTest() = default;
+
+ void SetUp() override {
+ PasswordsPrivateDelegateImplTest::SetUp();
+ delegate_ = CreateDelegate();
+ delegate_->SetRecipientsFetcherForTesting(
+ std::make_unique<password_manager::RecipientsFetcherImpl>(
+ version_info::Channel::DEFAULT,
+ profile_url_loader_factory().GetSafeWeakWrapper(),
+ identity_test_env_.identity_manager()));
+ identity_test_env_.MakePrimaryAccountAvailable("test@email.com",
+ signin::ConsentLevel::kSync);
+ identity_test_env_.SetAutomaticIssueOfAccessTokens(true);
+ }
+
+ void TearDown() override {
+ delegate_ = nullptr;
+ PasswordsPrivateDelegateImplTest::TearDown();
+ }
+
+ protected:
+ const std::string kTestUserId = "12345";
+ const std::string kTestUserName = "Theo Tester";
+ const std::string kTestEmail = "theo@example.com";
+ const std::string kTestProfileImageUrl =
+ "https://3837fjsdjaka.image.example.com";
+ const std::string kTestPublicKeyBase64 =
+ "MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MTI=";
+ const uint32_t kTestPublicKeyVersion = 42;
+
+ void SetServerResponse(sync_pb::PasswordSharingRecipientsResponse::
+ PasswordSharingRecipientsResult result,
+ net::HttpStatusCode status = net::HTTP_OK,
+ bool recipient_has_public_key = false) {
+ sync_pb::PasswordSharingRecipientsResponse response;
+ response.set_result(result);
+ if (result == sync_pb::PasswordSharingRecipientsResponse::SUCCESS) {
+ sync_pb::UserInfo* user_info = response.add_recipients();
+ user_info->set_user_id(kTestUserId);
+ user_info->mutable_user_display_info()->set_display_name(kTestUserName);
+ user_info->mutable_user_display_info()->set_email(kTestEmail);
+ user_info->mutable_user_display_info()->set_profile_image_url(
+ kTestProfileImageUrl);
+ if (recipient_has_public_key) {
+ const password_manager::PublicKey kTestPublicKey = {
+ kTestPublicKeyBase64, kTestPublicKeyVersion};
+ user_info->mutable_cross_user_sharing_public_key()->CopyFrom(
+ kTestPublicKey.ToProto());
+ }
+ }
+ profile_url_loader_factory().AddResponse(
+ password_manager::PasswordSharingRecipientsDownloader::
+ GetPasswordSharingRecipientsURL(version_info::Channel::DEFAULT)
+ .spec(),
+ response.SerializeAsString(), status);
+ }
+
+ PasswordsPrivateDelegateImpl* delegate() { return delegate_.get(); }
+
+ private:
+ signin::IdentityTestEnvironment identity_test_env_;
+ scoped_refptr<PasswordsPrivateDelegateImpl> delegate_;
+};
+
+TEST_F(PasswordsPrivateDelegateImplFetchFamilyMembersTest,
+ FetchFamilyMembersSucceedsWithoutPublicKey) {
+ SetServerResponse(sync_pb::PasswordSharingRecipientsResponse::SUCCESS);
+
+ base::MockCallback<PasswordsPrivateDelegate::FetchFamilyResultsCallback>
+ callback;
+ EXPECT_CALL(
+ callback,
+ Run(AllOf(Field(&FamilyFetchResults::status,
+ api::passwords_private::FAMILY_FETCH_STATUS_SUCCESS),
+ Field(&FamilyFetchResults::family_members,
+ ElementsAre(AllOf(
+ Field(&RecipientInfo::user_id, kTestUserId),
+ Field(&RecipientInfo::display_name, kTestUserName),
+ Field(&RecipientInfo::email, kTestEmail),
+ Field(&RecipientInfo::is_eligible, false),
+ Field(&RecipientInfo::public_key, Eq(absl::nullopt)),
+ Field(&RecipientInfo::profile_image_url,
+ kTestProfileImageUrl)))))));
+
+ delegate()->FetchFamilyMembers(callback.Get());
+ task_environment()->RunUntilIdle();
+}
+
+TEST_F(PasswordsPrivateDelegateImplFetchFamilyMembersTest,
+ FetchFamilyMembersSucceedsWithPublicKey) {
+ SetServerResponse(sync_pb::PasswordSharingRecipientsResponse::SUCCESS,
+ net::HTTP_OK, /*recipient_has_public_key=*/true);
+
+ base::MockCallback<PasswordsPrivateDelegate::FetchFamilyResultsCallback>
+ callback;
+ EXPECT_CALL(
+ callback,
+ Run(AllOf(
+ Field(&FamilyFetchResults::status,
+ api::passwords_private::FAMILY_FETCH_STATUS_SUCCESS),
+ Field(&FamilyFetchResults::family_members,
+ ElementsAre(AllOf(
+ Field(&RecipientInfo::user_id, kTestUserId),
+ Field(&RecipientInfo::display_name, kTestUserName),
+ Field(&RecipientInfo::email, kTestEmail),
+ Field(&RecipientInfo::is_eligible, true),
+ Field(&RecipientInfo::public_key,
+ Optional(AllOf(
+ Field(&api::passwords_private::PublicKey::value,
+ kTestPublicKeyBase64),
+ Field(&api::passwords_private::PublicKey::version,
+ kTestPublicKeyVersion)))),
+ Field(&RecipientInfo::profile_image_url,
+ kTestProfileImageUrl)))))));
+
+ delegate()->FetchFamilyMembers(callback.Get());
+ task_environment()->RunUntilIdle();
+}
+
+TEST_F(PasswordsPrivateDelegateImplFetchFamilyMembersTest,
+ FetchFamilyMembersFailsWithUnknownError) {
+ SetServerResponse(sync_pb::PasswordSharingRecipientsResponse::UNKNOWN);
+
+ base::MockCallback<PasswordsPrivateDelegate::FetchFamilyResultsCallback>
+ callback;
+ EXPECT_CALL(
+ callback,
+ Run(AllOf(
+ Field(&FamilyFetchResults::status,
+ api::passwords_private::FAMILY_FETCH_STATUS_UNKNOWN_ERROR),
+ Field(&FamilyFetchResults::family_members, IsEmpty()))));
+
+ delegate()->FetchFamilyMembers(callback.Get());
+ task_environment()->RunUntilIdle();
+}
+
+TEST_F(PasswordsPrivateDelegateImplFetchFamilyMembersTest,
+ FetchFamilyMembersFailsWithNoFamilyMembersError) {
+ SetServerResponse(
+ sync_pb::PasswordSharingRecipientsResponse::NOT_FAMILY_MEMBER);
+
+ base::MockCallback<PasswordsPrivateDelegate::FetchFamilyResultsCallback>
+ callback;
+ EXPECT_CALL(
+ callback,
+ Run(AllOf(Field(&FamilyFetchResults::status,
+ api::passwords_private::FAMILY_FETCH_STATUS_NO_MEMBERS),
+ Field(&FamilyFetchResults::family_members, IsEmpty()))));
+
+ delegate()->FetchFamilyMembers(callback.Get());
+ task_environment()->RunUntilIdle();
+}
+
+TEST_F(PasswordsPrivateDelegateImplFetchFamilyMembersTest,
+ FetchFamilyMembersFailsWithAnotherRequestInFlight) {
+ base::MockCallback<PasswordsPrivateDelegate::FetchFamilyResultsCallback>
+ callback1;
+ delegate()->FetchFamilyMembers(callback1.Get());
+
+ base::MockCallback<PasswordsPrivateDelegate::FetchFamilyResultsCallback>
+ callback2;
+ EXPECT_CALL(
+ callback2,
+ Run(AllOf(
+ Field(&FamilyFetchResults::status,
+ api::passwords_private::FAMILY_FETCH_STATUS_UNKNOWN_ERROR),
+ Field(&FamilyFetchResults::family_members, IsEmpty()))));
+ delegate()->FetchFamilyMembers(callback2.Get());
+
+ task_environment()->RunUntilIdle();
+}
+
+TEST_F(PasswordsPrivateDelegateImplFetchFamilyMembersTest,
+ FetchFamilyMembersFailsWithNetworkError) {
+ profile_url_loader_factory().AddResponse(
+ password_manager::PasswordSharingRecipientsDownloader::
+ GetPasswordSharingRecipientsURL(version_info::Channel::DEFAULT)
+ .spec(),
+ /*content=*/std::string(), net::HTTP_INTERNAL_SERVER_ERROR);
+
+ base::MockCallback<PasswordsPrivateDelegate::FetchFamilyResultsCallback>
+ callback;
+ FamilyFetchResults family_fetch_results;
+ EXPECT_CALL(
+ callback,
+ Run(AllOf(
+ Field(&FamilyFetchResults::status,
+ api::passwords_private::FAMILY_FETCH_STATUS_UNKNOWN_ERROR),
+ Field(&FamilyFetchResults::family_members, IsEmpty()))));
+
+ delegate()->FetchFamilyMembers(callback.Get());
+ task_environment()->RunUntilIdle();
+}
+
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils.h b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils.h
index e5dd4d1906a..c6914c2d038 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils.h
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils.h
@@ -7,7 +7,6 @@
#include <functional>
#include <string>
-#include <unordered_map>
#include "base/containers/flat_map.h"
#include "chrome/common/extensions/api/passwords_private.h"
@@ -67,10 +66,9 @@ class IdGenerator {
private:
// Maps credential key to id.
- std::unordered_map<std::string, int> key_to_id_;
+ base::flat_map<std::string, int> key_to_id_;
// Maps id to the credential.
- std::unordered_map<int, password_manager::CredentialUIEntry>
- id_to_credential_;
+ base::flat_map<int, password_manager::CredentialUIEntry> id_to_credential_;
int next_id_ = 0;
};
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils_chromeos.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils_chromeos.cc
index 4f0a24376f8..5e23d6b4fea 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils_chromeos.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils_chromeos.cc
@@ -28,7 +28,8 @@ bool IsOsReauthAllowedAsh(Profile* profile,
ash::ProfileHelper::Get()->GetUserByProfile(profile)->GetAccountId());
if (user_cannot_manually_enter_password)
return true;
-
+ // TODO (b/238606050): This code branch does not seem to be used now.
+ // Clean up the code, or add token as a parameter to this method.
ash::quick_unlock::QuickUnlockStorage* quick_unlock_storage =
ash::quick_unlock::QuickUnlockFactory::GetForProfile(profile);
const ash::quick_unlock::AuthToken* auth_token =
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc b/chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc
index 5921a127e35..3963eba8ef7 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc
@@ -26,9 +26,13 @@ constexpr size_t kNumMocks = 3;
api::passwords_private::PasswordUiEntry CreateEntry(int id) {
api::passwords_private::PasswordUiEntry entry;
- entry.urls.shown = "test" + base::NumberToString(id) + ".com";
- entry.urls.signon_realm = "http://" + entry.urls.shown + "/login";
- entry.urls.link = entry.urls.signon_realm;
+ entry.affiliated_domains.emplace_back();
+ entry.affiliated_domains.back().name =
+ "test" + base::NumberToString(id) + ".com";
+ entry.affiliated_domains.back().signon_realm =
+ "http://" + entry.affiliated_domains.back().name + "/login";
+ entry.affiliated_domains.back().url =
+ entry.affiliated_domains.back().signon_realm;
entry.username = "testName" + base::NumberToString(id);
entry.id = id;
entry.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
@@ -105,19 +109,6 @@ bool TestPasswordsPrivateDelegate::AddPassword(
return !url.empty() && !password.empty();
}
-absl::optional<int> TestPasswordsPrivateDelegate::ChangeSavedPassword(
- const int id,
- const api::passwords_private::ChangeSavedPasswordParams& params) {
- if (static_cast<size_t>(id) >= current_entries_.size()) {
- return absl::nullopt;
- }
-
- if (params.password.empty())
- return absl::nullopt;
-
- return id;
-}
-
bool TestPasswordsPrivateDelegate::ChangeCredential(
const api::passwords_private::PasswordUiEntry& credential) {
const auto existing = std::ranges::find_if(
@@ -233,6 +224,21 @@ void TestPasswordsPrivateDelegate::ContinueImport(
std::move(results_callback).Run(import_results_);
}
+void TestPasswordsPrivateDelegate::FetchFamilyMembers(
+ FetchFamilyResultsCallback callback) {
+ fetch_family_members_triggered_ = true;
+
+ family_fetch_results_.status =
+ api::passwords_private::FamilyFetchStatus::FAMILY_FETCH_STATUS_SUCCESS;
+ std::move(callback).Run(family_fetch_results_);
+}
+
+void TestPasswordsPrivateDelegate::SharePassword(
+ int id,
+ const ShareRecipients& recipients) {
+ share_password_triggered_ = true;
+}
+
void TestPasswordsPrivateDelegate::ResetImporter(bool delete_file) {
reset_importer_triggered_ = true;
}
@@ -246,10 +252,6 @@ void TestPasswordsPrivateDelegate::ExportPasswords(
std::move(callback).Run(std::string());
}
-void TestPasswordsPrivateDelegate::CancelExportPasswords() {
- cancel_export_passwords_triggered_ = true;
-}
-
api::passwords_private::ExportProgressStatus
TestPasswordsPrivateDelegate::GetExportProgressStatus() {
// The testing of password exporting itself should be handled via
@@ -272,10 +274,11 @@ std::vector<api::passwords_private::PasswordUiEntry>
TestPasswordsPrivateDelegate::GetInsecureCredentials() {
api::passwords_private::PasswordUiEntry leaked_credential;
leaked_credential.username = "alice";
- leaked_credential.urls.shown = "example.com";
- leaked_credential.urls.link = "https://example.com";
- leaked_credential.urls.signon_realm = "https://example.com";
- leaked_credential.is_android_credential = false;
+ leaked_credential.affiliated_domains.emplace_back();
+ leaked_credential.affiliated_domains.back().name = "example.com";
+ leaked_credential.affiliated_domains.back().url = "https://example.com";
+ leaked_credential.affiliated_domains.back().signon_realm =
+ "https://example.com";
leaked_credential.change_password_url = "https://example.com/change-password";
leaked_credential.compromised_info.emplace();
// Mar 03 2020 12:00:00 UTC
@@ -290,9 +293,9 @@ TestPasswordsPrivateDelegate::GetInsecureCredentials() {
api::passwords_private::PasswordUiEntry weak_credential;
weak_credential.username = "bob";
- weak_credential.urls.shown = "example.com";
- weak_credential.urls.link = "https://example.com";
- weak_credential.is_android_credential = false;
+ weak_credential.affiliated_domains.emplace_back();
+ weak_credential.affiliated_domains.back().name = "example.com";
+ weak_credential.affiliated_domains.back().url = "https://example.com";
weak_credential.change_password_url = "https://example.com/change-password";
weak_credential.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
weak_credential.compromised_info.emplace();
@@ -311,9 +314,9 @@ TestPasswordsPrivateDelegate::GetCredentialsWithReusedPassword() {
api::passwords_private::PasswordUiEntry credential_1;
credential_1.username = "bob";
- credential_1.urls.shown = "example.com";
- credential_1.urls.link = "https://example.com";
- credential_1.is_android_credential = false;
+ credential_1.affiliated_domains.emplace_back();
+ credential_1.affiliated_domains.back().name = "example.com";
+ credential_1.affiliated_domains.back().url = "https://example.com";
credential_1.change_password_url = "https://example.com/change-password";
credential_1.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
credential_1.compromised_info.emplace();
@@ -322,9 +325,9 @@ TestPasswordsPrivateDelegate::GetCredentialsWithReusedPassword() {
api::passwords_private::PasswordUiEntry credential_2;
credential_2.username = "angela";
- credential_2.urls.shown = "test.com";
- credential_2.urls.link = "https://test.com";
- credential_2.is_android_credential = false;
+ credential_2.affiliated_domains.emplace_back();
+ credential_2.affiliated_domains.back().name = "test.com";
+ credential_2.affiliated_domains.back().url = "https://test.com";
credential_2.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
credential_2.compromised_info.emplace();
credential_2.compromised_info->compromise_types = {
@@ -351,22 +354,12 @@ bool TestPasswordsPrivateDelegate::UnmuteInsecureCredential(
return IsCredentialPresentInInsecureCredentialsList(credential);
}
-void TestPasswordsPrivateDelegate::RecordChangePasswordFlowStarted(
- const api::passwords_private::PasswordUiEntry& credential) {
- last_change_flow_url_ =
- credential.change_password_url ? *credential.change_password_url : "";
-}
-
void TestPasswordsPrivateDelegate::StartPasswordCheck(
StartPasswordCheckCallback callback) {
start_password_check_triggered_ = true;
std::move(callback).Run(start_password_check_state_);
}
-void TestPasswordsPrivateDelegate::StopPasswordCheck() {
- stop_password_check_triggered_ = true;
-}
-
api::passwords_private::PasswordCheckStatus
TestPasswordsPrivateDelegate::GetPasswordCheckStatus() {
api::passwords_private::PasswordCheckStatus status;
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h b/chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h
index b2061d34e50..25c39a8de01 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h
+++ b/chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h
@@ -40,11 +40,6 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
const std::u16string& note,
bool use_account_store,
content::WebContents* web_contents) override;
- // Fake implementation of ChangeSavedPassword. This succeeds if the current
- // list of entries has the id and if the new password isn't empty.
- absl::optional<int> ChangeSavedPassword(
- const int id,
- const api::passwords_private::ChangeSavedPasswordParams& params) override;
bool ChangeCredential(
const api::passwords_private::PasswordUiEntry& credential) override;
void RemoveCredential(
@@ -62,6 +57,8 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
content::WebContents* web_contents) override;
void MovePasswordsToAccount(const std::vector<int>& ids,
content::WebContents* web_contents) override;
+ void FetchFamilyMembers(FetchFamilyResultsCallback callback) override;
+ void SharePassword(int id, const ShareRecipients& recipients) override;
void ImportPasswords(api::passwords_private::PasswordStoreSet to_store,
ImportResultsCallback results_callback,
content::WebContents* web_contents) override;
@@ -71,7 +68,6 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
void ResetImporter(bool delete_file) override;
void ExportPasswords(base::OnceCallback<void(const std::string&)> callback,
content::WebContents* web_contents) override;
- void CancelExportPasswords() override;
api::passwords_private::ExportProgressStatus GetExportProgressStatus()
override;
bool IsOptedInForAccountStorage() override;
@@ -89,12 +85,7 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
// delegate knows of a insecure credential with the same id.
bool UnmuteInsecureCredential(
const api::passwords_private::PasswordUiEntry& credential) override;
- // Fake implementation of `RecordChangePasswordFlowStarted`. Sets the url
- // returned by `last_change_flow_url()`.
- void RecordChangePasswordFlowStarted(
- const api::passwords_private::PasswordUiEntry& credential) override;
void StartPasswordCheck(StartPasswordCheckCallback callback) override;
- void StopPasswordCheck() override;
api::passwords_private::PasswordCheckStatus GetPasswordCheckStatus() override;
password_manager::InsecureCredentialsManager* GetInsecureCredentialsManager()
override;
@@ -116,22 +107,18 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
bool ContinueImportTriggered() const { return continue_import_triggered_; }
bool ResetImporterTriggered() const { return reset_importer_triggered_; }
bool ExportPasswordsTriggered() const { return export_passwords_triggered_; }
- bool CancelExportPasswordsTriggered() const {
- return cancel_export_passwords_triggered_;
+ bool FetchFamilyMembersTriggered() const {
+ return fetch_family_members_triggered_;
}
+ bool SharePasswordTriggered() const { return share_password_triggered_; }
bool StartPasswordCheckTriggered() const {
return start_password_check_triggered_;
}
- bool StopPasswordCheckTriggered() const {
- return stop_password_check_triggered_;
- }
void SetStartPasswordCheckState(
password_manager::BulkLeakCheckService::State state) {
start_password_check_state_ = state;
}
- const std::string& last_change_flow_url() { return last_change_flow_url_; }
-
const std::vector<int>& last_moved_passwords() const {
return last_moved_passwords_;
}
@@ -173,6 +160,8 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
api::passwords_private::ImportResults import_results_;
+ api::passwords_private::FamilyFetchResults family_fetch_results_;
+
// List of insecure credentials.
std::vector<api::passwords_private::PasswordUiEntry> insecure_credentials_;
raw_ptr<Profile, DanglingUntriaged> profile_ = nullptr;
@@ -180,23 +169,21 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
bool is_opted_in_for_account_storage_ = false;
bool is_account_store_default_ = false;
+ // Flags for detecting whether password sharing operations have been invoked.
+ bool fetch_family_members_triggered_ = false;
+ bool share_password_triggered_ = false;
+
// Flags for detecting whether import/export operations have been invoked.
bool import_passwords_triggered_ = false;
bool continue_import_triggered_ = false;
bool reset_importer_triggered_ = false;
bool export_passwords_triggered_ = false;
- bool cancel_export_passwords_triggered_ = false;
// Flags for detecting whether password check operations have been invoked.
bool start_password_check_triggered_ = false;
- bool stop_password_check_triggered_ = false;
password_manager::BulkLeakCheckService::State start_password_check_state_ =
password_manager::BulkLeakCheckService::State::kRunning;
- // Url of the last reported change password flow. Defaults to empty if
- // none has been registered.
- std::string last_change_flow_url_;
-
// Records the ids of the passwords that were last moved.
std::vector<int> last_moved_passwords_;
diff --git a/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.cc b/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.cc
index fa93ed64865..4d5278e8c53 100644
--- a/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.cc
+++ b/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.cc
@@ -12,11 +12,11 @@
namespace extensions {
// static
-PdfViewerPrivateEventRouter* PdfViewerPrivateEventRouter::Create(
- content::BrowserContext* context) {
+std::unique_ptr<PdfViewerPrivateEventRouter>
+PdfViewerPrivateEventRouter::Create(content::BrowserContext* context) {
DCHECK(context);
Profile* profile = Profile::FromBrowserContext(context);
- return new PdfViewerPrivateEventRouter(profile);
+ return std::make_unique<PdfViewerPrivateEventRouter>(profile);
}
PdfViewerPrivateEventRouter::PdfViewerPrivateEventRouter(Profile* profile)
diff --git a/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.h b/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.h
index 4035fac9170..1d4ffd7cf2f 100644
--- a/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.h
+++ b/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router.h
@@ -20,7 +20,8 @@ namespace extensions {
class PdfViewerPrivateEventRouter : public KeyedService,
public EventRouter::Observer {
public:
- static PdfViewerPrivateEventRouter* Create(content::BrowserContext* context);
+ static std::unique_ptr<PdfViewerPrivateEventRouter> Create(
+ content::BrowserContext* context);
explicit PdfViewerPrivateEventRouter(Profile* profile);
diff --git a/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.cc b/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.cc
index 77bb8787bb8..3a1c61b2763 100644
--- a/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.cc
+++ b/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.cc
@@ -42,7 +42,8 @@ PdfViewerPrivateEventRouterFactory::PdfViewerPrivateEventRouterFactory()
PdfViewerPrivateEventRouterFactory::~PdfViewerPrivateEventRouterFactory() =
default;
-KeyedService* PdfViewerPrivateEventRouterFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+PdfViewerPrivateEventRouterFactory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const {
return PdfViewerPrivateEventRouter::Create(context);
}
diff --git a/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.h b/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.h
index 97612812ac9..5cb6e8c7731 100644
--- a/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.h
+++ b/chromium/chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_event_router_factory.h
@@ -42,7 +42,7 @@ class PdfViewerPrivateEventRouterFactory : public ProfileKeyedServiceFactory {
~PdfViewerPrivateEventRouterFactory() override;
// BrowserContextKeyedServiceFactory:
- KeyedService* BuildServiceInstanceFor(
+ std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
content::BrowserContext* profile) const override;
};
diff --git a/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc b/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc
index 7e45a793576..4eb304afe20 100644
--- a/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc
+++ b/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc
@@ -21,6 +21,7 @@
#include "chromeos/crosapi/mojom/keystore_error.mojom-shared.h"
#include "chromeos/crosapi/mojom/keystore_service.mojom.h"
#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "net/base/net_errors.h"
#include "net/cert/asn1_util.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/x509_util.h"
diff --git a/chromium/chrome/browser/extensions/api/preference/preference_api.cc b/chromium/chrome/browser/extensions/api/preference/preference_api.cc
index 8f74c295315..aaf07e4ced3 100644
--- a/chromium/chrome/browser/extensions/api/preference/preference_api.cc
+++ b/chromium/chrome/browser/extensions/api/preference/preference_api.cc
@@ -41,6 +41,7 @@
#include "extensions/browser/extension_system_provider.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/pref_names.h"
+#include "extensions/common/api/types.h"
#include "extensions/common/constants.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension_id.h"
@@ -61,6 +62,8 @@ namespace extensions {
namespace {
+using extensions::api::types::ChromeSettingScope;
+
constexpr char kConversionErrorMessage[] =
"Internal error: Stored value for preference '*' cannot be converted "
"properly.";
@@ -79,6 +82,37 @@ constexpr char kIncognitoSpecific[] = "incognitoSpecific";
constexpr char kLevelOfControl[] = "levelOfControl";
constexpr char kValue[] = "value";
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// Returns true if the get, set or clear requests for the preference associated
+// with `pref_path` should only be applied at browser level. Returns false if
+// the requests should be forwarded to Ash.
+// All preferences explicitly added to`crosapi::mojom::PrefPath` should be
+// handled by Ash. The only exception is the `crosapi::mojom::PrefPath::kProxy`
+// pref which, for secondary profiles only, is applied at browser scope.
+bool IsBrowserScopePrefOperation(crosapi::mojom::PrefPath pref_path,
+ Profile* profile) {
+ if (pref_path == crosapi::mojom::PrefPath::kUnknown) {
+ return true;
+ }
+ if (pref_path == crosapi::mojom::PrefPath::kProxy) {
+ if (!profile->IsMainProfile()) {
+ return true;
+ }
+ // TODO(acostinas,b/267719988) If the current version of Ash does not
+ // support syncing the proxy pref via the Prefs mojo service, the proxy pref
+ // can be set at browser scope only and it will be synced with Ash via the
+ // NetworkSettingsService mojo API.
+ static constexpr int kMinVersionProxyPref = 4;
+ const int version = chromeos::LacrosService::Get()
+ ->GetInterfaceVersion<crosapi::mojom::Prefs>();
+ if (version < kMinVersionProxyPref) {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
// Transform the thirdPartyCookiesAllowed extension api to CookieControlsMode
// enum values.
class CookieControlsModeTransformer : public PrefTransformerInterface {
@@ -188,27 +222,9 @@ class PrivacySandboxTransformer : public PrefTransformerInterface {
}
};
-constexpr char kIncognitoPersistent[] = "incognito_persistent";
-constexpr char kIncognitoSessionOnly[] = "incognito_session_only";
-constexpr char kRegular[] = "regular";
-constexpr char kRegularOnly[] = "regular_only";
-
-// TODO(crbug.com/1366445): Consider using the ChromeSettingScope
-// enum instead of ExtensionPrefsScope. That way, we could remove
-// this function and the preceding string constants.
-bool StringToScope(const std::string& s, ExtensionPrefsScope* scope) {
- if (s == kRegular) {
- *scope = kExtensionPrefsScopeRegular;
- } else if (s == kRegularOnly) {
- *scope = kExtensionPrefsScopeRegularOnly;
- } else if (s == kIncognitoPersistent) {
- *scope = kExtensionPrefsScopeIncognitoPersistent;
- } else if (s == kIncognitoSessionOnly) {
- *scope = kExtensionPrefsScopeIncognitoSessionOnly;
- } else {
- return false;
- }
- return true;
+bool StringToScope(const std::string& s, ChromeSettingScope& scope) {
+ scope = extensions::api::types::ParseChromeSettingScope(s);
+ return scope != ChromeSettingScope::kNone;
}
} // namespace
@@ -232,7 +248,7 @@ PreferenceEventRouter::PreferenceEventRouter(Profile* profile)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
crosapi::mojom::PrefPath pref_path =
PrefMapping::GetInstance()->GetPrefPathForPrefName(pref.browser_pref);
- if (pref_path != crosapi::mojom::PrefPath::kUnknown &&
+ if (!IsBrowserScopePrefOperation(pref_path, profile) &&
ash_supports_crosapi_observers) {
// Extension-controlled pref with the real value to watch in ash.
// This base::Unretained() is safe because PreferenceEventRouter owns
@@ -527,19 +543,19 @@ void PreferenceAPI::OnContentSettingChanged(const std::string& extension_id,
ExtensionPrefs::Get(profile_)->UpdateExtensionPref(
extension_id, pref_names::kPrefIncognitoContentSettings,
base::Value(content_settings_store()->GetSettingsForExtension(
- extension_id, kExtensionPrefsScopeIncognitoPersistent)));
+ extension_id, ChromeSettingScope::kIncognitoPersistent)));
} else {
ExtensionPrefs::Get(profile_)->UpdateExtensionPref(
extension_id, pref_names::kPrefContentSettings,
base::Value(content_settings_store()->GetSettingsForExtension(
- extension_id, kExtensionPrefsScopeRegular)));
+ extension_id, ChromeSettingScope::kRegular)));
}
}
void PreferenceAPI::ClearIncognitoSessionOnlyContentSettings() {
for (const auto& id : ExtensionPrefs::Get(profile_)->GetExtensions()) {
content_settings_store()->ClearContentSettingsForExtension(
- id, kExtensionPrefsScopeIncognitoSessionOnly);
+ id, ChromeSettingScope::kIncognitoSessionOnly);
}
}
@@ -623,8 +639,12 @@ ExtensionFunction::ResponseAction GetPreferenceFunction::Run() {
cached_browser_pref_ = browser_pref;
crosapi::mojom::PrefPath pref_path =
PrefMapping::GetInstance()->GetPrefPathForPrefName(cached_browser_pref_);
- if (pref_path != crosapi::mojom::PrefPath::kUnknown) {
- if (!profile->IsMainProfile()) {
+ if (!IsBrowserScopePrefOperation(pref_path, profile)) {
+ // Exclude chrome.privacy.website.protectedContentID (mapped to
+ // kProtectedContentDefault) from secondary profile access
+ // (crbug.com/1450718).
+ if (!profile->IsMainProfile() &&
+ pref_path == crosapi::mojom::PrefPath::kProtectedContentDefault) {
return RespondNow(Error(kPrimaryProfileOnlyErrorMessage, pref_key));
}
// This pref should be read from ash.
@@ -749,15 +769,14 @@ ExtensionFunction::ResponseAction SetPreferenceFunction::Run() {
const base::Value* value = details.Find(kValue);
EXTENSION_FUNCTION_VALIDATE(value);
- ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
+ ChromeSettingScope scope = ChromeSettingScope::kRegular;
if (const std::string* scope_str = details.FindString(kScopeKey)) {
- EXTENSION_FUNCTION_VALIDATE(StringToScope(*scope_str, &scope));
+ EXTENSION_FUNCTION_VALIDATE(StringToScope(*scope_str, scope));
}
// Check incognito scope.
- bool incognito =
- (scope == kExtensionPrefsScopeIncognitoPersistent ||
- scope == kExtensionPrefsScopeIncognitoSessionOnly);
+ bool incognito = scope == ChromeSettingScope::kIncognitoPersistent ||
+ scope == ChromeSettingScope::kIncognitoSessionOnly;
if (incognito) {
// Regular profiles can't access incognito unless
// include_incognito_information is true.
@@ -775,7 +794,7 @@ ExtensionFunction::ResponseAction SetPreferenceFunction::Run() {
}
Profile* profile = Profile::FromBrowserContext(browser_context());
- if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
+ if (scope == ChromeSettingScope::kIncognitoSessionOnly &&
!profile->HasPrimaryOTRProfile()) {
return RespondNow(Error(extension_misc::kIncognitoSessionOnlyErrorMessage));
}
@@ -796,7 +815,7 @@ ExtensionFunction::ResponseAction SetPreferenceFunction::Run() {
crosapi::mojom::PrefPath pref_path =
PrefMapping::GetInstance()->GetPrefPathForPrefName(browser_pref);
chromeos::LacrosService* lacros_service;
- if (pref_path != crosapi::mojom::PrefPath::kUnknown) {
+ if (!IsBrowserScopePrefOperation(pref_path, profile)) {
if (!profile->IsMainProfile()) {
return RespondNow(Error(kPrimaryProfileOnlyErrorMessage, pref_key));
}
@@ -899,7 +918,7 @@ ExtensionFunction::ResponseAction SetPreferenceFunction::Run() {
prefs_helper->SetExtensionControlledPref(extension_id(), browser_pref, scope,
browser_pref_value->Clone());
#if BUILDFLAG(IS_CHROMEOS_LACROS)
- if (pref_path != crosapi::mojom::PrefPath::kUnknown &&
+ if (!IsBrowserScopePrefOperation(pref_path, profile) &&
prefs_helper->DoesExtensionControlPref(extension_id(), browser_pref,
nullptr)) {
lacros_service->GetRemote<crosapi::mojom::Prefs>()->SetPref(
@@ -928,15 +947,14 @@ ExtensionFunction::ResponseAction ClearPreferenceFunction::Run() {
std::string pref_key = args()[0].GetString();
const base::Value::Dict& details = args()[1].GetDict();
- ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
+ ChromeSettingScope scope = ChromeSettingScope::kRegular;
if (const std::string* scope_str = details.FindString(kScopeKey)) {
- EXTENSION_FUNCTION_VALIDATE(StringToScope(*scope_str, &scope));
+ EXTENSION_FUNCTION_VALIDATE(StringToScope(*scope_str, scope));
}
// Check incognito scope.
- bool incognito =
- (scope == kExtensionPrefsScopeIncognitoPersistent ||
- scope == kExtensionPrefsScopeIncognitoSessionOnly);
+ bool incognito = scope == ChromeSettingScope::kIncognitoPersistent ||
+ scope == ChromeSettingScope::kIncognitoSessionOnly;
if (incognito) {
// We don't check incognito permissions here, as an extension should be
// always allowed to clear its own settings.
@@ -964,8 +982,8 @@ ExtensionFunction::ResponseAction ClearPreferenceFunction::Run() {
crosapi::mojom::PrefPath pref_path =
PrefMapping::GetInstance()->GetPrefPathForPrefName(browser_pref);
chromeos::LacrosService* lacros_service;
- if (pref_path != crosapi::mojom::PrefPath::kUnknown) {
- Profile* profile = Profile::FromBrowserContext(browser_context());
+ Profile* profile = Profile::FromBrowserContext(browser_context());
+ if (!IsBrowserScopePrefOperation(pref_path, profile)) {
if (!profile->IsMainProfile()) {
return RespondNow(Error(kPrimaryProfileOnlyErrorMessage, pref_key));
}
@@ -1015,14 +1033,13 @@ ExtensionFunction::ResponseAction ClearPreferenceFunction::Run() {
extension_id(), prefs::kSafeBrowsingEnhanced, scope);
}
#if BUILDFLAG(IS_CHROMEOS_LACROS)
- if (pref_path != crosapi::mojom::PrefPath::kUnknown &&
+ if (!IsBrowserScopePrefOperation(pref_path, profile) &&
did_just_control_pref) {
// This is an ash pref and we need to update ash because the extension that
// just cleared the pref used to control it. Now, either another extension
// of lower precedence controls the pref (in which case we update the pref
// to that value), or no other extension has set the pref (in which case
// we can clear the value set by extensions in ash).
- Profile* profile = Profile::FromBrowserContext(browser_context());
PrefService* pref_service =
extensions::preference_helpers::GetProfilePrefService(profile,
incognito);
diff --git a/chromium/chrome/browser/extensions/api/preference/preference_api.h b/chromium/chrome/browser/extensions/api/preference/preference_api.h
index a1d0c204081..abee3457484 100644
--- a/chromium/chrome/browser/extensions/api/preference/preference_api.h
+++ b/chromium/chrome/browser/extensions/api/preference/preference_api.h
@@ -18,6 +18,7 @@
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_function.h"
+#include "extensions/common/api/types.h"
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/crosapi/mojom/prefs.mojom-shared.h"
@@ -96,6 +97,7 @@ class PreferenceAPI : public BrowserContextKeyedAPI,
public EventRouter::Observer,
public ContentSettingsStore::Observer {
public:
+ using ChromeSettingScope = extensions::api::types::ChromeSettingScope;
explicit PreferenceAPI(content::BrowserContext* context);
PreferenceAPI(const PreferenceAPI&) = delete;
diff --git a/chromium/chrome/browser/extensions/api/preference/preference_api_lacros_browsertest.cc b/chromium/chrome/browser/extensions/api/preference/preference_api_lacros_browsertest.cc
index 0ffff000462..b90472f5495 100644
--- a/chromium/chrome/browser/extensions/api/preference/preference_api_lacros_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/preference/preference_api_lacros_browsertest.cc
@@ -7,22 +7,31 @@
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/task/single_thread_task_runner.h"
+#include "base/test/test_future.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_test_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/pref_names.h"
-#include "chromeos/crosapi/mojom/prefs.mojom-test-utils.h"
+#include "chromeos/crosapi/mojom/prefs.mojom-shared.h"
#include "chromeos/crosapi/mojom/prefs.mojom.h"
+#include "chromeos/lacros/crosapi_pref_observer.h"
#include "chromeos/lacros/lacros_service.h"
#include "chromeos/lacros/lacros_test_helper.h"
#include "chromeos/startup/browser_params_proxy.h"
#include "components/keep_alive_registry/keep_alive_types.h"
#include "components/keep_alive_registry/scoped_keep_alive.h"
#include "components/prefs/pref_service.h"
+#include "components/proxy_config/proxy_config_dictionary.h"
+#include "components/proxy_config/proxy_config_pref_names.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
#include "extensions/browser/test_extension_registry_observer.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"
@@ -30,8 +39,26 @@
#include "mojo/public/cpp/bindings/remote_set.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace {
+
using ContextType = extensions::ExtensionBrowserTest::ContextType;
+void SetPref(crosapi::mojom::PrefPath path, base::Value value) {
+ base::test::TestFuture<void> future;
+ chromeos::LacrosService::Get()->GetRemote<crosapi::mojom::Prefs>()->SetPref(
+ path, std::move(value), future.GetCallback());
+ ASSERT_TRUE(future.Wait());
+}
+
+absl::optional<base::Value> GetPref(crosapi::mojom::PrefPath path) {
+ base::test::TestFuture<absl::optional<base::Value>> future;
+ chromeos::LacrosService::Get()->GetRemote<crosapi::mojom::Prefs>()->GetPref(
+ path, future.GetCallback());
+ return future.Take();
+}
+
+} // namespace
+
// Tests for extension-controlled prefs, where an extension in lacros sets a
// pref where the underlying feature lives in ash.
class ExtensionPreferenceApiLacrosBrowserTest
@@ -56,6 +83,13 @@ class ExtensionPreferenceApiLacrosBrowserTest
EXPECT_TRUE(pref->IsExtensionControlled());
EXPECT_TRUE(
prefs->GetBoolean(prefs::kLacrosAccessibilitySpokenFeedbackEnabled));
+
+ const PrefService::Preference* proxy_pref =
+ prefs->FindPreference(proxy_config::prefs::kProxy);
+ ASSERT_TRUE(proxy_pref);
+ EXPECT_TRUE(proxy_pref->IsExtensionControlled());
+ EXPECT_EQ(ProxyConfigDictionary::CreateDirect(),
+ proxy_pref->GetValue()->GetDict());
}
void CheckPreferencesCleared() {
@@ -66,6 +100,29 @@ class ExtensionPreferenceApiLacrosBrowserTest
EXPECT_FALSE(pref->IsExtensionControlled());
EXPECT_FALSE(
prefs->GetBoolean(prefs::kLacrosAccessibilitySpokenFeedbackEnabled));
+
+ const PrefService::Preference* proxy_pref =
+ prefs->FindPreference(proxy_config::prefs::kProxy);
+ ASSERT_TRUE(proxy_pref);
+ EXPECT_FALSE(proxy_pref->IsExtensionControlled());
+ EXPECT_EQ(ProxyConfigDictionary::CreateSystem(),
+ proxy_pref->GetValue()->GetDict());
+ }
+
+ void SetUp() override {
+ // When the test changes the value of
+ // chrome.accessibilityFeatures.autoclick in Ash, the pref value change is
+ // observed by AccessibilityController and will trigger popping up a dialog
+ // in Ash with the prompt about confirmation of disabling autoclick. The
+ // dialog is not closed when the test is torn down in Lacros, and will
+ // affect other tests running after it if the test runs with shared Ash.
+ // Therefore, we start a unique Ash to run with this test suite to avoid
+ // the test isolation issue.
+ StartUniqueAshChrome(
+ {}, {}, {},
+ "crbug.com/1435317 Switch to shared ash when autoclick disable "
+ "confirmation dialog issue is fixed");
+ ExtensionApiTest::SetUp();
}
void SetUpOnMainThread() override {
@@ -107,6 +164,13 @@ class ExtensionPreferenceApiLacrosBrowserTest
return true;
}
+ bool IsLacrosServiceSyncingProxyPref() {
+ static constexpr int kMinVersionProxyPolicy = 4;
+ const int version = chromeos::LacrosService::Get()
+ ->GetInterfaceVersion<crosapi::mojom::Prefs>();
+ return version >= kMinVersionProxyPolicy;
+ }
+
bool DoesAshSupportObservers() {
// Versions of ash without this capability cannot create observers for prefs
// writing to the ash standalone browser prefstore.
@@ -130,14 +194,9 @@ INSTANTIATE_TEST_SUITE_P(ServiceWorker,
::testing::Values(ContextType::kServiceWorker));
IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiLacrosBrowserTest, Lacros) {
- absl::optional<::base::Value> out_value;
- crosapi::mojom::PrefsAsyncWaiter async_waiter(
- chromeos::LacrosService::Get()->GetRemote<crosapi::mojom::Prefs>().get());
-
// At start, the value in ash should not be set.
- async_waiter.GetPref(
- crosapi::mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled,
- &out_value);
+ absl::optional<base::Value> out_value =
+ GetPref(crosapi::mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled);
EXPECT_FALSE(out_value.value().GetBool());
extensions::ExtensionId test_extension_id;
@@ -160,11 +219,14 @@ IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiLacrosBrowserTest, Lacros) {
CheckPreferencesSet();
// In ash, the value should now be set.
- async_waiter.GetPref(
- crosapi::mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled,
- &out_value);
+ out_value =
+ GetPref(crosapi::mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled);
EXPECT_TRUE(out_value.value().GetBool());
-
+ if (IsLacrosServiceSyncingProxyPref()) {
+ out_value = GetPref(crosapi::mojom::PrefPath::kProxy);
+ EXPECT_EQ(out_value.value().GetDict(),
+ ProxyConfigDictionary::CreateDirect());
+ }
// The settings should not be reset when the extension is reloaded.
{
ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
@@ -186,10 +248,15 @@ IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiLacrosBrowserTest, Lacros) {
// When the extension in uninstalled, the pref in lacros should be the
// default value (false). This only works if Ash correctly implements
// extension-controlled pref observers.
- async_waiter.GetPref(
- crosapi::mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled,
- &out_value);
+ out_value =
+ GetPref(crosapi::mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled);
EXPECT_FALSE(out_value.value().GetBool());
+
+ if (IsLacrosServiceSyncingProxyPref()) {
+ out_value = GetPref(crosapi::mojom::PrefPath::kProxy);
+ EXPECT_EQ(out_value.value().GetDict(),
+ ProxyConfigDictionary::CreateSystem());
+ }
}
{
@@ -201,6 +268,69 @@ IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiLacrosBrowserTest, Lacros) {
CheckPreferencesCleared();
}
+IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiLacrosBrowserTest,
+ LacrosSecondaryProfile) {
+ // At start, the value in ash should not be set.
+ absl::optional<base::Value> out_value =
+ GetPref(crosapi::mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled);
+ EXPECT_FALSE(out_value.value().GetBool());
+
+ // Create a secondary profile.
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ Profile& secondary_profile = profiles::testing::CreateProfileSync(
+ profile_manager, profile_manager->GenerateNextProfileDirectoryPath());
+ ASSERT_FALSE(secondary_profile.IsMainProfile());
+
+ // Load the testing extension in secondary profile.
+ extensions::ResultCatcher catcher;
+ ExtensionTestMessageListener listener_1("ready", ReplyBehavior::kWillReply);
+ extensions::ChromeTestExtensionLoader loader(&secondary_profile);
+ base::FilePath extension_path =
+ test_data_dir_.AppendASCII("preference/lacros_secondary_profile_read");
+ scoped_refptr<const extensions::Extension> extension =
+ loader.LoadExtension(extension_path);
+ ASSERT_TRUE(extension);
+ EXPECT_TRUE(listener_1.WaitUntilSatisfied());
+
+ // Run the test to verify that testing extension running in secondary
+ // profile reads the default values of the Prefs correctly.
+ listener_1.Reply("run test default value");
+ EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+
+ // Set the pref value in ash.
+ SetPref(crosapi::mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled,
+ base::Value(true));
+
+ // Verify the value is set in ash side.
+ out_value =
+ GetPref(crosapi::mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled);
+ EXPECT_TRUE(out_value.value().GetBool());
+
+ // Reload the testing extension in the secondary profile.
+ ExtensionTestMessageListener listener_2("ready", ReplyBehavior::kWillReply);
+ extensions::TestExtensionRegistryObserver observer(
+ extensions::ExtensionRegistry::Get(&secondary_profile), extension->id());
+ extensions::ExtensionService* extension_service =
+ extensions::ExtensionSystem::Get(&secondary_profile)->extension_service();
+ extension_service->ReloadExtension(extension->id());
+ observer.WaitForExtensionLoaded();
+ EXPECT_TRUE(listener_2.WaitUntilSatisfied());
+
+ // Run the test to verify that testing extension running in secondary
+ // profile reads the changed value of the accessibilityFeatures correctly.
+ listener_2.Reply("run test changed value");
+ EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+
+ // Since lacros browser tests shared the same ash instance, we need to restore
+ // the modified pref in ash to default before exiting the test, so that
+ // it won't affect other lacros browser tests.
+ SetPref(crosapi::mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled,
+ base::Value(false));
+ out_value =
+ GetPref(crosapi::mojom::PrefPath::kAccessibilitySpokenFeedbackEnabled);
+ EXPECT_FALSE(out_value.value().GetBool());
+}
+
IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiLacrosBrowserTest, OnChange) {
if (!DoesAshSupportObservers()) {
LOG(WARNING) << "Ash does not support observers, skipping the test.";
@@ -222,6 +352,144 @@ IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiLacrosBrowserTest,
<< message_;
}
+base::Value::Dict GetAshProxyPrefValue() {
+ absl::optional<::base::Value> out_value =
+ GetPref(crosapi::mojom::PrefPath::kProxy);
+ return out_value.value().GetDict().Clone();
+}
+
+scoped_refptr<const extensions::Extension> InstallExtensionForProfile(
+ Profile* profile,
+ const base::FilePath& path) {
+ extensions::ResultCatcher catcher;
+ ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
+ scoped_refptr<const extensions::Extension> extension =
+ extensions::ChromeTestExtensionLoader(profile).LoadExtension(path);
+ EXPECT_TRUE(listener.WaitUntilSatisfied());
+ // Run the tests.
+ listener.Reply("run test");
+ EXPECT_TRUE(catcher.GetNextResult());
+ return extension;
+}
+
+void ExpectThatProxyIsControlledByExtension(Profile* profile) {
+ const PrefService::Preference* pref =
+ profile->GetPrefs()->FindPreference(proxy_config::prefs::kProxy);
+ EXPECT_TRUE(pref->IsExtensionControlled());
+ EXPECT_EQ(ProxyConfigDictionary::CreateDirect(), pref->GetValue()->GetDict());
+}
+
+void ExpectThatProxyHasDefaultValue(Profile* profile) {
+ const PrefService::Preference* pref =
+ profile->GetPrefs()->FindPreference(proxy_config::prefs::kProxy);
+ EXPECT_FALSE(pref->IsExtensionControlled());
+ EXPECT_EQ(ProxyConfigDictionary::CreateSystem(), pref->GetValue()->GetDict());
+}
+
+// Secondary profiles should apply extension set proxy at browser level, but not
+// in Ash.
+IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiLacrosBrowserTest,
+ SecondaryProfilePrefs) {
+ if (!IsServiceAvailable()) {
+ return;
+ }
+ if (!IsLacrosServiceSyncingProxyPref()) {
+ GTEST_SKIP() << "Skipping test because the current version of Ash does not "
+ "support getting the proxy preference from a Lacros "
+ "extension via the preferences service";
+ }
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ base::FilePath path_profile =
+ profile_manager->GenerateNextProfileDirectoryPath();
+ Profile& secondary_profile =
+ profiles::testing::CreateProfileSync(profile_manager, path_profile);
+ scoped_refptr<const extensions::Extension> extension =
+ InstallExtensionForProfile(
+ &secondary_profile,
+ test_data_dir_.AppendASCII("preference/lacros_secondary_profile"));
+ // Verify that the proxy is set by the extension for the secondary profile.
+ ExpectThatProxyIsControlledByExtension(&secondary_profile);
+ // The proxy should not be set in the primary profile and Ash.
+ ExpectThatProxyHasDefaultValue(profile());
+ EXPECT_EQ(GetAshProxyPrefValue(), ProxyConfigDictionary::CreateSystem());
+}
+
+// Clearing an extension set proxy in a secondary profile should not clear the
+// extension set proxy in the primary profile and Ash (if the primary profile
+// has an extension which controls the proxy). The test setup:
+// - Create a secondary profile;
+// - Install an extension which controls the proxy pref in the primary profile;
+// - Install an extension which controls the proxy pref in the secondary
+// profile;
+// - Verify that both profiles have extension controlled proxy prefs;
+// - Uninstall the proxy controlling extension in the secondary profile;
+// - Verify that the secondary profile does not have an extension set proxy;
+// - Verify that the primary profile and Ash still have an extension set proxy.
+// This test can be extended to other prefs for which the primary profile
+// controls the value in Ash but secondary profiles only control the pref
+// value at browser level.
+IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiLacrosBrowserTest,
+ SecondaryProfilePrefsClearPref) {
+ if (!IsServiceAvailable()) {
+ return;
+ }
+ if (!IsLacrosServiceSyncingProxyPref()) {
+ GTEST_SKIP() << "Skipping test because the current version of Ash does not "
+ "support getting the proxy preference from a Lacros "
+ "extension via the preferences service";
+ }
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ base::FilePath path_profile =
+ profile_manager->GenerateNextProfileDirectoryPath();
+ Profile& secondary_profile =
+ profiles::testing::CreateProfileSync(profile_manager, path_profile);
+
+ scoped_refptr<const extensions::Extension> extension_primary =
+ InstallExtensionForProfile(
+ profile(),
+ test_data_dir_.AppendASCII("preference/lacros_secondary_profile"));
+
+ scoped_refptr<const extensions::Extension> extension_secondary =
+ InstallExtensionForProfile(
+ &secondary_profile,
+ test_data_dir_.AppendASCII("preference/lacros_secondary_profile"));
+
+ ExpectThatProxyIsControlledByExtension(&secondary_profile);
+ ExpectThatProxyIsControlledByExtension(profile());
+
+ // Uninstall the extension in the secondary profile and test that Ash is still
+ // returning the pref set by the extension running in the Lacros primary
+ // profile.
+ {
+ extensions::TestExtensionRegistryObserver observer(
+ extensions::ExtensionRegistry::Get(&secondary_profile),
+ extension_secondary->id());
+ auto* service_ = extensions::ExtensionSystem::Get(&secondary_profile)
+ ->extension_service();
+ service_->UninstallExtension(extension_secondary->id(),
+ extensions::UNINSTALL_REASON_FOR_TESTING,
+ NULL);
+ observer.WaitForExtensionUninstalled();
+ }
+
+ ExpectThatProxyHasDefaultValue(&secondary_profile);
+ ExpectThatProxyIsControlledByExtension(profile());
+ EXPECT_EQ(GetAshProxyPrefValue(), ProxyConfigDictionary::CreateDirect());
+
+ // Uninstall the extension in the primary profile.
+ {
+ extensions::TestExtensionRegistryObserver observer(
+ extensions::ExtensionRegistry::Get(profile()), extension_primary->id());
+ auto* service_ =
+ extensions::ExtensionSystem::Get(profile())->extension_service();
+ service_->UninstallExtension(extension_primary->id(),
+ extensions::UNINSTALL_REASON_FOR_TESTING,
+ NULL);
+ observer.WaitForExtensionUninstalled();
+ }
+ EXPECT_EQ(GetAshProxyPrefValue(), ProxyConfigDictionary::CreateSystem());
+}
+
// An implementation of the `crosapi::mojom::Prefs` mojo service which returns
// null when fetching a pref value. Used for testing the Preference API against
// Ash-Lacros version skew where Ash does not recognize the Lacros extension
diff --git a/chromium/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc b/chromium/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc
index 78e39d8bad4..8ca9d8be440 100644
--- a/chromium/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc
@@ -17,10 +17,12 @@
#include "extensions/browser/api/content_settings/content_settings_service.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_prefs_helper.h"
+#include "extensions/common/api/types.h"
#include "extensions/common/extension.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Value;
+using extensions::api::types::ChromeSettingScope;
namespace extensions {
@@ -95,7 +97,7 @@ void ExtensionControlledPrefsTest::InstallExtensionControlledPref(
base::Value value) {
EnsureExtensionInstalled(extension);
prefs_helper_.SetExtensionControlledPref(
- extension->id(), key, kExtensionPrefsScopeRegular, std::move(value));
+ extension->id(), key, ChromeSettingScope::kRegular, std::move(value));
}
void ExtensionControlledPrefsTest::InstallExtensionControlledPrefIncognito(
@@ -104,7 +106,7 @@ void ExtensionControlledPrefsTest::InstallExtensionControlledPrefIncognito(
base::Value value) {
EnsureExtensionInstalled(extension);
prefs_helper_.SetExtensionControlledPref(
- extension->id(), key, kExtensionPrefsScopeIncognitoPersistent,
+ extension->id(), key, ChromeSettingScope::kIncognitoPersistent,
std::move(value));
}
@@ -114,7 +116,7 @@ void ExtensionControlledPrefsTest::
base::Value value) {
EnsureExtensionInstalled(extension);
prefs_helper_.SetExtensionControlledPref(
- extension->id(), key, kExtensionPrefsScopeIncognitoSessionOnly,
+ extension->id(), key, ChromeSettingScope::kIncognitoSessionOnly,
std::move(value));
}
@@ -246,7 +248,7 @@ class ControlledPrefsUninstallExtension : public ExtensionControlledPrefsTest {
ContentSettingsPattern::FromString("http://[*.]example.com");
store->SetExtensionContentSetting(
extension1()->id(), pattern, pattern, ContentSettingsType::IMAGES,
- CONTENT_SETTING_BLOCK, kExtensionPrefsScopeRegular);
+ CONTENT_SETTING_BLOCK, ChromeSettingScope::kRegular);
UninstallExtension(extension1()->id());
}
diff --git a/chromium/chrome/browser/extensions/api/preference/preference_apitest.cc b/chromium/chrome/browser/extensions/api/preference/preference_apitest.cc
index 55f11fa80f9..fd399146cb9 100644
--- a/chromium/chrome/browser/extensions/api/preference/preference_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/preference/preference_apitest.cc
@@ -693,7 +693,9 @@ IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiEventPageTest,
// This check is not done in the Standard test so we can test if the granular
// Privacy Sandbox APIs are turned off, when |kPrivacySandboxApisEnabled| is
// turned off, in isolation of controlling them directly.
-IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiTest, PrivacySandboxMigration) {
+// TODO(crbug.com/1470295): Test is flaky on all platforms.
+IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiTest,
+ DISABLED_PrivacySandboxMigration) {
PrefService* prefs = profile_->GetPrefs();
prefs->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, true);
prefs->SetBoolean(prefs::kPrivacySandboxM1FledgeEnabled, true);
diff --git a/chromium/chrome/browser/extensions/api/preference/preference_helpers.h b/chromium/chrome/browser/extensions/api/preference/preference_helpers.h
index 2ab0bcfdf64..2e4c116866c 100644
--- a/chromium/chrome/browser/extensions/api/preference/preference_helpers.h
+++ b/chromium/chrome/browser/extensions/api/preference/preference_helpers.h
@@ -10,7 +10,6 @@
#include "base/values.h"
#include "build/chromeos_buildflags.h"
#include "extensions/browser/extension_event_histogram_value.h"
-#include "extensions/browser/extension_prefs_scope.h"
#include "extensions/common/mojom/api_permission_id.mojom-shared.h"
#include "extensions/common/permissions/permission_set.h"
diff --git a/chromium/chrome/browser/extensions/api/printer_provider/printer_provider_apitest.cc b/chromium/chrome/browser/extensions/api/printer_provider/printer_provider_apitest.cc
index 382bd6d92ba..e4852e7ed53 100644
--- a/chromium/chrome/browser/extensions/api/printer_provider/printer_provider_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/printer_provider/printer_provider_apitest.cc
@@ -419,12 +419,12 @@ IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, GetPrintersAsyncSuccess) {
IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest, GetPrintersTwoExtensions) {
ResultCatcher catcher;
- std::string extension_id_1;
+ ExtensionId extension_id_1;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"OK", &extension_id_1);
ASSERT_FALSE(extension_id_1.empty());
- std::string extension_id_2;
+ ExtensionId extension_id_2;
InitializePrinterProviderTestExtension(
"printer_provider/request_printers_second", "OK", &extension_id_2);
ASSERT_FALSE(extension_id_2.empty());
@@ -475,12 +475,12 @@ IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest,
GetPrintersTwoExtensionsBothUnloaded) {
ResultCatcher catcher;
- std::string extension_id_1;
+ ExtensionId extension_id_1;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"IGNORE_CALLBACK", &extension_id_1);
ASSERT_FALSE(extension_id_1.empty());
- std::string extension_id_2;
+ ExtensionId extension_id_2;
InitializePrinterProviderTestExtension(
"printer_provider/request_printers_second", "IGNORE_CALLBACK",
&extension_id_2);
@@ -505,12 +505,12 @@ IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest,
GetPrintersTwoExtensionsOneFails) {
ResultCatcher catcher;
- std::string extension_id_1;
+ ExtensionId extension_id_1;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"NOT_ARRAY", &extension_id_1);
ASSERT_FALSE(extension_id_1.empty());
- std::string extension_id_2;
+ ExtensionId extension_id_2;
InitializePrinterProviderTestExtension(
"printer_provider/request_printers_second", "OK", &extension_id_2);
ASSERT_FALSE(extension_id_2.empty());
@@ -547,12 +547,12 @@ IN_PROC_BROWSER_TEST_P(PrinterProviderApiTest,
GetPrintersTwoExtensionsOneWithNoListener) {
ResultCatcher catcher;
- std::string extension_id_1;
+ ExtensionId extension_id_1;
InitializePrinterProviderTestExtension("printer_provider/request_printers",
"NO_LISTENER", &extension_id_1);
ASSERT_FALSE(extension_id_1.empty());
- std::string extension_id_2;
+ ExtensionId extension_id_2;
InitializePrinterProviderTestExtension(
"printer_provider/request_printers_second", "OK", &extension_id_2);
ASSERT_FALSE(extension_id_2.empty());
diff --git a/chromium/chrome/browser/extensions/api/printing/fake_print_job_controller_ash.h b/chromium/chrome/browser/extensions/api/printing/fake_print_job_controller_ash.h
index 9558b5e5258..64779176f0d 100644
--- a/chromium/chrome/browser/extensions/api/printing/fake_print_job_controller_ash.h
+++ b/chromium/chrome/browser/extensions/api/printing/fake_print_job_controller_ash.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/containers/flat_map.h"
+#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/printing/cups_print_job_manager.h"
#include "chrome/browser/extensions/api/printing/print_job_controller.h"
@@ -47,8 +48,8 @@ class FakePrintJobControllerAsh : public PrintJobController,
std::unique_ptr<printing::PrintSettings> settings);
// Not owned by FakePrintJobControllerAsh.
- ash::TestCupsPrintJobManager* const print_job_manager_;
- ash::CupsPrintersManager* const printers_manager_;
+ const raw_ptr<ash::TestCupsPrintJobManager> print_job_manager_;
+ const raw_ptr<ash::CupsPrintersManager> printers_manager_;
// Stores ongoing print jobs as a mapping from job id to CupsPrintJob.
base::flat_map<std::string, std::unique_ptr<ash::CupsPrintJob>> jobs_;
diff --git a/chromium/chrome/browser/extensions/api/printing/printing_api_handler_unittest.cc b/chromium/chrome/browser/extensions/api/printing/printing_api_handler_unittest.cc
index 7c74e3a140a..53b228cd56e 100644
--- a/chromium/chrome/browser/extensions/api/printing/printing_api_handler_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/printing/printing_api_handler_unittest.cc
@@ -37,6 +37,7 @@
#include "extensions/browser/event_router_factory.h"
#include "extensions/browser/test_event_router.h"
#include "extensions/common/extension_builder.h"
+#include "extensions/common/extension_id.h"
#include "printing/backend/print_backend.h"
#include "printing/backend/test_print_backend.h"
#include "printing/mojom/print.mojom.h"
@@ -88,7 +89,7 @@ class PrintingEventObserver : public TestEventRouter::EventObserver {
}
}
- const std::string& extension_id() const { return extension_id_; }
+ const ExtensionId& extension_id() const { return extension_id_; }
const base::Value& event_args() const { return event_args_; }
@@ -100,7 +101,7 @@ class PrintingEventObserver : public TestEventRouter::EventObserver {
const std::string event_name_;
// The extension id passed for the last observed event.
- std::string extension_id_;
+ ExtensionId extension_id_;
// The arguments passed for the last observed event.
base::Value event_args_;
@@ -204,10 +205,10 @@ ConstructPrinterCapabilities() {
capabilities.duplex_modes.push_back(printing::mojom::DuplexMode::kSimplex);
capabilities.copies_max = 5;
capabilities.dpis.emplace_back(kHorizontalDpi, kVerticalDpi);
- printing::PrinterSemanticCapsAndDefaults::Paper paper;
- paper.vendor_id = kMediaSizeVendorId;
- paper.size_um = gfx::Size(kMediaSizeWidth, kMediaSizeHeight);
- capabilities.papers.push_back(paper);
+ printing::PrinterSemanticCapsAndDefaults::Paper paper(
+ /*display_name=*/"", kMediaSizeVendorId,
+ {kMediaSizeWidth, kMediaSizeHeight});
+ capabilities.papers.push_back(std::move(paper));
capabilities.collate_capable = true;
return capabilities;
}
diff --git a/chromium/chrome/browser/extensions/api/printing/printing_api_utils.cc b/chromium/chrome/browser/extensions/api/printing/printing_api_utils.cc
index 326699bf56f..bdd84766925 100644
--- a/chromium/chrome/browser/extensions/api/printing/printing_api_utils.cc
+++ b/chromium/chrome/browser/extensions/api/printing/printing_api_utils.cc
@@ -305,7 +305,7 @@ bool CheckSettingsAndCapabilitiesCompatibility(
capabilities.papers,
[&requested_media](
const printing::PrinterSemanticCapsAndDefaults::Paper& paper) {
- return paper.size_um == requested_media.size_microns;
+ return paper.IsSizeWithinBounds(requested_media.size_microns);
});
}
diff --git a/chromium/chrome/browser/extensions/api/printing/printing_api_utils_unittest.cc b/chromium/chrome/browser/extensions/api/printing/printing_api_utils_unittest.cc
index e3992329609..2982d3e640e 100644
--- a/chromium/chrome/browser/extensions/api/printing/printing_api_utils_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/printing/printing_api_utils_unittest.cc
@@ -32,6 +32,7 @@ constexpr int kHorizontalDpi = 300;
constexpr int kVerticalDpi = 400;
constexpr int kMediaSizeWidth = 210000;
constexpr int kMediaSizeHeight = 297000;
+constexpr int kCustomMediaSizeMin = 2540;
constexpr char kMediaSizeVendorId[] = "iso_a4_210x297mm";
constexpr char kVendorItemId[] = "finishings";
constexpr char kVendorItemValue[] = "trim";
@@ -151,14 +152,29 @@ printing::PrinterSemanticCapsAndDefaults ConstructPrinterCapabilities() {
capabilities.duplex_modes.push_back(printing::mojom::DuplexMode::kLongEdge);
capabilities.copies_max = kCopies;
capabilities.dpis.push_back(gfx::Size(kHorizontalDpi, kVerticalDpi));
- printing::PrinterSemanticCapsAndDefaults::Paper paper;
- paper.vendor_id = kMediaSizeVendorId;
- paper.size_um = gfx::Size(kMediaSizeWidth, kMediaSizeHeight);
+ printing::PrinterSemanticCapsAndDefaults::Paper paper(
+ /*display_name=*/"", kMediaSizeVendorId,
+ gfx::Size(kMediaSizeWidth, kMediaSizeHeight));
capabilities.papers.push_back(paper);
capabilities.collate_capable = true;
return capabilities;
}
+printing::PrinterSemanticCapsAndDefaults
+ConstructPrinterCapabilitiesWithCustomSize() {
+ printing::PrinterSemanticCapsAndDefaults capabilities =
+ ConstructPrinterCapabilities();
+ // Reset our papers and create a new paper with a custom size range.
+ capabilities.papers.clear();
+ printing::PrinterSemanticCapsAndDefaults::Paper paper(
+ /*display_name=*/"", kMediaSizeVendorId,
+ gfx::Size(kMediaSizeWidth, kCustomMediaSizeMin),
+ /*printable_area_um=*/gfx::Rect(), kMediaSizeHeight);
+ capabilities.papers.push_back(paper);
+
+ return capabilities;
+}
+
} // namespace
TEST(PrintingApiUtilsTest, GetDefaultPrinterRules) {
@@ -287,6 +303,41 @@ TEST(PrintingApiUtilsTest,
CheckSettingsAndCapabilitiesCompatibility(*settings, capabilities));
}
+TEST(PrintingApiUtilsTest,
+ CheckSettingsAndCapabilitiesCompatibilityCustomMediaSize) {
+ std::unique_ptr<printing::PrintSettings> settings = ConstructPrintSettings();
+ printing::PrinterSemanticCapsAndDefaults capabilities =
+ ConstructPrinterCapabilitiesWithCustomSize();
+ EXPECT_TRUE(
+ CheckSettingsAndCapabilitiesCompatibility(*settings, capabilities));
+}
+
+TEST(PrintingApiUtilsTest,
+ CheckSettingsAndCapabilitiesCompatibilityCustomMediaSizeLongWidth) {
+ std::unique_ptr<printing::PrintSettings> settings = ConstructPrintSettings();
+ // Update the requested media so the width is wider than our custom size.
+ printing::PrintSettings::RequestedMedia media = settings->requested_media();
+ media.size_microns.set_width(kMediaSizeWidth + 1);
+ settings->set_requested_media(media);
+ printing::PrinterSemanticCapsAndDefaults capabilities =
+ ConstructPrinterCapabilitiesWithCustomSize();
+ EXPECT_FALSE(
+ CheckSettingsAndCapabilitiesCompatibility(*settings, capabilities));
+}
+
+TEST(PrintingApiUtilsTest,
+ CheckSettingsAndCapabilitiesCompatibilityCustomMediaSizeShortHeight) {
+ std::unique_ptr<printing::PrintSettings> settings = ConstructPrintSettings();
+ // Update the requested media so the length is shorter than our custom size.
+ printing::PrintSettings::RequestedMedia media = settings->requested_media();
+ media.size_microns.set_height(kCustomMediaSizeMin - 1);
+ settings->set_requested_media(media);
+ printing::PrinterSemanticCapsAndDefaults capabilities =
+ ConstructPrinterCapabilitiesWithCustomSize();
+ EXPECT_FALSE(
+ CheckSettingsAndCapabilitiesCompatibility(*settings, capabilities));
+}
+
TEST(PrintingApiUtilsTest, CheckSettingsAndCapabilitiesCompatibility_Collate) {
std::unique_ptr<printing::PrintSettings> settings = ConstructPrintSettings();
printing::PrinterSemanticCapsAndDefaults capabilities =
diff --git a/chromium/chrome/browser/extensions/api/printing/printing_apitest.cc b/chromium/chrome/browser/extensions/api/printing/printing_apitest.cc
index 9f5bdc0364c..544f7370dab 100644
--- a/chromium/chrome/browser/extensions/api/printing/printing_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/printing/printing_apitest.cc
@@ -61,10 +61,10 @@ ConstructPrinterCapabilities() {
capabilities->duplex_modes.push_back(printing::mojom::DuplexMode::kSimplex);
capabilities->copies_max = 2;
capabilities->dpis.emplace_back(kHorizontalDpi, kVerticalDpi);
- printing::PrinterSemanticCapsAndDefaults::Paper paper;
- paper.vendor_id = kMediaSizeVendorId;
- paper.size_um = gfx::Size(kMediaSizeWidth, kMediaSizeHeight);
- capabilities->papers.push_back(paper);
+ printing::PrinterSemanticCapsAndDefaults::Paper paper(
+ /*display_name=*/"", kMediaSizeVendorId,
+ {kMediaSizeWidth, kMediaSizeHeight});
+ capabilities->papers.push_back(std::move(paper));
capabilities->collate_capable = true;
return capabilities;
}
diff --git a/chromium/chrome/browser/extensions/api/proxy/proxy_api.cc b/chromium/chrome/browser/extensions/api/proxy/proxy_api.cc
index 5ecb6201024..0d43a09f5d0 100644
--- a/chromium/chrome/browser/extensions/api/proxy/proxy_api.cc
+++ b/chromium/chrome/browser/extensions/api/proxy/proxy_api.cc
@@ -72,13 +72,10 @@ void ProxyEventRouter::OnPACScriptError(EventRouterForwarder* event_router,
base::Value::Dict dict;
dict.Set(kProxyEventFatalKey, false);
dict.Set(kProxyEventErrorKey, net::ErrorToString(net::ERR_PAC_SCRIPT_FAILED));
- std::string error_msg;
+ std::string error_msg = base::UTF16ToUTF8(error);
if (line_number != -1) {
- base::SStringPrintf(&error_msg,
- "line: %d: %s",
- line_number, base::UTF16ToUTF8(error).c_str());
- } else {
- error_msg = base::UTF16ToUTF8(error);
+ error_msg =
+ base::StringPrintf("line: %d: %s", line_number, error_msg.c_str());
}
dict.Set(kProxyEventDetailsKey, error_msg);
args.Append(base::Value(std::move(dict)));
diff --git a/chromium/chrome/browser/extensions/api/proxy/proxy_apitest.cc b/chromium/chrome/browser/extensions/api/proxy/proxy_apitest.cc
index 26e38d794e3..0ce8aed91a4 100644
--- a/chromium/chrome/browser/extensions/api/proxy/proxy_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/proxy/proxy_apitest.cc
@@ -34,6 +34,15 @@ const char kNoServer[] = "";
const char kNoBypass[] = "";
const char kNoPac[] = "";
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+bool IsLacrosServiceSyncingProxyPref() {
+ static constexpr int kMinVersionProxyPolicy = 4;
+ const int version = chromeos::LacrosService::Get()
+ ->GetInterfaceVersion<crosapi::mojom::Prefs>();
+ return version >= kMinVersionProxyPolicy;
+}
+#endif
+
} // namespace
class ProxySettingsApiTest : public ExtensionApiTest {
@@ -50,10 +59,22 @@ class ProxySettingsApiTest : public ExtensionApiTest {
// used for all tests in the target. Setting a proxy will prevent other
// tests which require a direct connection to complete successfully.
auto* lacros_service = chromeos::LacrosService::Get();
- if (lacros_service &&
- lacros_service->IsAvailable<crosapi::mojom::NetworkSettingsService>()) {
- lacros_service->GetRemote<crosapi::mojom::NetworkSettingsService>()
- ->ClearExtensionProxy();
+ if (!lacros_service) {
+ ExtensionApiTest::TearDownOnMainThread();
+ return;
+ }
+ if (IsLacrosServiceSyncingProxyPref()) {
+ if (lacros_service->IsAvailable<crosapi::mojom::Prefs>()) {
+ lacros_service->GetRemote<crosapi::mojom::Prefs>()
+ ->ClearExtensionControlledPref(crosapi::mojom::PrefPath::kProxy,
+ base::DoNothing());
+ }
+ } else {
+ if (lacros_service
+ ->IsAvailable<crosapi::mojom::NetworkSettingsService>()) {
+ lacros_service->GetRemote<crosapi::mojom::NetworkSettingsService>()
+ ->ClearExtensionProxy();
+ }
}
ExtensionApiTest::TearDownOnMainThread();
}
diff --git a/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.cc b/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.cc
index 97f35f6a112..82f7ff830fb 100644
--- a/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.cc
@@ -24,11 +24,13 @@
#include "chrome/browser/profiles/profile_manager.h"
#include "chromeos/ash/components/login/auth/public/authentication_error.h"
#include "chromeos/ash/components/login/auth/public/user_context.h"
+#include "chromeos/ash/components/osauth/public/auth_session_storage.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/event_router.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace extensions {
@@ -201,11 +203,31 @@ Profile* GetActiveProfile(content::BrowserContext* browser_context) {
}
AuthToken* GetActiveProfileAuthToken(content::BrowserContext* browser_context) {
+ CHECK(!ash::features::ShouldUseAuthSessionStorage());
return ash::quick_unlock::QuickUnlockFactory::GetForProfile(
GetActiveProfile(browser_context))
->GetAuthToken();
}
+absl::optional<std::string> CheckTokenValidity(
+ content::BrowserContext* browser_context,
+ const std::string& token) {
+ if (ash::features::ShouldUseAuthSessionStorage()) {
+ if (!ash::AuthSessionStorage::Get()->IsValid(token)) {
+ return kAuthTokenExpired;
+ }
+ } else {
+ AuthToken* auth_token = GetActiveProfileAuthToken(browser_context);
+ if (!auth_token) {
+ return kAuthTokenExpired;
+ }
+ if (token != auth_token->Identifier()) {
+ return kAuthTokenInvalid;
+ }
+ }
+ return absl::nullopt;
+}
+
} // namespace
// quickUnlockPrivate.getAuthToken
@@ -260,11 +282,11 @@ ExtensionFunction::ResponseAction
QuickUnlockPrivateSetLockScreenEnabledFunction::Run() {
auto params =
quick_unlock_private::SetLockScreenEnabled::Params::Create(args());
- AuthToken* auth_token = GetActiveProfileAuthToken(browser_context());
- if (!auth_token)
- return RespondNow(Error(kAuthTokenExpired));
- if (params->token != auth_token->Identifier())
- return RespondNow(Error(kAuthTokenInvalid));
+ absl::optional<std::string> error =
+ CheckTokenValidity(browser_context(), params->token);
+ if (error.has_value()) {
+ return RespondNow(Error(error.value()));
+ }
GetActiveProfile(browser_context())
->GetPrefs()
@@ -288,11 +310,11 @@ QuickUnlockPrivateSetPinAutosubmitEnabledFunction::Run() {
auto params =
quick_unlock_private::SetPinAutosubmitEnabled::Params::Create(args());
- AuthToken* auth_token = GetActiveProfileAuthToken(browser_context());
- if (!auth_token)
- return RespondNow(Error(kAuthTokenExpired));
- if (params->token != auth_token->Identifier())
- return RespondNow(Error(kAuthTokenInvalid));
+ absl::optional<std::string> error =
+ CheckTokenValidity(browser_context(), params->token);
+ if (error.has_value()) {
+ return RespondNow(Error(error.value()));
+ }
Profile* profile = GetActiveProfile(browser_context());
user_manager::User* user =
@@ -324,10 +346,6 @@ QuickUnlockPrivateCanAuthenticatePinFunction::
ExtensionFunction::ResponseAction
QuickUnlockPrivateCanAuthenticatePinFunction::Run() {
- AuthToken* auth_token = GetActiveProfileAuthToken(browser_context());
- if (!auth_token)
- return RespondNow(Error(kAuthTokenExpired));
-
Profile* profile = GetActiveProfile(browser_context());
user_manager::User* user =
ash::ProfileHelper::Get()->GetUserByProfile(profile);
@@ -490,11 +508,11 @@ ExtensionFunction::ResponseAction QuickUnlockPrivateSetModesFunction::Run() {
if (params_->modes.size() > 1)
return RespondNow(Error(kMultipleModesNotSupported));
- AuthToken* auth_token = GetActiveProfileAuthToken(browser_context());
- if (!auth_token)
- return RespondNow(Error(kAuthTokenExpired));
- if (params_->token != auth_token->Identifier())
- return RespondNow(Error(kAuthTokenInvalid));
+ absl::optional<std::string> error =
+ CheckTokenValidity(browser_context(), params_->token);
+ if (error.has_value()) {
+ return RespondNow(Error(error.value()));
+ }
// Verify every credential is valid based on policies.
PrefService* pref_service = GetActiveProfile(browser_context())->GetPrefs();
diff --git a/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api_unittest.cc b/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api_unittest.cc
index 72b99b2dd5c..ef287bff9e0 100644
--- a/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api_unittest.cc
@@ -7,6 +7,7 @@
#include "chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.h"
#include <memory>
+#include <utility>
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
@@ -44,6 +45,8 @@
#include "chromeos/ash/components/dbus/userdataauth/fake_userdataauth_client.h"
#include "chromeos/ash/components/login/auth/fake_extended_authenticator.h"
#include "chromeos/ash/components/login/auth/public/cryptohome_key_constants.h"
+#include "chromeos/ash/components/osauth/impl/auth_parts_impl.h"
+#include "chromeos/ash/components/osauth/impl/auth_session_storage_impl.h"
#include "chromeos/ash/services/device_sync/public/cpp/fake_device_sync_client.h"
#include "chromeos/ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h"
#include "chromeos/ash/services/secure_channel/public/cpp/client/fake_secure_channel_client.h"
@@ -202,6 +205,10 @@ class QuickUnlockPrivateUnitTest
fake_user_manager_ = fake_user_manager.get();
scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
std::move(fake_user_manager));
+ auth_parts_ = ash::AuthPartsImpl::CreateTestInstance();
+ auth_parts_->SetAuthSessionStorage(
+ std::make_unique<ash::AuthSessionStorageImpl>(
+ ash::UserDataAuthClient::Get()));
ExtensionApiUnittest::SetUp();
@@ -262,8 +269,14 @@ class QuickUnlockPrivateUnitTest
ash::AuthFactorsConfiguration());
}
- token_ = ash::quick_unlock::QuickUnlockFactory::GetForProfile(profile)
- ->CreateAuthToken(auth_token_user_context_);
+ if (ash::features::ShouldUseAuthSessionStorage()) {
+ token_ = ash::AuthSessionStorage::Get()->Store(
+ std::make_unique<ash::UserContext>(auth_token_user_context_));
+ } else {
+ token_ = ash::quick_unlock::QuickUnlockFactory::GetForProfile(profile)
+ ->CreateAuthToken(auth_token_user_context_);
+ }
+
base::RunLoop().RunUntilIdle();
return profile;
@@ -639,7 +652,8 @@ class QuickUnlockPrivateUnitTest
}
base::test::ScopedFeatureList feature_list_;
- raw_ptr<sync_preferences::TestingPrefServiceSyncable, ExperimentalAsh>
+ raw_ptr<sync_preferences::TestingPrefServiceSyncable,
+ DanglingUntriaged | ExperimentalAsh>
test_pref_service_;
private:
@@ -677,6 +691,7 @@ class QuickUnlockPrivateUnitTest
expect_modes_changed_ = false;
}
+ std::unique_ptr<ash::AuthPartsImpl> auth_parts_;
raw_ptr<ash::FakeChromeUserManager, ExperimentalAsh> fake_user_manager_ =
nullptr;
std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
@@ -695,8 +710,12 @@ TEST_P(QuickUnlockPrivateUnitTest, GetAuthTokenValid) {
ash::quick_unlock::QuickUnlockStorage* quick_unlock_storage =
ash::quick_unlock::QuickUnlockFactory::GetForProfile(profile());
- EXPECT_EQ(token_info->token,
- quick_unlock_storage->GetAuthToken()->Identifier());
+ if (ash::features::ShouldUseAuthSessionStorage()) {
+ EXPECT_TRUE(ash::AuthSessionStorage::Get()->IsValid(token_info->token));
+ } else {
+ EXPECT_EQ(token_info->token,
+ quick_unlock_storage->GetAuthToken()->Identifier());
+ }
EXPECT_EQ(token_info->lifetime_seconds,
ash::quick_unlock::AuthToken::kTokenExpiration.InSeconds());
}
diff --git a/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.cc b/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.cc
index bf66ae0ca12..f9c9848c791 100644
--- a/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.cc
+++ b/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.cc
@@ -14,11 +14,14 @@
#include "chrome/browser/ash/login/quick_unlock/quick_unlock_factory.h"
#include "chrome/browser/ash/login/quick_unlock/quick_unlock_storage.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/quick_unlock_private.h"
#include "chromeos/ash/components/login/auth/auth_performer.h"
#include "chromeos/ash/components/login/auth/extended_authenticator.h"
#include "chromeos/ash/components/login/auth/public/user_context.h"
+#include "chromeos/ash/components/osauth/public/auth_session_storage.h"
+#include "components/user_manager/known_user.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -75,8 +78,15 @@ void LegacyQuickUnlockPrivateGetAuthTokenHelper::OnAuthSuccess(
QuickUnlockStorage* quick_unlock_storage =
ash::quick_unlock::QuickUnlockFactory::GetForProfile(profile_);
quick_unlock_storage->MarkStrongAuth();
- token_info->token = quick_unlock_storage->CreateAuthToken(user_context);
- token_info->lifetime_seconds = AuthToken::kTokenExpiration.InSeconds();
+ if (ash::features::ShouldUseAuthSessionStorage()) {
+ token_info->token = ash::AuthSessionStorage::Get()->Store(
+ std::make_unique<ash::UserContext>(user_context));
+ // TODO(b/238606050): Determine authsession lifetime.
+ token_info->lifetime_seconds = AuthToken::kTokenExpiration.InSeconds();
+ } else {
+ token_info->token = quick_unlock_storage->CreateAuthToken(user_context);
+ token_info->lifetime_seconds = AuthToken::kTokenExpiration.InSeconds();
+ }
// The user has successfully authenticated, so we should reset pin/fingerprint
// attempt counts.
@@ -93,7 +103,8 @@ QuickUnlockPrivateGetAuthTokenHelper::QuickUnlockPrivateGetAuthTokenHelper(
std::string password)
: profile_(profile),
password_(std::move(password)),
- auth_performer_(ash::UserDataAuthClient::Get()) {}
+ auth_performer_(ash::UserDataAuthClient::Get()),
+ auth_factor_editor_(ash::UserDataAuthClient::Get()) {}
QuickUnlockPrivateGetAuthTokenHelper::~QuickUnlockPrivateGetAuthTokenHelper() =
default;
@@ -137,8 +148,9 @@ void QuickUnlockPrivateGetAuthTokenHelper::OnAuthSessionStarted(
return;
}
- const cryptohome::AuthFactor* password_factor =
- user_context->GetAuthFactorsData().FindOnlinePasswordFactor();
+ const auto* password_factor =
+ user_context->GetAuthFactorsData().FindFactorByType(
+ cryptohome::AuthFactorType::kPassword);
if (!password_factor) {
LOG(ERROR) << "Could not find password key";
std::move(callback).Run(
@@ -188,6 +200,14 @@ void QuickUnlockPrivateGetAuthTokenHelper::OnAuthFactorsConfiguration(
return;
}
+ // The user context stored in quick_unlock storage must have a device ID, so
+ // we retrieve and set it here.
+ user_manager::KnownUser known_user{g_browser_process->local_state()};
+ std::string device_id = known_user.GetDeviceId(user_context->GetAccountId());
+ LOG_IF(WARNING, device_id.empty())
+ << "Missing DeviceID for auth factor edits";
+ user_context->SetDeviceId(std::move(device_id));
+
QuickUnlockStorage* quick_unlock_storage =
ash::quick_unlock::QuickUnlockFactory::GetForProfile(profile_);
quick_unlock_storage->MarkStrongAuth();
@@ -197,9 +217,16 @@ void QuickUnlockPrivateGetAuthTokenHelper::OnAuthFactorsConfiguration(
quick_unlock_storage->fingerprint_storage()->ResetUnlockAttemptCount();
TokenInfo token_info;
- token_info.token =
- quick_unlock_storage->CreateAuthToken(std::move(*user_context));
- token_info.lifetime_seconds = AuthToken::kTokenExpiration.InSeconds();
+ if (ash::features::ShouldUseAuthSessionStorage()) {
+ token_info.token =
+ ash::AuthSessionStorage::Get()->Store(std::move(user_context));
+ // TODO(b/238606050): Determine authsession lifetime.
+ token_info.lifetime_seconds = AuthToken::kTokenExpiration.InSeconds();
+ } else {
+ token_info.token =
+ quick_unlock_storage->CreateAuthToken(std::move(*user_context));
+ token_info.lifetime_seconds = AuthToken::kTokenExpiration.InSeconds();
+ }
std::move(callback).Run(std::move(token_info), absl::nullopt);
}
diff --git a/chromium/chrome/browser/extensions/api/reading_list/OWNERS b/chromium/chrome/browser/extensions/api/reading_list/OWNERS
new file mode 100644
index 00000000000..a3823270d04
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/reading_list/OWNERS
@@ -0,0 +1,2 @@
+dljames@chromium.org
+dpenning@chromium.org
diff --git a/chromium/chrome/browser/extensions/api/reading_list/reading_list_api.cc b/chromium/chrome/browser/extensions/api/reading_list/reading_list_api.cc
new file mode 100644
index 00000000000..6fad2e28c28
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/reading_list/reading_list_api.cc
@@ -0,0 +1,266 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/reading_list/reading_list_api.h"
+
+#include "base/containers/flat_set.h"
+#include "base/time/time.h"
+#include "chrome/browser/extensions/api/reading_list/reading_list_api_constants.h"
+#include "chrome/browser/extensions/api/reading_list/reading_list_util.h"
+#include "chrome/browser/reading_list/reading_list_model_factory.h"
+#include "chrome/common/extensions/api/reading_list.h"
+#include "components/reading_list/core/reading_list_entry.h"
+#include "components/reading_list/core/reading_list_model.h"
+#include "components/reading_list/core/reading_list_model_observer.h"
+#include "extensions/browser/extension_function.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////// ReadingListAddEntryFunction //////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+ReadingListAddEntryFunction::ReadingListAddEntryFunction() = default;
+ReadingListAddEntryFunction::~ReadingListAddEntryFunction() = default;
+
+ExtensionFunction::ResponseAction ReadingListAddEntryFunction::Run() {
+ auto params = api::reading_list::AddEntry::Params::Create(args());
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ title_ = std::move(params->entry.title);
+ url_ = GURL(params->entry.url);
+ has_been_read_ = params->entry.has_been_read;
+
+ if (!url_.is_valid()) {
+ return RespondNow(Error(reading_list_api_constants::kInvalidURLError));
+ }
+
+ reading_list_model_ =
+ ReadingListModelFactory::GetForBrowserContext(browser_context());
+
+ if (!reading_list_model_->loaded()) {
+ reading_list_observation_.Observe(reading_list_model_);
+ AddRef();
+ return RespondLater();
+ }
+
+ auto response = AddEntryToReadingList();
+ return RespondNow(std::move(response));
+}
+
+void ReadingListAddEntryFunction::ReadingListModelLoaded(
+ const ReadingListModel* model) {
+ reading_list_observation_.Reset();
+ auto response = AddEntryToReadingList();
+ Respond(std::move(response));
+ Release(); // Balanced in Run().
+}
+
+ExtensionFunction::ResponseValue
+ReadingListAddEntryFunction::AddEntryToReadingList() {
+ if (!reading_list_model_->IsUrlSupported(url_)) {
+ return Error(reading_list_api_constants::kNotSupportedURLError);
+ }
+
+ if (reading_list_model_->GetEntryByURL(url_)) {
+ return Error(reading_list_api_constants::kDuplicateURLError);
+ }
+
+ reading_list_model_->AddOrReplaceEntry(
+ url_, title_, reading_list::EntrySource::ADDED_VIA_EXTENSION,
+ /*estimated_read_time=*/base::TimeDelta());
+ reading_list_model_->SetReadStatusIfExists(url_, has_been_read_);
+
+ return NoArguments();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////// ReadingListRemoveEntryFunction /////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+ReadingListRemoveEntryFunction::ReadingListRemoveEntryFunction() = default;
+ReadingListRemoveEntryFunction::~ReadingListRemoveEntryFunction() = default;
+
+ExtensionFunction::ResponseAction ReadingListRemoveEntryFunction::Run() {
+ auto params = api::reading_list::RemoveEntry::Params::Create(args());
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ url_ = GURL(params->info.url);
+ if (!url_.is_valid()) {
+ return RespondNow(Error(reading_list_api_constants::kInvalidURLError));
+ }
+
+ reading_list_model_ =
+ ReadingListModelFactory::GetForBrowserContext(browser_context());
+
+ if (!reading_list_model_->loaded()) {
+ reading_list_observation_.Observe(reading_list_model_);
+ AddRef();
+ return RespondLater();
+ }
+
+ auto response = RemoveEntryFromReadingList();
+ return RespondNow(std::move(response));
+}
+
+void ReadingListRemoveEntryFunction::ReadingListModelLoaded(
+ const ReadingListModel* model) {
+ reading_list_observation_.Reset();
+ auto response = RemoveEntryFromReadingList();
+ Respond(std::move(response));
+ Release(); // Balanced in Run().
+}
+
+ExtensionFunction::ResponseValue
+ReadingListRemoveEntryFunction::RemoveEntryFromReadingList() {
+ if (!reading_list_model_->IsUrlSupported(url_)) {
+ return Error(reading_list_api_constants::kNotSupportedURLError);
+ }
+
+ if (!reading_list_model_->GetEntryByURL(url_)) {
+ return Error(reading_list_api_constants::kURLNotFoundError);
+ }
+
+ reading_list_model_->RemoveEntryByURL(url_);
+
+ return NoArguments();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////// ReadingListUpdateEntryFunction /////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+ReadingListUpdateEntryFunction::ReadingListUpdateEntryFunction() = default;
+ReadingListUpdateEntryFunction::~ReadingListUpdateEntryFunction() = default;
+
+ExtensionFunction::ResponseAction ReadingListUpdateEntryFunction::Run() {
+ auto params = api::reading_list::UpdateEntry::Params::Create(args());
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ title_ = params->info.title;
+ has_been_read_ = params->info.has_been_read;
+
+ if (!title_.has_value() && !has_been_read_.has_value()) {
+ return RespondNow(Error(reading_list_api_constants::kNoUpdateProvided));
+ }
+
+ url_ = GURL(params->info.url);
+ if (!url_.is_valid()) {
+ return RespondNow(Error(reading_list_api_constants::kInvalidURLError));
+ }
+
+ reading_list_model_ =
+ ReadingListModelFactory::GetForBrowserContext(browser_context());
+
+ if (!reading_list_model_->loaded()) {
+ reading_list_observation_.Observe(reading_list_model_);
+ AddRef();
+ return RespondLater();
+ }
+
+ auto response = UpdateEntriesInTheReadingList();
+ return RespondNow(std::move(response));
+}
+
+void ReadingListUpdateEntryFunction::ReadingListModelLoaded(
+ const ReadingListModel* model) {
+ reading_list_observation_.Reset();
+ auto response = UpdateEntriesInTheReadingList();
+ Respond(std::move(response));
+ Release(); // Balanced in Run().
+}
+
+ExtensionFunction::ResponseValue
+ReadingListUpdateEntryFunction::UpdateEntriesInTheReadingList() {
+ if (!reading_list_model_->IsUrlSupported(url_)) {
+ return Error(reading_list_api_constants::kNotSupportedURLError);
+ }
+
+ if (!reading_list_model_->GetEntryByURL(url_)) {
+ return Error(reading_list_api_constants::kURLNotFoundError);
+ }
+
+ if (title_.has_value()) {
+ reading_list_model_->SetEntryTitleIfExists(url_, title_.value());
+ }
+
+ if (has_been_read_.has_value()) {
+ reading_list_model_->SetReadStatusIfExists(url_, has_been_read_.value());
+ }
+
+ return NoArguments();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////// ReadingListQueryFunction ///////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+ReadingListQueryFunction::ReadingListQueryFunction() = default;
+ReadingListQueryFunction::~ReadingListQueryFunction() = default;
+
+ExtensionFunction::ResponseAction ReadingListQueryFunction::Run() {
+ auto params = api::reading_list::Query::Params::Create(args());
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ if (params->info.url.has_value()) {
+ url_ = GURL(params->info.url.value());
+ if (!url_->is_valid()) {
+ return RespondNow(Error(reading_list_api_constants::kInvalidURLError));
+ }
+ }
+
+ title_ = params->info.title;
+ has_been_read_ = params->info.has_been_read;
+
+ reading_list_model_ =
+ ReadingListModelFactory::GetForBrowserContext(browser_context());
+
+ if (!reading_list_model_->loaded()) {
+ reading_list_observation_.Observe(reading_list_model_);
+ AddRef();
+ return RespondLater();
+ }
+
+ auto response = MatchEntries();
+ return RespondNow(std::move(response));
+}
+
+void ReadingListQueryFunction::ReadingListModelLoaded(
+ const ReadingListModel* model) {
+ reading_list_observation_.Reset();
+ auto response = MatchEntries();
+ Respond(std::move(response));
+ Release(); // Balanced in Run().
+}
+
+ExtensionFunction::ResponseValue ReadingListQueryFunction::MatchEntries() {
+ if (url_.has_value() && !reading_list_model_->IsUrlSupported(url_.value())) {
+ return Error(reading_list_api_constants::kNotSupportedURLError);
+ }
+
+ base::flat_set<GURL> urls = reading_list_model_->GetKeys();
+ std::vector<api::reading_list::ReadingListEntry> matching_entries;
+
+ for (const auto& url : urls) {
+ scoped_refptr<const ReadingListEntry> entry =
+ reading_list_model_->GetEntryByURL(url);
+
+ if (url_.has_value() && entry->URL() != url_) {
+ continue;
+ }
+ if (title_.has_value() && entry->Title() != title_) {
+ continue;
+ }
+ if (has_been_read_.has_value() && entry->IsRead() != has_been_read_) {
+ continue;
+ }
+ matching_entries.emplace_back(reading_list_util::ParseEntry(*entry));
+ }
+
+ return ArgumentList(
+ api::reading_list::Query::Results::Create(std::move(matching_entries)));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/reading_list/reading_list_api.h b/chromium/chrome/browser/extensions/api/reading_list/reading_list_api.h
new file mode 100644
index 00000000000..74288697206
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/reading_list/reading_list_api.h
@@ -0,0 +1,133 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_API_H_
+
+#include "base/scoped_observation.h"
+#include "components/reading_list/core/reading_list_model.h"
+#include "components/reading_list/core/reading_list_model_observer.h"
+#include "extensions/browser/extension_function.h"
+
+namespace extensions {
+
+class ReadingListAddEntryFunction : public ExtensionFunction,
+ public ReadingListModelObserver {
+ public:
+ DECLARE_EXTENSION_FUNCTION("readingList.addEntry", READINGLIST_ADDENTRY)
+
+ ReadingListAddEntryFunction();
+ ReadingListAddEntryFunction(const ReadingListAddEntryFunction&) = delete;
+ ReadingListAddEntryFunction& operator=(const ReadingListAddEntryFunction&) =
+ delete;
+
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ private:
+ ~ReadingListAddEntryFunction() override;
+
+ ResponseValue AddEntryToReadingList();
+
+ // ReadingListModelObserver:
+ void ReadingListModelLoaded(const ReadingListModel* model) override;
+
+ base::ScopedObservation<ReadingListModel, ReadingListModelObserver>
+ reading_list_observation_{this};
+ raw_ptr<ReadingListModel> reading_list_model_;
+ GURL url_;
+ std::string title_;
+ bool has_been_read_;
+};
+
+class ReadingListRemoveEntryFunction : public ExtensionFunction,
+ public ReadingListModelObserver {
+ public:
+ DECLARE_EXTENSION_FUNCTION("readingList.removeEntry", READINGLIST_REMOVEENTRY)
+
+ ReadingListRemoveEntryFunction();
+ ReadingListRemoveEntryFunction(const ReadingListRemoveEntryFunction&) =
+ delete;
+ ReadingListRemoveEntryFunction& operator=(
+ const ReadingListRemoveEntryFunction&) = delete;
+
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ private:
+ ~ReadingListRemoveEntryFunction() override;
+
+ ResponseValue RemoveEntryFromReadingList();
+
+ // ReadingListModelObserver:
+ void ReadingListModelLoaded(const ReadingListModel* model) override;
+
+ base::ScopedObservation<ReadingListModel, ReadingListModelObserver>
+ reading_list_observation_{this};
+ raw_ptr<ReadingListModel> reading_list_model_;
+ GURL url_;
+};
+
+class ReadingListUpdateEntryFunction : public ExtensionFunction,
+ public ReadingListModelObserver {
+ public:
+ DECLARE_EXTENSION_FUNCTION("readingList.updateEntry", READINGLIST_UPDATEENTRY)
+
+ ReadingListUpdateEntryFunction();
+ ReadingListUpdateEntryFunction(const ReadingListUpdateEntryFunction&) =
+ delete;
+ ReadingListUpdateEntryFunction& operator=(
+ const ReadingListUpdateEntryFunction&) = delete;
+
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ private:
+ ~ReadingListUpdateEntryFunction() override;
+
+ ResponseValue UpdateEntriesInTheReadingList();
+
+ // ReadingListModelObserver:
+ void ReadingListModelLoaded(const ReadingListModel* model) override;
+
+ base::ScopedObservation<ReadingListModel, ReadingListModelObserver>
+ reading_list_observation_{this};
+ raw_ptr<ReadingListModel> reading_list_model_;
+ GURL url_;
+ absl::optional<std::string> title_;
+ absl::optional<bool> has_been_read_;
+};
+
+class ReadingListQueryFunction : public ExtensionFunction,
+ public ReadingListModelObserver {
+ public:
+ DECLARE_EXTENSION_FUNCTION("readingList.query", READINGLIST_QUERY)
+
+ ReadingListQueryFunction();
+ ReadingListQueryFunction(const ReadingListQueryFunction&) = delete;
+ ReadingListQueryFunction& operator=(const ReadingListQueryFunction&) = delete;
+
+ // ExtensionFunction:
+ ResponseAction Run() override;
+
+ private:
+ ~ReadingListQueryFunction() override;
+
+ // Returns the entries that match the provided features.
+ ResponseValue MatchEntries();
+
+ // ReadingListModelObserver:
+ void ReadingListModelLoaded(const ReadingListModel* model) override;
+
+ base::ScopedObservation<ReadingListModel, ReadingListModelObserver>
+ reading_list_observation_{this};
+ raw_ptr<ReadingListModel> reading_list_model_;
+ absl::optional<GURL> url_;
+ absl::optional<std::string> title_;
+ absl::optional<bool> has_been_read_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_API_H_
diff --git a/chromium/chrome/browser/extensions/api/reading_list/reading_list_api_constants.cc b/chromium/chrome/browser/extensions/api/reading_list/reading_list_api_constants.cc
new file mode 100644
index 00000000000..f96e06c941b
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/reading_list/reading_list_api_constants.cc
@@ -0,0 +1,17 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/reading_list/reading_list_api_constants.h"
+
+namespace extensions::reading_list_api_constants {
+
+// Error messages.
+const char kInvalidURLError[] = "URL is not valid.";
+const char kNotSupportedURLError[] = "URL is not supported.";
+const char kDuplicateURLError[] = "Duplicate URL.";
+const char kURLNotFoundError[] = "URL not found.";
+const char kNoUpdateProvided[] =
+ "At least one of `title` or `hasBeenRead` must be provided.";
+
+} // namespace extensions::reading_list_api_constants
diff --git a/chromium/chrome/browser/extensions/api/reading_list/reading_list_api_constants.h b/chromium/chrome/browser/extensions/api/reading_list/reading_list_api_constants.h
new file mode 100644
index 00000000000..6a384f89d10
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/reading_list/reading_list_api_constants.h
@@ -0,0 +1,20 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_API_CONSTANTS_H_
+#define CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_API_CONSTANTS_H_
+
+// Constants used for the Reading List API.
+namespace extensions::reading_list_api_constants {
+
+// Error messages.
+extern const char kInvalidURLError[];
+extern const char kNotSupportedURLError[];
+extern const char kDuplicateURLError[];
+extern const char kURLNotFoundError[];
+extern const char kNoUpdateProvided[];
+
+} // namespace extensions::reading_list_api_constants
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_API_CONSTANTS_H_
diff --git a/chromium/chrome/browser/extensions/api/reading_list/reading_list_api_unittest.cc b/chromium/chrome/browser/extensions/api/reading_list/reading_list_api_unittest.cc
new file mode 100644
index 00000000000..de1b24b9173
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/reading_list/reading_list_api_unittest.cc
@@ -0,0 +1,538 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/reading_list/reading_list_api.h"
+
+#include <memory>
+
+#include "base/test/values_test_util.h"
+#include "base/time/time.h"
+#include "chrome/browser/extensions/api/reading_list/reading_list_api_constants.h"
+#include "chrome/browser/extensions/api/reading_list/reading_list_event_router.h"
+#include "chrome/browser/extensions/extension_service_test_base.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/reading_list/reading_list_model_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/extensions/api/reading_list.h"
+#include "chrome/test/base/test_browser_window.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/reading_list/core/reading_list_entry.h"
+#include "components/reading_list/core/reading_list_model.h"
+#include "components/reading_list/core/reading_list_test_utils.h"
+#include "components/version_info/channel.h"
+#include "content/public/browser/browser_context.h"
+#include "extensions/browser/api_test_utils.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/event_router_factory.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/test_event_router_observer.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/features/feature_channel.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+namespace {
+
+// Create an extension with "readingList" permission.
+scoped_refptr<const Extension> CreateReadingListExtension() {
+ return ExtensionBuilder("Extension with readingList permission")
+ .AddPermission("readingList")
+ .Build();
+}
+
+void AddReadingListEntry(ReadingListModel* reading_list_model,
+ const GURL& url,
+ const std::string& title,
+ bool has_been_read) {
+ reading_list_model->AddOrReplaceEntry(
+ url, title, reading_list::EntrySource::ADDED_VIA_CURRENT_APP,
+ base::TimeDelta());
+ reading_list_model->SetReadStatusIfExists(url, has_been_read);
+}
+
+std::unique_ptr<KeyedService> BuildReadingListEventRouter(
+ content::BrowserContext* context) {
+ return std::make_unique<ReadingListEventRouter>(context);
+}
+
+std::unique_ptr<KeyedService> BuildEventRouter(
+ content::BrowserContext* context) {
+ return std::make_unique<extensions::EventRouter>(
+ context, ExtensionPrefs::Get(context));
+}
+
+} // namespace
+
+class ReadingListApiUnitTest : public ExtensionServiceTestBase {
+ public:
+ ReadingListApiUnitTest() = default;
+ ReadingListApiUnitTest(const ReadingListApiUnitTest&) = delete;
+ ReadingListApiUnitTest& operator=(const ReadingListApiUnitTest&) = delete;
+ ~ReadingListApiUnitTest() override = default;
+
+ protected:
+ Browser* browser() { return browser_.get(); }
+ TestBrowserWindow* browser_window() { return browser_window_.get(); }
+
+ private:
+ void SetUp() override;
+ void TearDown() override;
+
+ std::unique_ptr<TestBrowserWindow> browser_window_;
+ std::unique_ptr<Browser> browser_;
+ ScopedCurrentChannel channel_{version_info::Channel::UNKNOWN};
+};
+
+void ReadingListApiUnitTest::SetUp() {
+ ExtensionServiceTestBase::SetUp();
+ InitializeEmptyExtensionService();
+
+ // Create a browser window.
+ browser_window_ = std::make_unique<TestBrowserWindow>();
+ Browser::CreateParams params(profile(), /*user_gesture*/ true);
+ params.type = Browser::TYPE_NORMAL;
+ params.window = browser_window_.get();
+ browser_ = std::unique_ptr<Browser>(Browser::Create(params));
+
+ ReadingListEventRouter::GetFactoryInstance()->SetTestingFactory(
+ browser_context(), base::BindRepeating(&BuildReadingListEventRouter));
+
+ EventRouterFactory::GetInstance()->SetTestingFactory(
+ browser_context(), base::BindRepeating(&BuildEventRouter));
+
+ // We need to call ReadingListEventRouterFactory::GetForProfile() in order to
+ // instantiate the keyed service, since it's not created by default in unit
+ // tests.
+ ReadingListEventRouter::Get(browser_context());
+}
+
+void ReadingListApiUnitTest::TearDown() {
+ browser_->tab_strip_model()->CloseAllTabs();
+ browser_.reset();
+ browser_window_.reset();
+ ExtensionServiceTestBase::TearDown();
+}
+
+// Test that it is possible to add a unique URL.
+TEST_F(ReadingListApiUnitTest, AddUniqueURL) {
+ scoped_refptr<const Extension> extension = CreateReadingListExtension();
+
+ static constexpr char kArgs[] =
+ R"([{
+ "url": "https://www.example.com",
+ "title": "example of title",
+ "hasBeenRead": false
+ }])";
+ auto function = base::MakeRefCounted<ReadingListAddEntryFunction>();
+ function->set_extension(extension);
+ ReadingListModel* reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ // Add the entry.
+ api_test_utils::RunFunction(function.get(), kArgs, profile(),
+ api_test_utils::FunctionMode::kNone);
+
+ EXPECT_EQ(reading_list_model->size(), 1u);
+
+ // Verify the features of the entry.
+ GURL url = GURL("https://www.example.com");
+ auto entry = reading_list_model->GetEntryByURL(url);
+ EXPECT_EQ(entry->URL(), url);
+ EXPECT_EQ(entry->Title(), "example of title");
+ EXPECT_FALSE(entry->IsRead());
+}
+
+// Test that it is possible to add an already read entry.
+TEST_F(ReadingListApiUnitTest, AddEntryThatHasBeenRead) {
+ scoped_refptr<const Extension> extension = CreateReadingListExtension();
+
+ static constexpr char kArgs[] =
+ R"([{
+ "url": "https://www.example.com",
+ "title": "example of title",
+ "hasBeenRead": true
+ }])";
+ auto function = base::MakeRefCounted<ReadingListAddEntryFunction>();
+ function->set_extension(extension);
+ ReadingListModel* reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ // Add the entry.
+ api_test_utils::RunFunction(function.get(), kArgs, profile(),
+ api_test_utils::FunctionMode::kNone);
+
+ EXPECT_EQ(reading_list_model->size(), 1u);
+
+ // Verify the features of the entry.
+ GURL url = GURL("https://www.example.com");
+ auto entry = reading_list_model->GetEntryByURL(url);
+ EXPECT_EQ(entry->URL(), url);
+ EXPECT_EQ(entry->Title(), "example of title");
+ EXPECT_TRUE(entry->IsRead());
+}
+
+// Test that adding a duplicate URL generates an error.
+TEST_F(ReadingListApiUnitTest, AddDuplicateURL) {
+ scoped_refptr<const Extension> extension = CreateReadingListExtension();
+
+ static constexpr char kArgs[] =
+ R"([{
+ "url": "https://www.example.com",
+ "title": "example of title",
+ "hasBeenRead": false
+ }])";
+ auto function = base::MakeRefCounted<ReadingListAddEntryFunction>();
+ function->set_extension(extension);
+ ReadingListModel* reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ // Add the entry.
+ api_test_utils::RunFunction(function.get(), kArgs, profile(),
+ api_test_utils::FunctionMode::kNone);
+
+ EXPECT_EQ(reading_list_model->size(), 1u);
+
+ // Verify the features of the entry.
+ GURL url = GURL("https://www.example.com");
+ auto entry = reading_list_model->GetEntryByURL(url);
+ EXPECT_EQ(entry->URL(), url);
+ EXPECT_EQ(entry->Title(), "example of title");
+ EXPECT_FALSE(entry->IsRead());
+
+ // Try to add a duplicate URL and expect an error.
+ function = base::MakeRefCounted<ReadingListAddEntryFunction>();
+ function->set_extension(extension);
+ std::string error = api_test_utils::RunFunctionAndReturnError(
+ function.get(), kArgs, profile(), api_test_utils::FunctionMode::kNone);
+ EXPECT_EQ(error, reading_list_api_constants::kDuplicateURLError);
+
+ // Review that the URL added earlier still exists and there is only 1 entry in
+ // the Reading List.
+ EXPECT_EQ(reading_list_model->size(), 1u);
+ entry = reading_list_model->GetEntryByURL(url);
+ EXPECT_EQ(entry->URL(), url);
+ EXPECT_EQ(entry->Title(), "example of title");
+ EXPECT_FALSE(entry->IsRead());
+}
+
+// Test that it is possible to remove a URL.
+TEST_F(ReadingListApiUnitTest, RemoveURL) {
+ scoped_refptr<const Extension> extension = CreateReadingListExtension();
+
+ ReadingListModel* reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ ReadingListLoadObserver(reading_list_model).Wait();
+
+ AddReadingListEntry(reading_list_model, GURL("https://www.example.com"),
+ "example of title", /*has_been_read=*/false);
+
+ // Verify that the entry has been added.
+ EXPECT_EQ(reading_list_model->size(), 1u);
+
+ // Remove the URL that was added before.
+ auto remove_function = base::MakeRefCounted<ReadingListRemoveEntryFunction>();
+ remove_function->set_extension(extension);
+ static constexpr char kArgs[] =
+ R"([{
+ "url": "https://www.example.com"
+ }])";
+ api_test_utils::RunFunction(remove_function.get(), kArgs, profile(),
+ api_test_utils::FunctionMode::kNone);
+
+ // Verify the size of the reading list model.
+ EXPECT_EQ(reading_list_model->size(), 0u);
+}
+
+// Test that trying to remove a URL that is not in the Reading List, generates
+// an error.
+TEST_F(ReadingListApiUnitTest, RemoveNonExistentURL) {
+ scoped_refptr<const Extension> extension = CreateReadingListExtension();
+
+ static constexpr char kArgs[] =
+ R"([{
+ "url": "https://www.example.com"
+ }])";
+ auto function = base::MakeRefCounted<ReadingListRemoveEntryFunction>();
+ function->set_extension(extension);
+
+ // Remove the entry.
+ std::string error = api_test_utils::RunFunctionAndReturnError(
+ function.get(), kArgs, profile(), api_test_utils::FunctionMode::kNone);
+ EXPECT_EQ(error, reading_list_api_constants::kURLNotFoundError);
+}
+
+// Test that it is possible to update the features of an entry.
+TEST_F(ReadingListApiUnitTest, UpdateEntryFeatures) {
+ scoped_refptr<const Extension> extension = CreateReadingListExtension();
+
+ ReadingListModel* reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ ReadingListLoadObserver(reading_list_model).Wait();
+
+ AddReadingListEntry(reading_list_model, GURL("https://www.example.com"),
+ "example of title", /*has_been_read=*/false);
+
+ // Verify that the entry has been added.
+ EXPECT_EQ(reading_list_model->size(), 1u);
+
+ // Update the entry that was added before.
+ auto update_function = base::MakeRefCounted<ReadingListUpdateEntryFunction>();
+ update_function->set_extension(extension);
+ static constexpr char kArgs[] =
+ R"([{
+ "url": "https://www.example.com",
+ "title": "Title",
+ "hasBeenRead": true
+ }])";
+ api_test_utils::RunFunction(update_function.get(), kArgs, profile(),
+ api_test_utils::FunctionMode::kNone);
+
+ // Verify that the size of the reading list model is still the same.
+ EXPECT_EQ(reading_list_model->size(), 1u);
+
+ // Verify the features of the entry.
+ GURL url = GURL("https://www.example.com");
+ auto entry = reading_list_model->GetEntryByURL(url);
+ EXPECT_EQ(entry->URL(), url);
+ EXPECT_EQ(entry->Title(), "Title");
+ EXPECT_TRUE(entry->IsRead());
+}
+
+// Test that trying to update an entry by providing only the URL, generates an
+// error.
+TEST_F(ReadingListApiUnitTest, UpdateEntryOnlyWithTheURL) {
+ scoped_refptr<const Extension> extension = CreateReadingListExtension();
+
+ ReadingListModel* reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ ReadingListLoadObserver(reading_list_model).Wait();
+
+ AddReadingListEntry(reading_list_model, GURL("https://www.example.com"),
+ "example of title", /*has_been_read=*/false);
+
+ // Verify that the entry has been added.
+ EXPECT_EQ(reading_list_model->size(), 1u);
+
+ // Update the entry that was added before.
+ auto update_function = base::MakeRefCounted<ReadingListUpdateEntryFunction>();
+ update_function->set_extension(extension);
+ static constexpr char kArgs[] =
+ R"([{
+ "url": "https://www.example.com",
+ }])";
+ std::string error = api_test_utils::RunFunctionAndReturnError(
+ update_function.get(), kArgs, profile(),
+ api_test_utils::FunctionMode::kNone);
+ EXPECT_EQ(error, reading_list_api_constants::kNoUpdateProvided);
+
+ // Verify that the size of the reading list model is still the same.
+ EXPECT_EQ(reading_list_model->size(), 1u);
+
+ // Verify the features of the entry.
+ GURL url = GURL("https://www.example.com");
+ auto entry = reading_list_model->GetEntryByURL(url);
+ EXPECT_EQ(entry->URL(), url);
+ EXPECT_EQ(entry->Title(), "example of title");
+ EXPECT_FALSE(entry->IsRead());
+}
+
+// Test that it is possible to retrieve all the entries.
+TEST_F(ReadingListApiUnitTest, RetrieveAllEntries) {
+ scoped_refptr<const Extension> extension = CreateReadingListExtension();
+
+ ReadingListModel* reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ ReadingListLoadObserver(reading_list_model).Wait();
+
+ AddReadingListEntry(reading_list_model, GURL("https://www.example.com"),
+ "example of title", /*has_been_read=*/false);
+ AddReadingListEntry(reading_list_model, GURL("https://www.example2.com"),
+ "Title #2", /*has_been_read=*/false);
+
+ // Verify that the entries have been added.
+ EXPECT_EQ(reading_list_model->size(), 2u);
+
+ // Retrieve all the entries in the Reading List.
+ auto update_function = base::MakeRefCounted<ReadingListQueryFunction>();
+ update_function->set_extension(extension);
+ static constexpr char kArgs[] = "[{}]";
+
+ auto entries = api_test_utils::RunFunctionAndReturnSingleResult(
+ update_function.get(), kArgs, profile(),
+ api_test_utils::FunctionMode::kNone);
+
+ // Verify that all the entries were retrieved.
+ EXPECT_EQ(entries.value().GetList().size(), 2u);
+
+ // Verify that the size of the reading list model is still the same.
+ EXPECT_EQ(reading_list_model->size(), 2u);
+}
+
+// Test that it is possible to retrieve entries with certain features.
+TEST_F(ReadingListApiUnitTest, RetrieveCertainEntries) {
+ scoped_refptr<const Extension> extension = CreateReadingListExtension();
+
+ ReadingListModel* reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ ReadingListLoadObserver(reading_list_model).Wait();
+
+ AddReadingListEntry(reading_list_model, GURL("https://www.example.com"),
+ "example of title", /*has_been_read=*/false);
+ AddReadingListEntry(reading_list_model, GURL("https://www.example2.com"),
+ "Example", /*has_been_read=*/false);
+ AddReadingListEntry(reading_list_model, GURL("https://www.example3.com"),
+ "Example", /*has_been_read=*/false);
+
+ // Verify that the entries have been added.
+ EXPECT_EQ(reading_list_model->size(), 3u);
+
+ // Retrieve entries whose title is "Example".
+ auto update_function = base::MakeRefCounted<ReadingListQueryFunction>();
+ update_function->set_extension(extension);
+ static constexpr char kArgs[] =
+ R"([{
+ "title": "Example"
+ }])";
+ auto entries = api_test_utils::RunFunctionAndReturnSingleResult(
+ update_function.get(), kArgs, profile(),
+ api_test_utils::FunctionMode::kNone);
+
+ // Verify only 2 entries were retrieved: example_2 and example_3.
+ ASSERT_EQ(entries.value().GetList().size(), 2u);
+
+ scoped_refptr<const ReadingListEntry> e2 =
+ reading_list_model->GetEntryByURL(GURL("https://www.example2.com"));
+ scoped_refptr<const ReadingListEntry> e3 =
+ reading_list_model->GetEntryByURL(GURL("https://www.example3.com"));
+
+ // Expect that the first entry is equivalent to `e2`.
+ absl::optional<api::reading_list::ReadingListEntry> entry1_actual =
+ api::reading_list::ReadingListEntry::FromValue(entries->GetList()[0]);
+ int64_t e2_update_in_milliseconds =
+ base::Microseconds(e2->UpdateTime()).InMilliseconds();
+ int64_t e2_creation_in_milliseconds =
+ base::Microseconds(e2->CreationTime()).InMilliseconds();
+ EXPECT_EQ(entry1_actual->url, e2->URL().spec());
+ EXPECT_EQ(entry1_actual->title, e2->Title());
+ EXPECT_EQ(entry1_actual->has_been_read, e2->IsRead());
+ EXPECT_EQ(entry1_actual->last_update_time, e2_update_in_milliseconds);
+ EXPECT_EQ(entry1_actual->creation_time, e2_creation_in_milliseconds);
+
+ // Expect that the second entry is equivalent to `e3`.
+ absl::optional<api::reading_list::ReadingListEntry> entry2_actual =
+ api::reading_list::ReadingListEntry::FromValue(entries->GetList()[1]);
+ int64_t e3_update_in_milliseconds =
+ base::Microseconds(e3->UpdateTime()).InMilliseconds();
+ int64_t e3_creation_in_milliseconds =
+ base::Microseconds(e3->CreationTime()).InMilliseconds();
+ EXPECT_EQ(entry2_actual->url, e3->URL().spec());
+ EXPECT_EQ(entry2_actual->title, e3->Title());
+ EXPECT_EQ(entry2_actual->has_been_read, e3->IsRead());
+ EXPECT_EQ(entry2_actual->last_update_time, e3_update_in_milliseconds);
+ EXPECT_EQ(entry2_actual->creation_time, e3_creation_in_milliseconds);
+
+ EXPECT_EQ(reading_list_model->size(), 3u);
+}
+
+// Test that a query can return no matching entries.
+TEST_F(ReadingListApiUnitTest, NoEntriesRetrieved) {
+ scoped_refptr<const Extension> extension = CreateReadingListExtension();
+
+ ReadingListModel* reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ ReadingListLoadObserver(reading_list_model).Wait();
+
+ AddReadingListEntry(reading_list_model, GURL("https://www.example.com"),
+ "example of title", /*has_been_read=*/false);
+
+ // Query for an entry.
+ auto update_function = base::MakeRefCounted<ReadingListQueryFunction>();
+ update_function->set_extension(extension);
+ static constexpr char kArgs[] =
+ R"([{
+ "url": "https://www.example.com",
+ "title": "Title",
+ "hasBeenRead": false
+ }])";
+ auto entries = api_test_utils::RunFunctionAndReturnSingleResult(
+ update_function.get(), kArgs, profile(),
+ api_test_utils::FunctionMode::kNone);
+
+ EXPECT_EQ(entries.value().GetList().size(), 0u);
+}
+
+// Test that adding an entry generates an event.
+TEST_F(ReadingListApiUnitTest, ReadingListOnEntryAdded) {
+ TestEventRouterObserver event_observer(EventRouter::Get(browser_context()));
+
+ ReadingListModel* const reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ ReadingListLoadObserver(reading_list_model).Wait();
+
+ AddReadingListEntry(reading_list_model, GURL("https://www.example.com"),
+ "example of title", /*has_been_read=*/false);
+
+ EXPECT_EQ(reading_list_model->size(), 1u);
+
+ EXPECT_TRUE(base::Contains(event_observer.events(),
+ api::reading_list::OnEntryAdded::kEventName));
+}
+
+// Test that removing an entry generates an event.
+TEST_F(ReadingListApiUnitTest, ReadingListOnEntryRemoved) {
+ ReadingListModel* const reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ ReadingListLoadObserver(reading_list_model).Wait();
+
+ const GURL url = GURL("https://www.example.com");
+
+ AddReadingListEntry(reading_list_model, url, "example of title",
+ /*has_been_read=*/false);
+ EXPECT_EQ(reading_list_model->size(), 1u);
+
+ TestEventRouterObserver event_observer(EventRouter::Get(browser_context()));
+
+ reading_list_model->RemoveEntryByURL(url);
+ EXPECT_EQ(reading_list_model->size(), 0u);
+
+ EXPECT_EQ(event_observer.events().size(), 1u);
+ EXPECT_TRUE(base::Contains(event_observer.events(),
+ api::reading_list::OnEntryRemoved::kEventName));
+}
+
+// Test that updating an entry generates an event.
+TEST_F(ReadingListApiUnitTest, ReadingListOnEntryUpdated) {
+ ReadingListModel* const reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+
+ ReadingListLoadObserver(reading_list_model).Wait();
+
+ const GURL url = GURL("https://www.example.com");
+
+ AddReadingListEntry(reading_list_model, url, "example of title",
+ /*has_been_read=*/false);
+ EXPECT_EQ(reading_list_model->size(), 1u);
+ EXPECT_EQ(reading_list_model->GetEntryByURL(url)->Title(),
+ "example of title");
+
+ TestEventRouterObserver event_observer(EventRouter::Get(browser_context()));
+
+ reading_list_model->SetEntryTitleIfExists(url, "New title");
+ EXPECT_EQ(reading_list_model->GetEntryByURL(url)->Title(), "New title");
+
+ EXPECT_EQ(event_observer.events().size(), 1u);
+ EXPECT_TRUE(base::Contains(event_observer.events(),
+ api::reading_list::OnEntryUpdated::kEventName));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/reading_list/reading_list_apitest.cc b/chromium/chrome/browser/extensions/api/reading_list/reading_list_apitest.cc
new file mode 100644
index 00000000000..4bc8e8034bb
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/reading_list/reading_list_apitest.cc
@@ -0,0 +1,67 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/reading_list/reading_list_model_factory.h"
+#include "chrome/common/extensions/api/reading_list.h"
+#include "components/reading_list/core/reading_list_model.h"
+#include "content/public/test/browser_test.h"
+#include "extensions/browser/test_event_router_observer.h"
+
+namespace extensions {
+
+namespace {
+
+using ReadingListApiTest = ExtensionApiTest;
+
+IN_PROC_BROWSER_TEST_F(ReadingListApiTest, TestReadingListWorks) {
+ ASSERT_TRUE(RunExtensionTest("reading_list")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ReadingListApiTest,
+ TestReadingListEventsAcrossProfiles) {
+ // The EventRouter is shared between on- and off-the-record profiles, so
+ // this observer will catch events for each.
+ TestEventRouterObserver event_observer(EventRouter::Get(profile()));
+
+ // Add a Reading List entry in a normal browser.
+ ReadingListModel* const reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(profile());
+ reading_list_model->AddOrReplaceEntry(
+ GURL("https://www.example.com"), "example of title",
+ reading_list::EntrySource::ADDED_VIA_CURRENT_APP, base::TimeDelta());
+
+ ASSERT_TRUE(base::Contains(event_observer.events(),
+ api::reading_list::OnEntryAdded::kEventName));
+ Event* normal_event = event_observer.events()
+ .at(api::reading_list::OnEntryAdded::kEventName)
+ .get();
+ EXPECT_EQ(normal_event->restrict_to_browser_context, profile());
+
+ event_observer.ClearEvents();
+ ASSERT_FALSE(base::Contains(event_observer.events(),
+ api::reading_list::OnEntryAdded::kEventName));
+
+ const Browser* const incognito_browser = CreateIncognitoBrowser(profile());
+
+ // Add a Reading List entry in an incognito browser.
+ ReadingListModel* const incognito_reading_list_model =
+ ReadingListModelFactory::GetForBrowserContext(
+ incognito_browser->profile());
+ incognito_reading_list_model->AddOrReplaceEntry(
+ GURL("https://www.example.com"), "example of title",
+ reading_list::EntrySource::ADDED_VIA_CURRENT_APP, base::TimeDelta());
+
+ ASSERT_TRUE(base::Contains(event_observer.events(),
+ api::reading_list::OnEntryAdded::kEventName));
+ Event* incognito_event = event_observer.events()
+ .at(api::reading_list::OnEntryAdded::kEventName)
+ .get();
+ EXPECT_EQ(incognito_event->restrict_to_browser_context,
+ incognito_browser->profile());
+}
+
+} // namespace
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/reading_list/reading_list_event_router.cc b/chromium/chrome/browser/extensions/api/reading_list/reading_list_event_router.cc
new file mode 100644
index 00000000000..32d1fa3935d
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/reading_list/reading_list_event_router.cc
@@ -0,0 +1,143 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/reading_list/reading_list_event_router.h"
+
+#include "base/no_destructor.h"
+#include "chrome/browser/extensions/api/reading_list/reading_list_util.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
+#include "chrome/browser/reading_list/reading_list_model_factory.h"
+#include "chrome/common/extensions/api/reading_list.h"
+#include "components/reading_list/core/reading_list_entry.h"
+#include "components/reading_list/core/reading_list_model.h"
+#include "content/public/browser/browser_context.h"
+#include "extensions/browser/event_router_factory.h"
+
+namespace extensions {
+
+namespace {
+
+// The factory responsible for creating the per-profile event router for the
+// ReadingList API.
+class ReadingListEventRouterFactory : public ProfileKeyedServiceFactory {
+ public:
+ ReadingListEventRouterFactory();
+ ReadingListEventRouterFactory(const ReadingListEventRouterFactory&) = delete;
+ ReadingListEventRouterFactory& operator=(
+ const ReadingListEventRouterFactory&) = delete;
+ ~ReadingListEventRouterFactory() override = default;
+
+ // Given a browser context, returns the corresponding ReadingListEventRouter.
+ ReadingListEventRouter* GetForProfile(content::BrowserContext* context);
+
+ private:
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* profile) const override;
+ bool ServiceIsCreatedWithBrowserContext() const override;
+ bool ServiceIsNULLWhileTesting() const override;
+};
+
+ReadingListEventRouterFactory::ReadingListEventRouterFactory()
+ : ProfileKeyedServiceFactory(
+ "ReadingListEventRouter",
+ ProfileSelections::BuildForRegularAndIncognito()) {
+ DependsOn(EventRouterFactory::GetInstance());
+ DependsOn(ReadingListModelFactory::GetInstance());
+}
+
+ReadingListEventRouter* ReadingListEventRouterFactory::GetForProfile(
+ content::BrowserContext* context) {
+ return static_cast<ReadingListEventRouter*>(
+ GetServiceForBrowserContext(context, /*create=*/true));
+}
+
+KeyedService* ReadingListEventRouterFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new ReadingListEventRouter(context);
+}
+
+bool ReadingListEventRouterFactory::ServiceIsCreatedWithBrowserContext() const {
+ return true;
+}
+
+// Since there is a dependency on `EventRouter` that is null by default in unit
+// tests, this service needs to be null as well. If we want to enable it in a
+// specific test we need to override the factories for both `EventRouter` and
+// this factory to enforce the service creation.
+bool ReadingListEventRouterFactory::ServiceIsNULLWhileTesting() const {
+ return true;
+}
+
+} // namespace
+
+ReadingListEventRouter::ReadingListEventRouter(
+ content::BrowserContext* browser_context)
+ : reading_list_model_(
+ ReadingListModelFactory::GetForBrowserContext(browser_context)),
+ profile_(Profile::FromBrowserContext(browser_context)),
+ event_router_(EventRouter::Get(browser_context)) {
+ reading_list_observation_.Observe(reading_list_model_);
+}
+
+ReadingListEventRouter::~ReadingListEventRouter() = default;
+
+// static
+ReadingListEventRouter* ReadingListEventRouter::Get(
+ content::BrowserContext* browser_context) {
+ return static_cast<ReadingListEventRouterFactory*>(GetFactoryInstance())
+ ->GetForProfile(browser_context);
+}
+
+// static
+ProfileKeyedServiceFactory* ReadingListEventRouter::GetFactoryInstance() {
+ static base::NoDestructor<ReadingListEventRouterFactory> factory;
+ return factory.get();
+}
+
+void ReadingListEventRouter::ReadingListDidAddEntry(
+ const ReadingListModel* model,
+ const GURL& url,
+ reading_list::EntrySource source) {
+ auto args(api::reading_list::OnEntryAdded::Create(
+ reading_list_util::ParseEntry(*model->GetEntryByURL(url))));
+
+ DispatchEvent(events::READING_LIST_ON_ENTRY_ADDED,
+ api::reading_list::OnEntryAdded::kEventName, std::move(args));
+}
+
+void ReadingListEventRouter::ReadingListWillRemoveEntry(
+ const ReadingListModel* model,
+ const GURL& url) {
+ auto args(api::reading_list::OnEntryRemoved::Create(
+ reading_list_util::ParseEntry(*model->GetEntryByURL(url))));
+
+ // Even though we dispatch the event in ReadingListWillRemoveEntry() (i.e.,
+ // the entry is still in the model at this point), we can safely dispatch it
+ // as `onEntryRemoved` (past tense) to the extension. The entry is removed
+ // synchronously after this, so there's no way the extension could still
+ // see the entry in the list.
+ DispatchEvent(events::READING_LIST_ON_ENTRY_REMOVED,
+ api::reading_list::OnEntryRemoved::kEventName, std::move(args));
+}
+
+void ReadingListEventRouter::ReadingListDidUpdateEntry(
+ const ReadingListModel* model,
+ const GURL& url) {
+ auto args(api::reading_list::OnEntryUpdated::Create(
+ reading_list_util::ParseEntry(*model->GetEntryByURL(url))));
+
+ DispatchEvent(events::READING_LIST_ON_ENTRY_UPDATED,
+ api::reading_list::OnEntryUpdated::kEventName, std::move(args));
+}
+
+void ReadingListEventRouter::DispatchEvent(
+ events::HistogramValue histogram_value,
+ const std::string& event_name,
+ base::Value::List args) {
+ event_router_->BroadcastEvent(std::make_unique<Event>(
+ histogram_value, event_name, std::move(args), profile_));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/reading_list/reading_list_event_router.h b/chromium/chrome/browser/extensions/api/reading_list/reading_list_event_router.h
new file mode 100644
index 00000000000..20e8e8427f8
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/reading_list/reading_list_event_router.h
@@ -0,0 +1,67 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_EVENT_ROUTER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_EVENT_ROUTER_H_
+
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/reading_list/core/reading_list_entry.h"
+#include "components/reading_list/core/reading_list_model_observer.h"
+#include "content/public/browser/browser_context.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_event_histogram_value.h"
+
+class ProfileKeyedServiceFactory;
+
+namespace extensions {
+
+// The ReadingListEventRouter listens for reading list events and notifies
+// observers of the changes.
+class ReadingListEventRouter : public KeyedService,
+ public ReadingListModelObserver {
+ public:
+ explicit ReadingListEventRouter(content::BrowserContext* browser_context);
+ ReadingListEventRouter(const ReadingListEventRouter&) = delete;
+ ReadingListEventRouter& operator=(const ReadingListEventRouter&) = delete;
+ ~ReadingListEventRouter() override;
+
+ static ReadingListEventRouter* Get(content::BrowserContext* browser_context);
+
+ static ProfileKeyedServiceFactory* GetFactoryInstance();
+
+ private:
+ // ReadingListModelObserver:
+ void ReadingListModelLoaded(const ReadingListModel* model) override{};
+ void ReadingListDidAddEntry(const ReadingListModel* model,
+ const GURL& url,
+ reading_list::EntrySource source) override;
+ void ReadingListWillRemoveEntry(const ReadingListModel* model,
+ const GURL& url) override;
+ void ReadingListDidUpdateEntry(const ReadingListModel* model,
+ const GURL& url) override;
+
+ void DispatchEvent(events::HistogramValue histogram_value,
+ const std::string& event_name,
+ base::Value::List args);
+
+ base::ScopedObservation<ReadingListModel, ReadingListModelObserver>
+ reading_list_observation_{this};
+
+ // Guaranteed to outlive this object since it is declared as a KeyedService
+ // dependency.
+ raw_ptr<ReadingListModel> reading_list_model_;
+
+ // Guaranteed to outlive this object since it is declared as a KeyedService
+ // dependency.
+ raw_ptr<Profile> const profile_;
+
+ // Notifies observers of events associated with the profile. Guaranteed to
+ // outlive this object since it is declared as a KeyedService dependency.
+ raw_ptr<EventRouter> const event_router_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_EVENT_ROUTER_H_
diff --git a/chromium/chrome/browser/extensions/api/reading_list/reading_list_util.cc b/chromium/chrome/browser/extensions/api/reading_list/reading_list_util.cc
new file mode 100644
index 00000000000..7c4db3edbf9
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/reading_list/reading_list_util.cc
@@ -0,0 +1,24 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/reading_list/reading_list_util.h"
+#include "base/time/time.h"
+
+namespace extensions::reading_list_util {
+
+api::reading_list::ReadingListEntry ParseEntry(const ReadingListEntry& entry) {
+ api::reading_list::ReadingListEntry reading_list_entry;
+
+ reading_list_entry.url = entry.URL().spec();
+ reading_list_entry.title = entry.Title();
+ reading_list_entry.has_been_read = entry.IsRead();
+ reading_list_entry.last_update_time =
+ base::Microseconds(entry.UpdateTime()).InMilliseconds();
+ reading_list_entry.creation_time =
+ base::Microseconds(entry.CreationTime()).InMilliseconds();
+
+ return reading_list_entry;
+}
+
+} // namespace extensions::reading_list_util
diff --git a/chromium/chrome/browser/extensions/api/reading_list/reading_list_util.h b/chromium/chrome/browser/extensions/api/reading_list/reading_list_util.h
new file mode 100644
index 00000000000..ad50c345379
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/reading_list/reading_list_util.h
@@ -0,0 +1,18 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_UTIL_H_
+#define CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_UTIL_H_
+
+#include "chrome/common/extensions/api/reading_list.h"
+#include "components/reading_list/core/reading_list_entry.h"
+
+namespace extensions::reading_list_util {
+
+// Converts from ReadingListEntry to api::reading_list::ReadingListEntry.
+api::reading_list::ReadingListEntry ParseEntry(const ReadingListEntry& entry);
+
+} // namespace extensions::reading_list_util
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_READING_LIST_READING_LIST_UTIL_H_
diff --git a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.cc b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.cc
index 4c807188e08..6b2aaa005f3 100644
--- a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.cc
+++ b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.cc
@@ -48,9 +48,10 @@ SafeBrowsingPrivateEventRouterFactory::SafeBrowsingPrivateEventRouterFactory()
SafeBrowsingPrivateEventRouterFactory::
~SafeBrowsingPrivateEventRouterFactory() = default;
-KeyedService* SafeBrowsingPrivateEventRouterFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+SafeBrowsingPrivateEventRouterFactory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const {
- return new SafeBrowsingPrivateEventRouter(context);
+ return std::make_unique<SafeBrowsingPrivateEventRouter>(context);
}
bool SafeBrowsingPrivateEventRouterFactory::ServiceIsCreatedWithBrowserContext()
diff --git a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h
index 4c85cb71b32..f8cfef70def 100644
--- a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h
+++ b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h
@@ -43,7 +43,7 @@ class SafeBrowsingPrivateEventRouterFactory
~SafeBrowsingPrivateEventRouterFactory() override;
// BrowserContextKeyedServiceFactory:
- KeyedService* BuildServiceInstanceFor(
+ std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
content::BrowserContext* profile) const override;
};
diff --git a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_util.cc b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_util.cc
index ecd466ce7ec..2756fbec578 100644
--- a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_util.cc
+++ b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_util.cc
@@ -101,6 +101,11 @@ safe_browsing_private::ReferrerChainEntry ReferrerToReferrerChainEntry(
entry.navigation_initiation = safe_browsing_private::
NAVIGATION_INITIATION_COPY_PASTE_USER_INITIATED;
break;
+ case safe_browsing::
+ ReferrerChainEntry_NavigationInitiation_NOTIFICATION_INITIATED:
+ entry.navigation_initiation =
+ safe_browsing_private::NAVIGATION_INITIATION_NOTIFICATION_INITIATED;
+ break;
case safe_browsing::ReferrerChainEntry_NavigationInitiation_UNDEFINED:
NOTREACHED();
}
diff --git a/chromium/chrome/browser/extensions/api/scripting/scripting_api.cc b/chromium/chrome/browser/extensions/api/scripting/scripting_api.cc
index 77d0b1ccb6d..9459dec59b0 100644
--- a/chromium/chrome/browser/extensions/api/scripting/scripting_api.cc
+++ b/chromium/chrome/browser/extensions/api/scripting/scripting_api.cc
@@ -16,11 +16,10 @@
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/common/extensions/api/scripting.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "extensions/browser/api/scripting/scripting_constants.h"
+#include "extensions/browser/api/scripting/scripting_utils.h"
#include "extensions/browser/extension_api_frame_id_map.h"
#include "extensions/browser/extension_file_task_runner.h"
#include "extensions/browser/extension_system.h"
@@ -37,8 +36,8 @@
#include "extensions/common/mojom/execution_world.mojom-shared.h"
#include "extensions/common/mojom/host_id.mojom.h"
#include "extensions/common/mojom/run_location.mojom-shared.h"
-#include "extensions/common/permissions/api_permission.h"
#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/common/user_script.h"
#include "extensions/common/utils/content_script_utils.h"
#include "extensions/common/utils/extension_types_utils.h"
@@ -51,9 +50,6 @@ constexpr char kDuplicateFileSpecifiedError[] =
"Duplicate file specified: '*'.";
constexpr char kExactlyOneOfCssAndFilesError[] =
"Exactly one of 'css' and 'files' must be specified.";
-constexpr char kFilesExceededSizeLimitError[] =
- "Scripts could not be loaded because '*' exceeds the maximum script size "
- "or the extension's maximum total script size.";
// Note: CSS always injects as soon as possible, so we default to
// document_start. Because of tab loading, there's no guarantee this will
@@ -500,37 +496,12 @@ std::unique_ptr<UserScript> ParseUserScript(
return result;
}
-ValidateContentScriptsResult ValidateParsedScriptsOnFileThread(
- ExtensionResource::SymlinkPolicy symlink_policy,
- std::unique_ptr<UserScriptList> scripts) {
- DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence());
-
- // Validate that claimed script resources actually exist, and are UTF-8
- // encoded.
- std::string error;
- std::vector<InstallWarning> warnings;
- bool are_script_files_valid = script_parsing::ValidateFileSources(
- *scripts, symlink_policy, &error, &warnings);
-
- // Script files over the per script/extension limit are recorded as warnings.
- // However, for the scripting API we should treat "install warnings" as
- // errors by turning this call into a no-op and returning an error.
- if (!warnings.empty() && error.empty()) {
- error = ErrorUtils::FormatErrorMessage(kFilesExceededSizeLimitError,
- warnings[0].specific);
- are_script_files_valid = false;
- }
-
- return std::make_pair(std::move(scripts), are_script_files_valid
- ? absl::nullopt
- : absl::make_optional(error));
-}
-
// Converts a UserScript object to a api::scripting::RegisteredContentScript
// object, used for getRegisteredContentScripts.
api::scripting::RegisteredContentScript CreateRegisteredContentScriptInfo(
const UserScript& script) {
api::scripting::RegisteredContentScript script_info;
+ CHECK_EQ(UserScript::Source::kDynamicContentScript, script.GetSource());
script_info.id = script.id();
script_info.matches.emplace();
@@ -936,32 +907,25 @@ ScriptingRegisterContentScriptsFunction::Run() {
std::vector<api::scripting::RegisteredContentScript>& scripts =
params->scripts;
-
ExtensionUserScriptLoader* loader =
ExtensionSystem::Get(browser_context())
->user_script_manager()
->GetUserScriptLoaderForExtension(extension()->id());
- std::set<std::string> existing_script_ids = loader->GetDynamicScriptIDs();
- std::set<std::string> new_script_ids;
- for (const auto& script : scripts) {
- if (script.id.empty())
- return RespondNow(Error("Content script's ID must not be empty"));
-
- if (script.id[0] == UserScript::kGeneratedIDPrefix) {
- return RespondNow(Error(base::StringPrintf(
- "Content script's ID '%s' must not start with '%c'",
- script.id.c_str(), UserScript::kGeneratedIDPrefix)));
- }
- if (base::Contains(existing_script_ids, script.id) ||
- base::Contains(new_script_ids, script.id)) {
- return RespondNow(Error(
- base::StringPrintf("Duplicate script ID '%s'", script.id.c_str())));
- }
-
- new_script_ids.insert(script.id);
+ // Create script ids for dynamic content scripts.
+ std::string error;
+ std::set<std::string> existing_script_ids =
+ loader->GetDynamicScriptIDs(UserScript::Source::kDynamicContentScript);
+ std::set<std::string> new_script_ids = scripting::CreateDynamicScriptIds(
+ scripts, UserScript::Source::kDynamicContentScript, existing_script_ids,
+ &error);
+
+ if (!error.empty()) {
+ CHECK(new_script_ids.empty());
+ return RespondNow(Error(std::move(error)));
}
+ // Parse content scripts.
std::u16string parse_error;
auto parsed_scripts = std::make_unique<UserScriptList>();
std::set<std::string> persistent_script_ids;
@@ -971,12 +935,13 @@ ScriptingRegisterContentScriptsFunction::Run() {
parsed_scripts->reserve(scripts.size());
for (size_t i = 0; i < scripts.size(); ++i) {
if (!scripts[i].matches) {
+ std::string error_script_id =
+ UserScript::TrimPrefixFromScriptID(scripts[i].id);
return RespondNow(
Error(base::StringPrintf("Script with ID '%s' must specify 'matches'",
- scripts[i].id.c_str())));
+ error_script_id.c_str())));
}
- // Parse/Create user script.
std::unique_ptr<UserScript> user_script =
ParseUserScript(browser_context(), *extension(), scripts[i], i,
valid_schemes, &parse_error);
@@ -997,7 +962,7 @@ ScriptingRegisterContentScriptsFunction::Run() {
GetExtensionFileTaskRunner()->PostTaskAndReplyWithResult(
FROM_HERE,
- base::BindOnce(&ValidateParsedScriptsOnFileThread,
+ base::BindOnce(&scripting::ValidateParsedScriptsOnFileThread,
script_parsing::GetSymlinkPolicy(extension()),
std::move(parsed_scripts)),
base::BindOnce(&ScriptingRegisterContentScriptsFunction::
@@ -1012,10 +977,11 @@ ScriptingRegisterContentScriptsFunction::Run() {
void ScriptingRegisterContentScriptsFunction::OnContentScriptFilesValidated(
std::set<std::string> persistent_script_ids,
- ValidateContentScriptsResult result) {
+ scripting::ValidateScriptsResult result) {
// We cannot proceed if the `browser_context` is not valid as the
// `ExtensionSystem` will not exist.
if (!browser_context()) {
+ Release(); // Matches the `AddRef()` in `Run()`.
return;
}
@@ -1028,8 +994,9 @@ void ScriptingRegisterContentScriptsFunction::OnContentScriptFilesValidated(
if (error.has_value()) {
std::set<std::string> ids_to_remove;
- for (const auto& script : *scripts)
+ for (const auto& script : *scripts) {
ids_to_remove.insert(script->id());
+ }
loader->RemovePendingDynamicScriptIDs(std::move(ids_to_remove));
Respond(Error(std::move(*error)));
@@ -1068,8 +1035,10 @@ ScriptingGetRegisteredContentScriptsFunction::Run() {
params->filter;
std::set<std::string> id_filter;
if (filter && filter->ids) {
- id_filter.insert(std::make_move_iterator(filter->ids->begin()),
- std::make_move_iterator(filter->ids->end()));
+ for (const std::string& id : *(filter->ids)) {
+ id_filter.insert(scripting::AddPrefixToDynamicScriptId(
+ id, UserScript::Source::kDynamicContentScript));
+ }
}
ExtensionUserScriptLoader* loader =
@@ -1082,12 +1051,22 @@ ScriptingGetRegisteredContentScriptsFunction::Run() {
std::set<std::string> persistent_script_ids =
loader->GetPersistentDynamicScriptIDs();
for (const std::unique_ptr<UserScript>& script : dynamic_scripts) {
- if (id_filter.empty() || base::Contains(id_filter, script->id())) {
- auto registered_script = CreateRegisteredContentScriptInfo(*script);
- registered_script.persist_across_sessions =
- base::Contains(persistent_script_ids, script->id());
- script_infos.push_back(std::move(registered_script));
+ if (script->GetSource() != UserScript::Source::kDynamicContentScript) {
+ continue;
}
+
+ if (!id_filter.empty() && !base::Contains(id_filter, script->id())) {
+ continue;
+ }
+
+ auto registered_script = CreateRegisteredContentScriptInfo(*script);
+ registered_script.persist_across_sessions =
+ base::Contains(persistent_script_ids, script->id());
+
+ // Remove the internally used prefix from the `script`'s ID before
+ // returning.
+ registered_script.id = script->GetIDWithoutPrefix();
+ script_infos.push_back(std::move(registered_script));
}
return RespondNow(
@@ -1107,41 +1086,26 @@ ScriptingUnregisterContentScriptsFunction::Run() {
EXTENSION_FUNCTION_VALIDATE(params);
absl::optional<api::scripting::ContentScriptFilter>& filter = params->filter;
- std::set<std::string> ids_to_remove;
-
- ExtensionUserScriptLoader* loader =
- ExtensionSystem::Get(browser_context())
- ->user_script_manager()
- ->GetUserScriptLoaderForExtension(extension()->id());
- std::set<std::string> existing_script_ids = loader->GetDynamicScriptIDs();
- if (filter && filter->ids) {
- for (const auto& id : *filter->ids) {
- if (UserScript::IsIDGenerated(id)) {
- return RespondNow(Error(base::StringPrintf(
- "Content script's ID '%s' must not start with '%c'", id.c_str(),
- UserScript::kGeneratedIDPrefix)));
- }
-
- if (!base::Contains(existing_script_ids, id)) {
- return RespondNow(Error(
- base::StringPrintf("Nonexistent script ID '%s'", id.c_str())));
- }
-
- ids_to_remove.insert(id);
- }
+ absl::optional<std::vector<std::string>> ids = absl::nullopt;
+ // TODO(crbug.com/1300657): `ids` should have an empty list when filter ids is
+ // empty, instead of a nullopt. Otherwise, we are incorrectly removing all
+ // content scripts when ids is empty.
+ if (filter && filter->ids && !filter->ids->empty()) {
+ ids = std::move(filter->ids);
}
- if (ids_to_remove.empty()) {
- loader->ClearDynamicScripts(
- base::BindOnce(&ScriptingUnregisterContentScriptsFunction::
- OnContentScriptsUnregistered,
- this));
- } else {
- loader->RemoveDynamicScripts(
- std::move(ids_to_remove),
- base::BindOnce(&ScriptingUnregisterContentScriptsFunction::
- OnContentScriptsUnregistered,
- this));
+ std::string error;
+ bool removal_triggered = scripting::RemoveScripts(
+ ids, UserScript::Source::kDynamicContentScript, browser_context(),
+ extension()->id(),
+ base::BindOnce(&ScriptingUnregisterContentScriptsFunction::
+ OnContentScriptsUnregistered,
+ this),
+ &error);
+
+ if (!removal_triggered) {
+ CHECK(!error.empty());
+ return RespondNow(Error(std::move(error)));
}
return RespondLater();
@@ -1167,6 +1131,18 @@ ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
std::vector<api::scripting::RegisteredContentScript>& scripts =
params->scripts;
+ std::string error;
+
+ // Add the prefix for dynamic content scripts onto the IDs of all scripts in
+ // `scripts` before continuing.
+ std::set<std::string> ids_to_update = scripting::CreateDynamicScriptIds(
+ scripts, UserScript::Source::kDynamicContentScript,
+ std::set<std::string>(), &error);
+
+ if (!error.empty()) {
+ CHECK(ids_to_update.empty());
+ return RespondNow(Error(std::move(error)));
+ }
ExtensionUserScriptLoader* loader =
ExtensionSystem::Get(browser_context())
@@ -1177,29 +1153,21 @@ ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
loaded_scripts_metadata;
const UserScriptList& dynamic_scripts = loader->GetLoadedDynamicScripts();
for (const std::unique_ptr<UserScript>& script : dynamic_scripts) {
- loaded_scripts_metadata.emplace(script->id(),
- CreateRegisteredContentScriptInfo(*script));
+ if (script->GetSource() == UserScript::Source::kDynamicContentScript) {
+ loaded_scripts_metadata.emplace(
+ script->id(), CreateRegisteredContentScriptInfo(*script));
+ }
}
- std::set<std::string> ids_to_update;
for (const auto& script : scripts) {
+ std::string error_script_id = UserScript::TrimPrefixFromScriptID(script.id);
if (loaded_scripts_metadata.find(script.id) ==
loaded_scripts_metadata.end()) {
return RespondNow(
- Error(base::StringPrintf("Content script with ID '%s' does not exist "
+ Error(base::StringPrintf("Script with ID '%s' does not exist "
"or is not fully registered",
- script.id.c_str())));
- }
-
- DCHECK(!script.id.empty());
- DCHECK(!UserScript::IsIDGenerated(script.id));
-
- if (base::Contains(ids_to_update, script.id)) {
- return RespondNow(Error(
- base::StringPrintf("Duplicate script ID '%s'", script.id.c_str())));
+ error_script_id.c_str())));
}
-
- ids_to_update.insert(script.id);
}
std::u16string parse_error;
@@ -1268,7 +1236,7 @@ ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
GetExtensionFileTaskRunner()->PostTaskAndReplyWithResult(
FROM_HERE,
- base::BindOnce(&ValidateParsedScriptsOnFileThread,
+ base::BindOnce(&scripting::ValidateParsedScriptsOnFileThread,
script_parsing::GetSymlinkPolicy(extension()),
std::move(parsed_scripts)),
base::BindOnce(
@@ -1283,10 +1251,11 @@ ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
void ScriptingUpdateContentScriptsFunction::OnContentScriptFilesValidated(
std::set<std::string> persistent_script_ids,
- ValidateContentScriptsResult result) {
+ scripting::ValidateScriptsResult result) {
// We cannot proceed if the `browser_context` is not valid as the
// `ExtensionSystem` will not exist.
if (!browser_context()) {
+ Release(); // Matches the `AddRef()` in `Run()`.
return;
}
diff --git a/chromium/chrome/browser/extensions/api/scripting/scripting_api.h b/chromium/chrome/browser/extensions/api/scripting/scripting_api.h
index 811da641457..a9db6bc8959 100644
--- a/chromium/chrome/browser/extensions/api/scripting/scripting_api.h
+++ b/chromium/chrome/browser/extensions/api/scripting/scripting_api.h
@@ -11,6 +11,7 @@
#include <vector>
#include "chrome/common/extensions/api/scripting.h"
+#include "extensions/browser/api/scripting/scripting_utils.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/script_executor.h"
#include "extensions/common/mojom/code_injection.mojom.h"
@@ -108,9 +109,6 @@ class ScriptingRemoveCSSFunction : public ExtensionFunction {
void OnCSSRemoved(std::vector<ScriptExecutor::FrameResult> results);
};
-using ValidateContentScriptsResult =
- std::pair<std::unique_ptr<UserScriptList>, absl::optional<std::string>>;
-
class ScriptingRegisterContentScriptsFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("scripting.registerContentScripts",
@@ -131,7 +129,7 @@ class ScriptingRegisterContentScriptsFunction : public ExtensionFunction {
// Called when script files have been checked.
void OnContentScriptFilesValidated(
std::set<std::string> persistent_script_ids,
- ValidateContentScriptsResult result);
+ scripting::ValidateScriptsResult result);
// Called when content scripts have been registered.
void OnContentScriptsRegistered(const absl::optional<std::string>& error);
@@ -196,7 +194,7 @@ class ScriptingUpdateContentScriptsFunction : public ExtensionFunction {
// Called when script files have been checked.
void OnContentScriptFilesValidated(
std::set<std::string> persistent_script_ids,
- ValidateContentScriptsResult result);
+ scripting::ValidateScriptsResult result);
// Called when content scripts have been updated.
void OnContentScriptsUpdated(const absl::optional<std::string>& error);
diff --git a/chromium/chrome/browser/extensions/api/scripting/scripting_apitest.cc b/chromium/chrome/browser/extensions/api/scripting/scripting_apitest.cc
index abe0c434f07..2f86e914ae1 100644
--- a/chromium/chrome/browser/extensions/api/scripting/scripting_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/scripting/scripting_apitest.cc
@@ -21,6 +21,7 @@
#include "extensions/browser/api_test_utils.h"
#include "extensions/browser/background_script_executor.h"
#include "extensions/browser/disable_reason.h"
+#include "extensions/common/extension_features.h"
#include "extensions/common/features/feature_channel.h"
#include "extensions/common/utils/content_script_utils.h"
#include "extensions/test/extension_test_message_listener.h"
@@ -550,4 +551,30 @@ IN_PROC_BROWSER_TEST_F(ScriptingAPIPrerenderingTest, MAYBE_Basic) {
ASSERT_TRUE(RunExtensionTest("scripting/prerendering")) << message_;
}
+class ScriptingAndUserScriptsAPITest : public ScriptingAPITest {
+ public:
+ ScriptingAndUserScriptsAPITest() {
+ scoped_feature_list_.InitAndEnableFeature(
+ extensions_features::kApiUserScripts);
+ }
+ ScriptingAndUserScriptsAPITest(const ScriptingAndUserScriptsAPITest&) =
+ delete;
+ ScriptingAndUserScriptsAPITest& operator=(
+ const ScriptingAndUserScriptsAPITest&) = delete;
+ ~ScriptingAndUserScriptsAPITest() override = default;
+
+ private:
+ // The userScripts API is currently behind a channel and feature restriction.
+ // TODO(crbug.com/1472902): Remove channel override when user scripts API goes
+ // to stable.
+ ScopedCurrentChannel current_channel_override_{
+ version_info::Channel::UNKNOWN};
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(ScriptingAndUserScriptsAPITest,
+ ScriptingAPIDoesNotAffectUserScripts) {
+ ASSERT_TRUE(RunExtensionTest("scripting/dynamic_user_scripts")) << message_;
+}
+
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/settings_overrides/settings_overrides_api.cc b/chromium/chrome/browser/extensions/api/settings_overrides/settings_overrides_api.cc
index e94dc4dfd5a..e897598888f 100644
--- a/chromium/chrome/browser/extensions/api/settings_overrides/settings_overrides_api.cc
+++ b/chromium/chrome/browser/extensions/api/settings_overrides/settings_overrides_api.cc
@@ -23,9 +23,12 @@
#include "extensions/browser/extension_prefs_factory.h"
#include "extensions/browser/extension_prefs_helper.h"
#include "extensions/browser/extension_prefs_helper_factory.h"
+#include "extensions/common/api/types.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/manifest_constants.h"
+using extensions::api::types::ChromeSettingScope;
+
namespace extensions {
namespace {
@@ -147,7 +150,7 @@ void SettingsOverridesAPI::SetPref(const std::string& extension_id,
return;
prefs_helper->SetExtensionControlledPref(
- extension_id, pref_key, kExtensionPrefsScopeRegular, std::move(value));
+ extension_id, pref_key, ChromeSettingScope::kRegular, std::move(value));
}
void SettingsOverridesAPI::UnsetPref(const std::string& extension_id,
@@ -157,7 +160,7 @@ void SettingsOverridesAPI::UnsetPref(const std::string& extension_id,
if (!prefs_helper)
return;
prefs_helper->RemoveExtensionControlledPref(extension_id, pref_key,
- kExtensionPrefsScopeRegular);
+ ChromeSettingScope::kRegular);
}
void SettingsOverridesAPI::OnExtensionLoaded(
diff --git a/chromium/chrome/browser/extensions/api/settings_private/generated_prefs.h b/chromium/chrome/browser/extensions/api/settings_private/generated_prefs.h
index ec5992b76b3..bd31f1492c3 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/generated_prefs.h
+++ b/chromium/chrome/browser/extensions/api/settings_private/generated_prefs.h
@@ -7,8 +7,8 @@
#include <memory>
#include <string>
-#include <unordered_map>
+#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/extensions/api/settings_private/generated_pref.h"
#include "chrome/browser/extensions/api/settings_private/prefs_util_enums.h"
@@ -22,11 +22,10 @@ class Value;
}
namespace extensions {
-namespace api {
-namespace settings_private {
+
+namespace api::settings_private {
struct PrefObject;
-} // namespace settings_private
-} // namespace api
+} // namespace api::settings_private
namespace settings_private {
@@ -36,8 +35,7 @@ namespace settings_private {
class GeneratedPrefs : public KeyedService {
public:
// Preference name to implementation map.
- using PrefsMap =
- std::unordered_map<std::string, std::unique_ptr<GeneratedPref>>;
+ using PrefsMap = base::flat_map<std::string, std::unique_ptr<GeneratedPref>>;
explicit GeneratedPrefs(Profile* profile);
diff --git a/chromium/chrome/browser/extensions/api/settings_private/generated_prefs_factory.cc b/chromium/chrome/browser/extensions/api/settings_private/generated_prefs_factory.cc
index af641e055d1..4ad1f0f943e 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/generated_prefs_factory.cc
+++ b/chromium/chrome/browser/extensions/api/settings_private/generated_prefs_factory.cc
@@ -41,9 +41,10 @@ bool GeneratedPrefsFactory::ServiceIsNULLWhileTesting() const {
return true;
}
-KeyedService* GeneratedPrefsFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+GeneratedPrefsFactory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* profile) const {
- return new GeneratedPrefs(static_cast<Profile*>(profile));
+ return std::make_unique<GeneratedPrefs>(static_cast<Profile*>(profile));
}
} // namespace settings_private
diff --git a/chromium/chrome/browser/extensions/api/settings_private/generated_prefs_factory.h b/chromium/chrome/browser/extensions/api/settings_private/generated_prefs_factory.h
index 2aaea1496d8..69d829feec5 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/generated_prefs_factory.h
+++ b/chromium/chrome/browser/extensions/api/settings_private/generated_prefs_factory.h
@@ -32,7 +32,7 @@ class GeneratedPrefsFactory : public ProfileKeyedServiceFactory {
// BrowserContextKeyedServiceFactory implementation.
bool ServiceIsNULLWhileTesting() const override;
- KeyedService* BuildServiceInstanceFor(
+ std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
content::BrowserContext* profile) const override;
};
diff --git a/chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 0e684543447..40fb00a537e 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -42,8 +42,10 @@
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/payments/core/payment_prefs.h"
#include "components/performance_manager/public/user_tuning/prefs.h"
+#include "components/permissions/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
+#include "components/privacy_sandbox/tracking_protection_prefs.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/search_engines/default_search_manager.h"
@@ -188,6 +190,8 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
(*s_allowlist)[autofill::prefs::kAutofillPaymentMethodsMandatoryReauth] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
#endif
+ (*s_allowlist)[autofill::prefs::kAutofillPaymentCvcStorage] =
+ settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[payments::kCanMakePaymentEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[bookmarks::prefs::kShowBookmarkBar] =
@@ -208,8 +212,6 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
(*s_allowlist)[::prefs::kPolicyThemeColor] =
settings_api::PrefType::PREF_TYPE_NUMBER;
#if BUILDFLAG(IS_LINUX)
- (*s_allowlist)[::prefs::kUsesSystemThemeDeprecated] =
- settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[::prefs::kSystemTheme] =
settings_api::PrefType::PREF_TYPE_NUMBER;
#endif
@@ -265,6 +267,8 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::PREF_TYPE_STRING;
(*s_allowlist)[drive::prefs::kDriveFsBulkPinningEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
+ (*s_allowlist)[drive::prefs::kDisableDriveOverCellular] =
+ settings_api::PrefType::PREF_TYPE_BOOLEAN;
#endif
(*s_allowlist)[::prefs::kDownloadBubblePartialViewEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
@@ -292,6 +296,10 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
[password_manager::prefs::kBiometricAuthenticationBeforeFilling] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
#endif
+#if BUILDFLAG(IS_MAC)
+ (*s_allowlist)[::prefs::kCreatePasskeysInICloudKeychain] =
+ settings_api::PrefType::PREF_TYPE_BOOLEAN;
+#endif
// Privacy page
(*s_allowlist)[::prefs::kSigninAllowedOnNextStartup] =
@@ -352,6 +360,10 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[::prefs::kPrivacySandboxFirstPartySetsEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
+ (*s_allowlist)[::prefs::kBlockAll3pcToggleEnabled] =
+ settings_api::PrefType::PREF_TYPE_BOOLEAN;
+ (*s_allowlist)[::prefs::kTrackingProtectionLevel] =
+ settings_api::PrefType::PREF_TYPE_NUMBER;
// Sync and personalization page.
(*s_allowlist)[::prefs::kSearchSuggestEnabled] =
@@ -398,6 +410,8 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[ash::prefs::kAssistPredictiveWritingEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
+ (*s_allowlist)[ash::prefs::kOrcaEnabled] =
+ settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[ash::prefs::kEmojiSuggestionEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[ash::prefs::kLacrosProxyControllingExtension] =
@@ -450,6 +464,9 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::PREF_TYPE_NUMBER;
(*s_allowlist)[::prefs::kEnableQuietNotificationPermissionUi] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
+ (*s_allowlist)
+ [::permissions::prefs::kUnusedSitePermissionsRevocationEnabled] =
+ settings_api::PrefType::PREF_TYPE_BOOLEAN;
// Clear browsing data settings.
(*s_allowlist)[browsing_data::prefs::kDeleteBrowsingHistory] =
@@ -503,6 +520,8 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[::prefs::kLiveCaptionLanguageCode] =
settings_api::PrefType::PREF_TYPE_STRING;
+ (*s_allowlist)[::prefs::kLiveCaptionMaskOffensiveWords] =
+ settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[::prefs::kLiveTranslateEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[::prefs::kLiveTranslateTargetLanguageCode] =
@@ -512,6 +531,10 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
(*s_allowlist)[::prefs::kAccessibilityPdfOcrAlwaysActive] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
#endif
+#if defined(USE_AURA)
+ (*s_allowlist)[::prefs::kOverscrollHistoryNavigationEnabled] =
+ settings_api::PrefType::PREF_TYPE_BOOLEAN;
+#endif
(*s_allowlist)[::prefs::kCaretBrowsingEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
@@ -549,11 +572,11 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[ash::prefs::kAccessibilityAutoclickMovementThreshold] =
settings_api::PrefType::PREF_TYPE_NUMBER;
- (*s_allowlist)[ash::prefs::kAccessibilityColorFiltering] =
+ (*s_allowlist)[ash::prefs::kAccessibilityColorCorrectionEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[ash::prefs::kAccessibilityColorVisionCorrectionAmount] =
settings_api::PrefType::PREF_TYPE_NUMBER;
- (*s_allowlist)[ash::prefs::kAccessibilityColorVisionDeficiencyType] =
+ (*s_allowlist)[ash::prefs::kAccessibilityColorVisionCorrectionType] =
settings_api::PrefType::PREF_TYPE_NUMBER;
(*s_allowlist)[ash::prefs::kShouldAlwaysShowAccessibilityMenu] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.cc b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.cc
index f28e6c77245..f139561b41a 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.cc
+++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.cc
@@ -38,9 +38,11 @@ SettingsPrivateDelegateFactory::SettingsPrivateDelegateFactory()
SettingsPrivateDelegateFactory::~SettingsPrivateDelegateFactory() = default;
-KeyedService* SettingsPrivateDelegateFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+SettingsPrivateDelegateFactory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* profile) const {
- return new SettingsPrivateDelegate(static_cast<Profile*>(profile));
+ return std::make_unique<SettingsPrivateDelegate>(
+ static_cast<Profile*>(profile));
}
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.h b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.h
index d756c4c2c9b..eef59cde0f7 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.h
+++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.h
@@ -35,7 +35,7 @@ class SettingsPrivateDelegateFactory : public ProfileKeyedServiceFactory {
~SettingsPrivateDelegateFactory() override;
// BrowserContextKeyedServiceFactory implementation.
- KeyedService* BuildServiceInstanceFor(
+ std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
content::BrowserContext* profile) const override;
};
diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
index 418137145ae..532c08d59bf 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
+++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
@@ -161,15 +161,16 @@ void SettingsPrivateEventRouter::SendPrefChange(const std::string& pref_name) {
auto args(api::settings_private::OnPrefsChanged::Create(prefs));
- std::unique_ptr<Event> extension_event(new Event(
- events::SETTINGS_PRIVATE_ON_PREFS_CHANGED,
- api::settings_private::OnPrefsChanged::kEventName, std::move(args)));
+ std::unique_ptr<Event> extension_event =
+ std::make_unique<Event>(events::SETTINGS_PRIVATE_ON_PREFS_CHANGED,
+ api::settings_private::OnPrefsChanged::kEventName,
+ std::move(args), context_);
event_router->BroadcastEvent(std::move(extension_event));
}
-SettingsPrivateEventRouter* SettingsPrivateEventRouter::Create(
+std::unique_ptr<SettingsPrivateEventRouter> SettingsPrivateEventRouter::Create(
content::BrowserContext* context) {
- return new SettingsPrivateEventRouter(context);
+ return std::make_unique<SettingsPrivateEventRouter>(context);
}
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.h b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
index 7d2c5543799..a16221f9ec5 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
+++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
@@ -35,9 +35,10 @@ class SettingsPrivateEventRouter
public EventRouter::Observer,
public settings_private::GeneratedPref::Observer {
public:
- static SettingsPrivateEventRouter* Create(
+ static std::unique_ptr<SettingsPrivateEventRouter> Create(
content::BrowserContext* browser_context);
+ explicit SettingsPrivateEventRouter(content::BrowserContext* context);
SettingsPrivateEventRouter(const SettingsPrivateEventRouter&) = delete;
SettingsPrivateEventRouter& operator=(const SettingsPrivateEventRouter&) =
delete;
@@ -50,8 +51,6 @@ class SettingsPrivateEventRouter
content::BrowserContext* context_for_test() { return context_; }
protected:
- explicit SettingsPrivateEventRouter(content::BrowserContext* context);
-
// KeyedService overrides:
void Shutdown() override;
diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.cc b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.cc
index bf49f8d1803..24c742fa38e 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.cc
+++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.cc
@@ -46,7 +46,8 @@ SettingsPrivateEventRouterFactory::SettingsPrivateEventRouterFactory()
SettingsPrivateEventRouterFactory::~SettingsPrivateEventRouterFactory() =
default;
-KeyedService* SettingsPrivateEventRouterFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+SettingsPrivateEventRouterFactory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const {
return SettingsPrivateEventRouter::Create(context);
}
diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.h b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.h
index a16216aca44..d831a361e81 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.h
+++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.h
@@ -42,7 +42,7 @@ class SettingsPrivateEventRouterFactory : public ProfileKeyedServiceFactory {
~SettingsPrivateEventRouterFactory() override;
// BrowserContextKeyedServiceFactory:
- KeyedService* BuildServiceInstanceFor(
+ std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
content::BrowserContext* profile) const override;
};
diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_unittest.cc b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_unittest.cc
new file mode 100644
index 00000000000..f1ff2ea6e74
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router_unittest.cc
@@ -0,0 +1,160 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/settings_private/settings_private_event_router.h"
+
+#include "base/test/run_until.h"
+#include "chrome/browser/extensions/api/settings_private/settings_private_event_router_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "extensions/browser/event_router_factory.h"
+#include "extensions/browser/process_map.h"
+#include "extensions/browser/process_map_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+namespace {
+
+// A fake that pretends that all contexts are WebUI.
+class ProcessMapFake : public ProcessMap {
+ public:
+ Feature::Context GetMostLikelyContextType(const Extension* extension,
+ int process_id,
+ const GURL* url) const override {
+ return Feature::WEBUI_CONTEXT;
+ }
+};
+
+std::unique_ptr<KeyedService> BuildEventRouter(
+ content::BrowserContext* profile) {
+ return std::make_unique<extensions::EventRouter>(profile, nullptr);
+}
+
+std::unique_ptr<KeyedService> BuildSettingsPrivateEventRouter(
+ content::BrowserContext* profile) {
+ return std::unique_ptr<KeyedService>(
+ SettingsPrivateEventRouter::Create(profile));
+}
+
+std::unique_ptr<KeyedService> BuildProcessMap(
+ content::BrowserContext* profile) {
+ return std::make_unique<ProcessMapFake>();
+}
+
+// Tracks event dispatches to a specific process.
+class EventRouterObserver : public EventRouter::TestObserver {
+ public:
+ // Only counts events that match |process_id|.
+ explicit EventRouterObserver(int process_id) : process_id_(process_id) {}
+
+ void OnWillDispatchEvent(const Event& event) override {
+ // Do nothing.
+ }
+
+ void OnDidDispatchEventToProcess(const Event& event,
+ int process_id) override {
+ if (process_id == process_id_) {
+ ++dispatch_count;
+ }
+ }
+
+ int dispatch_count = 0;
+ const int process_id_;
+};
+
+class SettingsPrivateEventRouterTest : public testing::Test {
+ public:
+ SettingsPrivateEventRouterTest()
+ : manager_(TestingBrowserProcess::GetGlobal()) {}
+ void SetUp() override { ASSERT_TRUE(manager_.SetUp()); }
+
+ protected:
+ content::BrowserTaskEnvironment task_environment_;
+ TestingProfileManager manager_;
+};
+
+// Tests that events from incognito profiles do not get routed to regular
+// profiles. Regression test for https://crbug.com/1381219.
+TEST_F(SettingsPrivateEventRouterTest, IncognitoEventRouting) {
+ // Create a testing profile. Override relevant factories.
+ TestingProfile* profile = manager_.CreateTestingProfile("test");
+ EventRouterFactory::GetInstance()->SetTestingFactory(
+ profile, base::BindRepeating(&BuildEventRouter));
+ SettingsPrivateEventRouterFactory::GetInstance()->SetTestingFactory(
+ profile, base::BindRepeating(&BuildSettingsPrivateEventRouter));
+ ProcessMapFactory::GetInstance()->SetTestingFactory(
+ profile, base::BindRepeating(&BuildProcessMap));
+
+ // Create an otr profile. Override relevant factories.
+ Profile::OTRProfileID otr_id = Profile::OTRProfileID::PrimaryID();
+ Profile* otr_profile =
+ profile->GetOffTheRecordProfile(otr_id, /*create_if_needed=*/true);
+ EventRouterFactory::GetInstance()->SetTestingFactory(
+ otr_profile, base::BindRepeating(&BuildEventRouter));
+ SettingsPrivateEventRouterFactory::GetInstance()->SetTestingFactory(
+ otr_profile, base::BindRepeating(&BuildSettingsPrivateEventRouter));
+ ProcessMapFactory::GetInstance()->SetTestingFactory(
+ otr_profile, base::BindRepeating(&BuildProcessMap));
+
+ // Create the event routers.
+ EventRouter* regular_event_router =
+ EventRouterFactory::GetInstance()->GetForBrowserContext(profile);
+ EventRouter* otr_event_router =
+ EventRouterFactory::GetInstance()->GetForBrowserContext(otr_profile);
+
+ // Today, EventRouter instances are shared between on- and off-the-record
+ // profile instances. We separate them into variables here, since the
+ // SettingsPrivateEventRouter shouldn't necessarily know about that or
+ // care.
+ EXPECT_EQ(regular_event_router, otr_event_router);
+
+ // Create the special routers for settingsPrivate.
+ ASSERT_TRUE(SettingsPrivateEventRouterFactory::GetForProfile(profile));
+ ASSERT_TRUE(SettingsPrivateEventRouterFactory::GetForProfile(otr_profile));
+
+ // Create some mock rphs.
+ content::MockRenderProcessHost regular_rph(profile);
+ content::MockRenderProcessHost otr_rph(otr_profile);
+
+ // Add event listeners, as if we had created two real WebUIs, one in a regular
+ // profile and one in an otr profile. Note that the string chrome://settings
+ // is hardcoded into the api permissions of settingsPrivate.
+ GURL kDummyURL("chrome://settings");
+ regular_event_router->AddEventListenerForURL(
+ api::settings_private::OnPrefsChanged::kEventName, &regular_rph,
+ kDummyURL);
+ otr_event_router->AddEventListenerForURL(
+ api::settings_private::OnPrefsChanged::kEventName, &otr_rph, kDummyURL);
+
+ // Hook up some test observers
+ EventRouterObserver regular_counter(regular_rph.GetID());
+ regular_event_router->AddObserverForTesting(&regular_counter);
+ EventRouterObserver otr_counter(otr_rph.GetID());
+ otr_event_router->AddObserverForTesting(&otr_counter);
+
+ EXPECT_EQ(0, regular_counter.dispatch_count);
+ EXPECT_EQ(0, otr_counter.dispatch_count);
+
+ // Setting an otr pref should not trigger the normal observer.
+ otr_profile->GetPrefs()->SetBoolean(prefs::kPromptForDownload, true);
+ ASSERT_TRUE(
+ base::test::RunUntil([&]() { return otr_counter.dispatch_count == 1; }));
+ EXPECT_EQ(0, regular_counter.dispatch_count);
+ EXPECT_EQ(1, otr_counter.dispatch_count);
+
+ // Setting a regular pref should not trigger the otr observer.
+ profile->GetPrefs()->SetBoolean(prefs::kPromptForDownload, true);
+ ASSERT_TRUE(base::test::RunUntil(
+ [&]() { return regular_counter.dispatch_count == 1; }));
+ EXPECT_EQ(1, regular_counter.dispatch_count);
+ EXPECT_EQ(1, otr_counter.dispatch_count);
+}
+
+} // namespace
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.h b/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.h
index 4e672e62e66..571f4e1b0aa 100644
--- a/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.h
+++ b/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.h
@@ -93,7 +93,7 @@ class ManagedValueStoreCache : public ValueStoreCache,
VALID_CONTEXT_REQUIRED(backend_sequence_checker_);
// The profile that owns the extension system being used.
- const raw_ref<Profile, DanglingUntriaged> profile_
+ const raw_ref<Profile, AcrossTasksDanglingUntriaged> profile_
GUARDED_BY_CONTEXT(ui_sequence_checker_);
// The policy domain. This is used for observing the policy updates.
@@ -101,8 +101,8 @@ class ManagedValueStoreCache : public ValueStoreCache,
GUARDED_BY_CONTEXT(ui_sequence_checker_);
// The `profile_`'s `PolicyService`.
- const raw_ref<policy::PolicyService, DanglingUntriaged> policy_service_
- GUARDED_BY_CONTEXT(ui_sequence_checker_);
+ const raw_ref<policy::PolicyService, AcrossTasksDanglingUntriaged>
+ policy_service_ GUARDED_BY_CONTEXT(ui_sequence_checker_);
// Observes extension loading and unloading, and keeps the `Profile`'s
// `PolicyService` aware of the current list of extensions.
diff --git a/chromium/chrome/browser/extensions/api/storage/policy_value_store.h b/chromium/chrome/browser/extensions/api/storage/policy_value_store.h
index fc39df27d06..872f953838e 100644
--- a/chromium/chrome/browser/extensions/api/storage/policy_value_store.h
+++ b/chromium/chrome/browser/extensions/api/storage/policy_value_store.h
@@ -13,6 +13,7 @@
#include "components/value_store/value_store.h"
#include "extensions/browser/api/storage/settings_observer.h"
+#include "extensions/common/extension_id.h"
namespace policy {
class PolicyMap;
@@ -63,7 +64,7 @@ class PolicyValueStore : public value_store::ValueStore {
value_store::ValueStore* delegate() { return delegate_.get(); }
private:
- std::string extension_id_;
+ ExtensionId extension_id_;
SequenceBoundSettingsChangedCallback observer_;
std::unique_ptr<value_store::ValueStore> delegate_;
};
diff --git a/chromium/chrome/browser/extensions/api/storage/setting_sync_data.h b/chromium/chrome/browser/extensions/api/storage/setting_sync_data.h
index 913bc2c76a8..76dce4a4b14 100644
--- a/chromium/chrome/browser/extensions/api/storage/setting_sync_data.h
+++ b/chromium/chrome/browser/extensions/api/storage/setting_sync_data.h
@@ -10,6 +10,7 @@
#include "base/values.h"
#include "components/sync/model/sync_change.h"
+#include "extensions/common/extension_id.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace syncer {
@@ -45,7 +46,7 @@ class SettingSyncData {
const {
return change_type_;
}
- const std::string& extension_id() const { return extension_id_; }
+ const ExtensionId& extension_id() const { return extension_id_; }
const std::string& key() const { return key_; }
// value() cannot be called if ExtractValue() has been called.
const base::Value& value() const { return *value_; }
@@ -60,7 +61,7 @@ class SettingSyncData {
void ExtractSyncData(const syncer::SyncData& sync_data);
absl::optional<syncer::SyncChange::SyncChangeType> change_type_;
- std::string extension_id_;
+ ExtensionId extension_id_;
std::string key_;
absl::optional<base::Value> value_;
};
diff --git a/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.h b/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.h
index e8702bc637c..e1e8f119a2a 100644
--- a/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.h
+++ b/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.h
@@ -12,6 +12,7 @@
#include "base/values.h"
#include "components/sync/base/model_type.h"
#include "components/value_store/value_store_change.h"
+#include "extensions/common/extension_id.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace syncer {
@@ -53,7 +54,7 @@ class SettingsSyncProcessor {
private:
// ID of the extension the changes are for.
- const std::string extension_id_;
+ const ExtensionId extension_id_;
// Sync model type. Either EXTENSION_SETTING or APP_SETTING.
const syncer::ModelType type_;
diff --git a/chromium/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.cc b/chromium/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.cc
index e36654a1039..75ca60daa3d 100644
--- a/chromium/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.cc
+++ b/chromium/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.cc
@@ -39,14 +39,15 @@ SystemIndicatorManagerFactory::SystemIndicatorManagerFactory()
SystemIndicatorManagerFactory::~SystemIndicatorManagerFactory() = default;
-KeyedService* SystemIndicatorManagerFactory::BuildServiceInstanceFor(
+std::unique_ptr<KeyedService>
+SystemIndicatorManagerFactory::BuildServiceInstanceForBrowserContext(
content::BrowserContext* profile) const {
StatusTray* status_tray = g_browser_process->status_tray();
if (status_tray == NULL)
return NULL;
- return new SystemIndicatorManager(static_cast<Profile*>(profile),
- status_tray);
+ return std::make_unique<SystemIndicatorManager>(
+ static_cast<Profile*>(profile), status_tray);
}
bool SystemIndicatorManagerFactory::ServiceIsCreatedWithBrowserContext() const {
diff --git a/chromium/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h b/chromium/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h
index 2168833ed93..cb24fad396c 100644
--- a/chromium/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h
+++ b/chromium/chrome/browser/extensions/api/system_indicator/system_indicator_manager_factory.h
@@ -30,7 +30,7 @@ class SystemIndicatorManagerFactory : public ProfileKeyedServiceFactory {
~SystemIndicatorManagerFactory() override;
// BrowserContextKeyedServiceFactory implementation.
- KeyedService* BuildServiceInstanceFor(
+ std::unique_ptr<KeyedService> BuildServiceInstanceForBrowserContext(
content::BrowserContext* context) const override;
bool ServiceIsCreatedWithBrowserContext() const override;
};
diff --git a/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc b/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc
index 64a8ace89c1..e324c999ad3 100644
--- a/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc
+++ b/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc
@@ -3,9 +3,9 @@
// found in the LICENSE file.
#include <cmath>
-#include <unordered_map>
#include "base/command_line.h"
+#include "base/containers/flat_map.h"
#include "base/files/file_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/trace_event_analyzer.h"
@@ -54,7 +54,7 @@ constexpr char kEventSuffixFailRate[] = "FailRate";
constexpr char kEventSuffixLatency[] = "Latency";
constexpr char kEventCommitAndDrawCompositorFrame[] =
"WidgetBase::DidCommitAndDrawCompositorFrame";
-const std::unordered_map<std::string, std::string> kEventToMetricMap(
+const base::flat_map<std::string, std::string> kEventToMetricMap(
{{kEventCapture, kMetricCaptureMs},
{std::string(kEventCapture) + kEventSuffixFailRate,
kMetricCaptureFailRatePercent},
diff --git a/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc b/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
index 05ea0170bfa..170aa77db94 100644
--- a/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
+++ b/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
@@ -20,6 +20,7 @@
#include "content/public/browser/web_contents_observer.h"
#include "extensions/browser/event_router.h"
#include "extensions/common/extension.h"
+#include "extensions/common/extension_id.h"
#include "url/origin.h"
using content::BrowserThread;
@@ -35,7 +36,7 @@ namespace tab_capture = api::tab_capture;
class TabCaptureRegistry::LiveRequest : public content::WebContentsObserver {
public:
LiveRequest(content::WebContents* target_contents,
- const std::string& extension_id,
+ const ExtensionId& extension_id,
bool is_anonymous,
TabCaptureRegistry* registry)
: content::WebContentsObserver(target_contents),
@@ -56,7 +57,7 @@ class TabCaptureRegistry::LiveRequest : public content::WebContentsObserver {
~LiveRequest() override {}
// Accessors.
- const std::string& extension_id() const { return extension_id_; }
+ const ExtensionId& extension_id() const { return extension_id_; }
bool is_anonymous() const { return is_anonymous_; }
TabCaptureState capture_state() const { return capture_state_; }
bool is_verified() const { return is_verified_; }
@@ -102,7 +103,7 @@ class TabCaptureRegistry::LiveRequest : public content::WebContentsObserver {
}
private:
- const std::string extension_id_;
+ const ExtensionId extension_id_;
const bool is_anonymous_;
const raw_ptr<TabCaptureRegistry> registry_;
TabCaptureState capture_state_ = tab_capture::TAB_CAPTURE_STATE_NONE;
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc
index 5025286fe96..93b7498b7c5 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -51,6 +51,8 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
#include "chrome/browser/resource_coordinator/tab_manager.h"
+#include "chrome/browser/safe_browsing/extension_telemetry/extension_telemetry_service.h"
+#include "chrome/browser/safe_browsing/extension_telemetry/tabs_api_signal.h"
#include "chrome/browser/translate/chrome_translate_client.h"
#include "chrome/browser/ui/apps/chrome_app_delegate.h"
#include "chrome/browser/ui/browser.h"
@@ -76,6 +78,7 @@
#include "chrome/common/url_constants.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
+#include "components/safe_browsing/core/common/features.h"
#include "components/sessions/content/session_tab_helper.h"
#include "components/tab_groups/tab_group_color.h"
#include "components/tab_groups/tab_group_id.h"
@@ -437,6 +440,30 @@ bool WindowBoundsIntersectDisplays(const gfx::Rect& bounds) {
return intersect_area >= (bounds.size().GetArea() / 2);
}
+void NotifyExtensionTelemetry(Profile* profile,
+ const Extension* extension,
+ safe_browsing::TabsApiInfo::ApiMethod api_method,
+ const std::string& current_url,
+ const std::string& new_url) {
+ // Ignore API calls that are not invoked by extensions.
+ if (!extension) {
+ return;
+ }
+
+ auto* extension_telemetry_service =
+ safe_browsing::ExtensionTelemetryService::Get(profile);
+
+ if (!extension_telemetry_service || !extension_telemetry_service->enabled() ||
+ !base::FeatureList::IsEnabled(
+ safe_browsing::kExtensionTelemetryTabsApiSignal)) {
+ return;
+ }
+
+ auto tabs_api_signal = std::make_unique<safe_browsing::TabsApiSignal>(
+ extension->id(), api_method, current_url, new_url);
+ extension_telemetry_service->AddSignal(std::move(tabs_api_signal));
+}
+
} // namespace
void ZoomModeToZoomSettings(ZoomController::ZoomMode zoom_mode,
@@ -1298,6 +1325,11 @@ ExtensionFunction::ResponseAction TabsCreateFunction::Run() {
return Error(result.error());
}
+ NotifyExtensionTelemetry(Profile::FromBrowserContext(browser_context()),
+ extension(), safe_browsing::TabsApiInfo::CREATE,
+ /*current_url=*/std::string(),
+ options.url.value_or(std::string()));
+
// Return data about the newly created tab.
return has_callback() ? WithArguments(std::move(*result)) : NoArguments();
}());
@@ -1509,8 +1541,18 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
return RespondNow(Error(ErrorUtils::FormatErrorMessage(
tabs_constants::kURLsNotAllowedInIncognitoError, updated_url)));
}
+
+ // Get last committed or pending URL.
+ std::string current_url = contents->GetVisibleURL().is_valid()
+ ? contents->GetVisibleURL().spec()
+ : std::string();
+
if (!UpdateURL(updated_url, tab_id, &error))
return RespondNow(Error(std::move(error)));
+
+ NotifyExtensionTelemetry(Profile::FromBrowserContext(browser_context()),
+ extension(), safe_browsing::TabsApiInfo::UPDATE,
+ current_url, updated_url);
}
bool active = false;
@@ -1613,12 +1655,6 @@ bool TabsUpdateFunction::UpdateURL(const std::string& url_string,
return false;
}
- // JavaScript URLs are forbidden in chrome.tabs.update().
- if (url->SchemeIs(url::kJavaScriptScheme)) {
- *error = tabs_constants::kJavaScriptUrlsNotAllowedInTabsUpdate;
- return false;
- }
-
NavigationController::LoadURLParams load_params(*url);
// Treat extension-initiated navigations as renderer-initiated so that the URL
@@ -1864,6 +1900,15 @@ bool TabsRemoveFunction::RemoveTab(int tab_id, std::string* error) {
*error = tabs_constants::kTabStripNotEditableError;
return false;
}
+
+ // Get last committed or pending URL.
+ std::string current_url = contents->GetVisibleURL().is_valid()
+ ? contents->GetVisibleURL().spec()
+ : std::string();
+ NotifyExtensionTelemetry(Profile::FromBrowserContext(browser_context()),
+ extension(), safe_browsing::TabsApiInfo::REMOVE,
+ current_url, /*new_url=*/std::string());
+
// The tab might not immediately close after calling Close() below, so we
// should wait until WebContentsDestroyed is called before responding.
web_contents_destroyed_observers_.push_back(
@@ -2420,9 +2465,9 @@ bool ExecuteCodeInTabFunction::CanExecuteScriptOnPage(std::string* error) {
int frame_id = details_->frame_id ? *details_->frame_id
: ExtensionApiFrameIdMap::kTopFrameId;
- content::RenderFrameHost* rfh =
+ content::RenderFrameHost* render_frame_host =
ExtensionApiFrameIdMap::GetRenderFrameHostById(contents, frame_id);
- if (!rfh) {
+ if (!render_frame_host) {
*error = ErrorUtils::FormatErrorMessage(
tabs_constants::kFrameNotFoundError, base::NumberToString(frame_id),
base::NumberToString(execute_tab_id_));
@@ -2432,11 +2477,12 @@ bool ExecuteCodeInTabFunction::CanExecuteScriptOnPage(std::string* error) {
// Content scripts declared in manifest.json can access frames at about:-URLs
// if the extension has permission to access the frame's origin, so also allow
// programmatic content scripts at about:-URLs for allowed origins.
- GURL effective_document_url(rfh->GetLastCommittedURL());
+ GURL effective_document_url(render_frame_host->GetLastCommittedURL());
bool is_about_url = effective_document_url.SchemeIs(url::kAboutScheme);
if (is_about_url && details_->match_about_blank &&
*details_->match_about_blank) {
- effective_document_url = GURL(rfh->GetLastCommittedOrigin().Serialize());
+ effective_document_url =
+ GURL(render_frame_host->GetLastCommittedOrigin().Serialize());
}
if (!effective_document_url.is_valid()) {
@@ -2454,8 +2500,8 @@ bool ExecuteCodeInTabFunction::CanExecuteScriptOnPage(std::string* error) {
mojom::APIPermissionID::kTab)) {
*error = ErrorUtils::FormatErrorMessage(
manifest_errors::kCannotAccessAboutUrl,
- rfh->GetLastCommittedURL().spec(),
- rfh->GetLastCommittedOrigin().Serialize());
+ render_frame_host->GetLastCommittedURL().spec(),
+ render_frame_host->GetLastCommittedOrigin().Serialize());
}
return false;
}
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
index 42c4e323d51..1e164b48f21 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
@@ -42,7 +42,7 @@
#endif
#if BUILDFLAG(IS_CHROMEOS)
-#include "chrome/browser/chromeos/policy/dlp/mock_dlp_content_manager.h"
+#include "chrome/browser/chromeos/policy/dlp/test/mock_dlp_content_manager.h"
#endif
namespace extensions {
@@ -537,7 +537,8 @@ TEST_F(TabsApiUnitTest, TabsUpdateJavaScriptUrlNotAllowed) {
kFormatArgs, tab_id, "javascript:void(document.title = 'Won't work')");
std::string error = api_test_utils::RunFunctionAndReturnError(
function.get(), args, profile(), api_test_utils::FunctionMode::kNone);
- EXPECT_EQ(tabs_constants::kJavaScriptUrlsNotAllowedInTabsUpdate, error);
+ EXPECT_EQ(tabs_constants::kJavaScriptUrlsNotAllowedInExtensionNavigations,
+ error);
// Clean up.
browser()->tab_strip_model()->CloseAllTabs();
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_apitest.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_apitest.cc
index fbac58ab101..1aa7cb74978 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_apitest.cc
@@ -11,7 +11,6 @@
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/scoped_disable_client_side_decorations_for_test.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_switches.h"
@@ -132,7 +131,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTabTest, TabAudible) {
<< message_;
}
-IN_PROC_BROWSER_TEST_P(ExtensionApiTabTestWithContextType, Muted) {
+// TODO(crbug.com/1470083): Re-enable this test
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_Muted DISABLED_Muted
+#else
+#define MAYBE_Muted Muted
+#endif
+IN_PROC_BROWSER_TEST_P(ExtensionApiTabTestWithContextType, MAYBE_Muted) {
ASSERT_TRUE(RunExtensionTest("tabs/basics/muted")) << message_;
}
@@ -146,11 +151,6 @@ IN_PROC_BROWSER_TEST_P(ExtensionApiTabTestWithContextType, Duplicate) {
}
IN_PROC_BROWSER_TEST_P(ExtensionApiTabTestWithContextType, Size) {
- // TODO(crbug.com/1240482): the test expectations fail if the window gets CSD
- // and becomes smaller because of that. Investigate this and remove the line
- // below if possible.
- ui::ScopedDisableClientSideDecorationsForTest scoped_disabled_csd;
-
ASSERT_TRUE(RunExtensionTest("tabs/basics/tab_size")) << message_;
}
@@ -206,7 +206,8 @@ IN_PROC_BROWSER_TEST_P(ExtensionApiTabTestWithContextType, GetCurrent) {
ASSERT_TRUE(RunExtensionTest("tabs/get_current")) << message_;
}
-IN_PROC_BROWSER_TEST_P(ExtensionApiTabTestWithContextType, Connect) {
+// Disabled for being flaky. See crbug.com/1472144
+IN_PROC_BROWSER_TEST_P(ExtensionApiTabTestWithContextType, DISABLED_Connect) {
ASSERT_TRUE(RunExtensionTest("tabs/connect")) << message_;
}
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_constants.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_constants.cc
index 3c8378d7f00..ed6d1a80111 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_constants.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_constants.cc
@@ -124,9 +124,9 @@ const char kCannotDetermineLanguageOfUnloadedTab[] =
const char kMissingLockWindowFullscreenPrivatePermission[] =
"Cannot lock window to fullscreen or close a locked fullscreen window "
"without lockWindowFullscreenPrivate manifest permission";
-const char kJavaScriptUrlsNotAllowedInTabsUpdate[] =
- "JavaScript URLs are not allowed in chrome.tabs.update. Use "
- "chrome.tabs.executeScript instead.";
+const char kJavaScriptUrlsNotAllowedInExtensionNavigations[] =
+ "JavaScript URLs are not allowed in API based extension navigations. Use "
+ "chrome.scripting.executeScript instead.";
const char kBrowserWindowNotAllowed[] = "Browser windows not allowed.";
const char kLockedFullscreenModeNewTabError[] =
"You cannot create new tabs while in locked fullscreen mode.";
@@ -142,6 +142,8 @@ const char kCannotHighlightTabs[] =
"progress.";
const char kNotAllowedForDevToolsError[] =
"Operation not allowed for DevTools windows";
+const char kFileUrlsNotAllowedInExtensionNavigations[] =
+ "Cannot navigate to a file URL without local file access.";
} // namespace tabs_constants
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_constants.h b/chromium/chrome/browser/extensions/api/tabs/tabs_constants.h
index fc1d59b4317..c68ccde74e3 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_constants.h
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_constants.h
@@ -78,6 +78,7 @@ extern const char kWindowTypeValueDevTools[];
// Error messages.
extern const char kCannotZoomDisabledTabError[];
+extern const char kFileUrlsNotAllowedInExtensionNavigations[];
extern const char kFrameNotFoundError[];
extern const char kNoCrashBrowserError[];
extern const char kNoCurrentWindowError[];
@@ -110,7 +111,7 @@ extern const char kScreenshotsDisabledByDlp[];
extern const char kCannotUpdateMuteCaptured[];
extern const char kCannotDetermineLanguageOfUnloadedTab[];
extern const char kMissingLockWindowFullscreenPrivatePermission[];
-extern const char kJavaScriptUrlsNotAllowedInTabsUpdate[];
+extern const char kJavaScriptUrlsNotAllowedInExtensionNavigations[];
extern const char kBrowserWindowNotAllowed[];
extern const char kLockedFullscreenModeNewTabError[];
extern const char kGroupParamsError[];
diff --git a/chromium/chrome/browser/extensions/api/tabs/windows_event_router.h b/chromium/chrome/browser/extensions/api/tabs/windows_event_router.h
index 9db3a0d58c4..f5cadaf2e34 100644
--- a/chromium/chrome/browser/extensions/api/tabs/windows_event_router.h
+++ b/chromium/chrome/browser/extensions/api/tabs/windows_event_router.h
@@ -88,7 +88,7 @@ class WindowsEventRouter : public AppWindowRegistry::Observer,
// The profile the currently focused window belongs to; either the main or
// incognito profile or NULL (none of the above). We remember this in order
// to correctly handle focus changes between non-OTR and OTR windows.
- raw_ptr<Profile, DanglingUntriaged> focused_profile_;
+ raw_ptr<Profile, AcrossTasksDanglingUntriaged> focused_profile_;
// The currently focused window. We keep this so as to avoid sending multiple
// windows.onFocusChanged events with the same windowId.
diff --git a/chromium/chrome/browser/extensions/api/terminal/terminal_private_api.cc b/chromium/chrome/browser/extensions/api/terminal/terminal_private_api.cc
index 2872ac2f667..b5156852191 100644
--- a/chromium/chrome/browser/extensions/api/terminal/terminal_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/terminal/terminal_private_api.cc
@@ -12,6 +12,7 @@
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
+#include "ash/webui/settings/public/constants/routes.mojom.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
@@ -46,7 +47,6 @@
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/settings_window_manager_chromeos.h"
-#include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/api/terminal_private.h"
#include "chromeos/ash/components/dbus/cicerone/cicerone_client.h"
diff --git a/chromium/chrome/browser/extensions/api/user_scripts/user_scripts_apitest.cc b/chromium/chrome/browser/extensions/api/user_scripts/user_scripts_apitest.cc
new file mode 100644
index 00000000000..c641309fa82
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/user_scripts/user_scripts_apitest.cc
@@ -0,0 +1,52 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "components/version_info/channel.h"
+#include "content/public/test/browser_test.h"
+#include "extensions/common/extension_features.h"
+#include "net/dns/mock_host_resolver.h"
+
+namespace extensions {
+
+class UserScriptsAPITest : public ExtensionApiTest {
+ public:
+ UserScriptsAPITest();
+ UserScriptsAPITest(const UserScriptsAPITest&) = delete;
+ const UserScriptsAPITest& operator=(const UserScriptsAPITest&) = delete;
+ ~UserScriptsAPITest() override = default;
+
+ void SetUpOnMainThread() override {
+ ExtensionApiTest::SetUpOnMainThread();
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ }
+
+ private:
+ // The userScripts API is currently behind a channel and feature restriction.
+ // TODO(crbug.com/1472902): Remove channel override when user scripts API goes
+ // to stable.
+ ScopedCurrentChannel current_channel_override_{
+ version_info::Channel::UNKNOWN};
+ base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+UserScriptsAPITest::UserScriptsAPITest() {
+ scoped_feature_list_.InitAndEnableFeature(
+ extensions_features::kApiUserScripts);
+}
+
+IN_PROC_BROWSER_TEST_F(UserScriptsAPITest, RegisterUserScripts) {
+ ASSERT_TRUE(RunExtensionTest("user_scripts/register")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(UserScriptsAPITest, GetUserScripts) {
+ ASSERT_TRUE(RunExtensionTest("user_scripts/get_scripts")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(UserScriptsAPITest, UnregisterUserScripts) {
+ ASSERT_TRUE(RunExtensionTest("user_scripts/unregister")) << message_;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chromium/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
index 9984c0e75b2..15bb28c4fa6 100644
--- a/chromium/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
+++ b/chromium/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -13,6 +13,7 @@
#include "ash/public/cpp/clipboard_history_controller.h"
#include "ash/public/cpp/clipboard_image_model_factory.h"
#include "ash/public/cpp/keyboard/keyboard_types.h"
+#include "ash/webui/settings/public/constants/routes.mojom-forward.h"
#include "base/check.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
@@ -24,7 +25,6 @@
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
#include "chrome/browser/ui/settings_window_manager_chromeos.h"
-#include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom-forward.h"
#include "chromeos/constants/chromeos_features.h"
#include "chromeos/crosapi/mojom/clipboard_history.mojom.h"
#include "components/user_manager/user_manager.h"
@@ -127,7 +127,8 @@ bool SendKeyEventImpl(const std::string& type,
SendProcessKeyEvent(ui::ET_KEY_PRESSED, host);
- ui::KeyEvent char_event(key_value, code, ui::DomCode::NONE, ui::EF_NONE);
+ ui::KeyEvent char_event = ui::KeyEvent::FromCharacter(
+ key_value, code, ui::DomCode::NONE, ui::EF_NONE);
if (tic)
tic->InsertChar(char_event);
SendProcessKeyEvent(ui::ET_KEY_RELEASED, host);
@@ -517,9 +518,6 @@ void ChromeVirtualKeyboardDelegate::OnHasInputDevices(
"newheader",
base::FeatureList::IsEnabled(ash::features::kVirtualKeyboardNewHeader)));
features.Append(GenerateFeatureFlag(
- "multitouch",
- base::FeatureList::IsEnabled(ash::features::kVirtualKeyboardMultitouch)));
- features.Append(GenerateFeatureFlag(
"roundCorners", base::FeatureList::IsEnabled(
ash::features::kVirtualKeyboardRoundCorners)));
features.Append(
@@ -540,6 +538,9 @@ void ChromeVirtualKeyboardDelegate::OnHasInputDevices(
features.Append(GenerateFeatureFlag(
"japanesefunctionrow",
base::FeatureList::IsEnabled(ash::features::kJapaneseFunctionRow)));
+ features.Append(GenerateFeatureFlag(
+ "virtualkeyboardremovenacl",
+ base::FeatureList::IsEnabled(ash::features::kVirtualKeyboardRemoveNacl)));
results.Set("features", std::move(features));
diff --git a/chromium/chrome/browser/extensions/api/virtual_keyboard_private/virtual_keyboard_private_apitest.cc b/chromium/chrome/browser/extensions/api/virtual_keyboard_private/virtual_keyboard_private_apitest.cc
index a1c970a77cf..92d43cdd507 100644
--- a/chromium/chrome/browser/extensions/api/virtual_keyboard_private/virtual_keyboard_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/virtual_keyboard_private/virtual_keyboard_private_apitest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "ash/public/cpp/clipboard_history_controller.h"
+#include "base/containers/flat_map.h"
#include "base/path_service.h"
#include "chrome/browser/ash/login/lock/screen_locker_tester.h"
#include "chrome/browser/extensions/extension_apitest.h"
@@ -31,7 +32,7 @@ void CopyBitmapItem() {
}
void CopyFileItem() {
- const std::unordered_map<std::u16string, std::u16string> input_data = {
+ const base::flat_map<std::u16string, std::u16string> input_data = {
{u"fs/sources", u"/path/to/My%20File.txt"}};
base::Pickle input_data_pickle;
ui::WriteCustomDataToPickle(input_data, &input_data_pickle);
diff --git a/chromium/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc b/chromium/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
index b3ab5fbff15..85c934eaf4e 100644
--- a/chromium/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
@@ -16,7 +16,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/common/extensions/api/vpn_provider.h"
#include "chromeos/ash/components/network/shill_property_handler.h"
-#include "chromeos/crosapi/mojom/vpn_service.mojom-test-utils.h"
+#include "chromeos/crosapi/mojom/vpn_service.mojom.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/pepper_vpn_provider_resource_host_proxy.h"
#include "content/public/browser/vpn_service_proxy.h"
@@ -41,7 +41,6 @@
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
-#include "chromeos/crosapi/mojom/test_controller.mojom-test-utils.h"
#include "chromeos/crosapi/mojom/test_controller.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#endif
@@ -208,9 +207,11 @@ class VpnProviderApiTestLacros : public VpnProviderApiTestBase {
LOG(ERROR) << "Unsupported ash version.";
return false;
}
- crosapi::mojom::TestControllerAsyncWaiter waiter{
- service->GetRemote<crosapi::mojom::TestController>().get()};
- waiter.BindTestShillController(controller_.BindNewPipeAndPassReceiver());
+ base::test::TestFuture<void> future;
+ service->GetRemote<crosapi::mojom::TestController>()
+ ->BindTestShillController(controller_.BindNewPipeAndPassReceiver(),
+ future.GetCallback());
+ EXPECT_TRUE(future.Wait());
return true;
}
@@ -650,9 +651,9 @@ IN_PROC_BROWSER_TEST_F(VpnProviderApiTest, PlatformMessage) {
extension_id(), remote.BindNewPipeAndPassReceiver(),
receiver.BindNewPipeAndPassRemote());
- crosapi::mojom::VpnServiceForExtensionAsyncWaiter waiter{remote.get()};
- crosapi::mojom::VpnErrorResponsePtr error;
- waiter.CreateConfiguration(kTestConfig, &error);
+ base::test::TestFuture<crosapi::mojom::VpnErrorResponsePtr> future;
+ remote->CreateConfiguration(kTestConfig, future.GetCallback());
+ auto error = future.Take();
ASSERT_FALSE(error) << "CreateConfiguration failed with |message| = "
<< error->message.value_or(std::string{});
diff --git a/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc b/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
index 143cbd58c2d..275a78505da 100644
--- a/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
+++ b/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
@@ -33,8 +33,9 @@ bool FrameNavigationState::allow_extension_scheme_ = false;
DOCUMENT_USER_DATA_KEY_IMPL(FrameNavigationState);
-FrameNavigationState::FrameNavigationState(content::RenderFrameHost* rfh)
- : content::DocumentUserData<FrameNavigationState>(rfh) {}
+FrameNavigationState::FrameNavigationState(
+ content::RenderFrameHost* render_frame_host)
+ : content::DocumentUserData<FrameNavigationState>(render_frame_host) {}
FrameNavigationState::~FrameNavigationState() = default;
// static
diff --git a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
index 1639909dca1..e72083bb18a 100644
--- a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
+++ b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
@@ -430,11 +430,11 @@ bool WebNavigationTabObserver::IsReferenceFragmentNavigation(
}
void WebNavigationTabObserver::RenderFrameHostPendingDeletion(
- content::RenderFrameHost* pending_delete_rfh) {
- // The |pending_delete_rfh| and its children are now pending deletion.
- // Stop tracking them.
+ content::RenderFrameHost* pending_delete_render_frame_host) {
+ // The |pending_delete_render_frame_host| and its children are now pending
+ // deletion. Stop tracking them.
- pending_delete_rfh->ForEachRenderFrameHost(
+ pending_delete_render_frame_host->ForEachRenderFrameHost(
[this](content::RenderFrameHost* render_frame_host) {
auto* navigation_state =
FrameNavigationState::GetForCurrentDocument(render_frame_host);
diff --git a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
index e6308c358c0..3d5386ddb06 100644
--- a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -111,8 +111,9 @@ class DelayLoadStartAndExecuteJavascript : public TabStripModelObserver,
// WebContentsObserver:
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override {
- if (navigation_handle->GetURL() != delay_url_ || !rfh_)
+ if (navigation_handle->GetURL() != delay_url_ || !render_frame_host_) {
return;
+ }
auto throttle =
std::make_unique<WillStartRequestObserverThrottle>(navigation_handle);
@@ -120,11 +121,11 @@ class DelayLoadStartAndExecuteJavascript : public TabStripModelObserver,
navigation_handle->RegisterThrottleForTesting(std::move(throttle));
if (has_user_gesture_) {
- rfh_->ExecuteJavaScriptWithUserGestureForTests(base::UTF8ToUTF16(script_),
- base::NullCallback());
+ render_frame_host_->ExecuteJavaScriptWithUserGestureForTests(
+ base::UTF8ToUTF16(script_), base::NullCallback());
} else {
- rfh_->ExecuteJavaScriptForTests(base::UTF8ToUTF16(script_),
- base::NullCallback());
+ render_frame_host_->ExecuteJavaScriptForTests(base::UTF8ToUTF16(script_),
+ base::NullCallback());
}
script_was_executed_ = true;
}
@@ -143,7 +144,7 @@ class DelayLoadStartAndExecuteJavascript : public TabStripModelObserver,
}
if (navigation_handle->IsInMainFrame())
- rfh_ = navigation_handle->GetRenderFrameHost();
+ render_frame_host_ = navigation_handle->GetRenderFrameHost();
}
void set_has_user_gesture(bool has_user_gesture) {
@@ -184,7 +185,8 @@ class DelayLoadStartAndExecuteJavascript : public TabStripModelObserver,
std::string script_;
bool has_user_gesture_ = false;
bool script_was_executed_ = false;
- raw_ptr<content::RenderFrameHost, DanglingUntriaged> rfh_ = nullptr;
+ raw_ptr<content::RenderFrameHost, AcrossTasksDanglingUntriaged>
+ render_frame_host_ = nullptr;
};
// Handles requests for URLs with paths of "/test*" sent to the test server, so
@@ -479,6 +481,7 @@ IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, UserAction) {
params.is_editable = false;
params.media_type = blink::mojom::ContextMenuDataMediaType::kNone;
params.page_url = url;
+ params.frame_url = url;
params.link_url = extension->GetResourceURL("b.html");
// Get the child frame, which will be the one associated with the context
diff --git a/chromium/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chromium/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index 9955d59dad3..95f82df0033 100644
--- a/chromium/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -39,6 +39,7 @@
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/api/declarative_net_request/test_utils.h"
+#include "extensions/browser/api/web_request/extension_web_request_event_router.h"
#include "extensions/browser/api/web_request/upload_data_presenter.h"
#include "extensions/browser/api/web_request/web_request_api.h"
#include "extensions/browser/api/web_request/web_request_api_constants.h"
@@ -151,12 +152,12 @@ TEST_F(ExtensionWebRequestTest, AddAndRemoveListeners) {
// Add two listeners.
ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
- &profile_, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName1,
+ &profile_, ext_id, ext_id, kEventName, kSubEventName1,
ExtensionWebRequestEventRouter::RequestFilter(), 0,
1 /* render_process_id */, 0, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
- &profile_, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName2,
+ &profile_, ext_id, ext_id, kEventName, kSubEventName2,
ExtensionWebRequestEventRouter::RequestFilter(), 0,
1 /* render_process_id */, 0, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
@@ -167,20 +168,18 @@ TEST_F(ExtensionWebRequestTest, AddAndRemoveListeners) {
// Now remove the listeners one at a time, verifying the counts after each
// removal.
- ExtensionWebRequestEventRouter::GetInstance()->UpdateActiveListener(
- ExtensionWebRequestEventRouter::ListenerUpdateType::kRemove,
- ExtensionWebRequestEventRouter::GetBrowserContextID(&profile_), ext_id,
- kSubEventName1, extensions::kMainThreadId,
+ ExtensionWebRequestEventRouter::GetInstance()->UpdateActiveListenerForTesting(
+ &profile_, ExtensionWebRequestEventRouter::ListenerUpdateType::kRemove,
+ ext_id, kSubEventName1, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
EXPECT_EQ(
1u,
ExtensionWebRequestEventRouter::GetInstance()->GetListenerCountForTesting(
&profile_, kEventName));
- ExtensionWebRequestEventRouter::GetInstance()->UpdateActiveListener(
- ExtensionWebRequestEventRouter::ListenerUpdateType::kRemove,
- ExtensionWebRequestEventRouter::GetBrowserContextID(&profile_), ext_id,
- kSubEventName2, extensions::kMainThreadId,
+ ExtensionWebRequestEventRouter::GetInstance()->UpdateActiveListenerForTesting(
+ &profile_, ExtensionWebRequestEventRouter::ListenerUpdateType::kRemove,
+ ext_id, kSubEventName2, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
EXPECT_EQ(
0u,
@@ -200,23 +199,23 @@ TEST_F(ExtensionWebRequestTest, BrowserContextShutdown) {
const std::string kSubEventName = kEventName + "/1";
EXPECT_EQ(0u,
event_router->GetListenerCountForTesting(&profile_, kEventName));
- EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerImpl(&profile_));
+ EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerForTesting(&profile_));
// Add two listeners for the main profile.
event_router->AddEventListener(
- &profile_, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName,
+ &profile_, ext_id, ext_id, kEventName, kSubEventName,
ExtensionWebRequestEventRouter::RequestFilter(), 0,
1 /* render_process_id */, 0, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
event_router->AddEventListener(
- &profile_, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName,
+ &profile_, ext_id, ext_id, kEventName, kSubEventName,
ExtensionWebRequestEventRouter::RequestFilter(), 0,
2 /* render_process_id */, 0, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
event_router->IncrementExtraHeadersListenerCount(&profile_);
EXPECT_EQ(2u,
event_router->GetListenerCountForTesting(&profile_, kEventName));
- EXPECT_TRUE(event_router->HasAnyExtraHeadersListenerImpl(&profile_));
+ EXPECT_TRUE(event_router->HasAnyExtraHeadersListenerForTesting(&profile_));
// Create an off-the-record profile.
auto otr_profile_id = Profile::OTRProfileID::CreateUniqueForTesting();
@@ -232,29 +231,29 @@ TEST_F(ExtensionWebRequestTest, BrowserContextShutdown) {
event_router->OnOTRBrowserContextCreated(&profile_, otr_profile);
EXPECT_EQ(0u,
event_router->GetListenerCountForTesting(otr_profile, kEventName));
- EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerImpl(otr_profile));
+ EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerForTesting(otr_profile));
// Add two listeners for the otr profile.
event_router->AddEventListener(
- otr_profile, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName,
+ otr_profile, ext_id, ext_id, kEventName, kSubEventName,
ExtensionWebRequestEventRouter::RequestFilter(), 0,
1 /* render_process_id */, 0, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
event_router->AddEventListener(
- otr_profile, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName,
+ otr_profile, ext_id, ext_id, kEventName, kSubEventName,
ExtensionWebRequestEventRouter::RequestFilter(), 0,
2 /* render_process_id */, 0, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
event_router->IncrementExtraHeadersListenerCount(otr_profile);
EXPECT_EQ(2u,
event_router->GetListenerCountForTesting(otr_profile, kEventName));
- EXPECT_TRUE(event_router->HasAnyExtraHeadersListenerImpl(otr_profile));
+ EXPECT_TRUE(event_router->HasAnyExtraHeadersListenerForTesting(otr_profile));
// Simulate the OTR being destroyed.
event_router->OnOTRBrowserContextDestroyed(&profile_, otr_profile);
EXPECT_EQ(0u,
event_router->GetListenerCountForTesting(otr_profile, kEventName));
- EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerImpl(otr_profile));
+ EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerForTesting(otr_profile));
// We can't just delete the profile, because the call comes through the
// WebRequestAPI instance for that profile, and creating that requires
@@ -263,7 +262,7 @@ TEST_F(ExtensionWebRequestTest, BrowserContextShutdown) {
event_router->OnBrowserContextShutdown(&profile_);
EXPECT_EQ(0u,
event_router->GetListenerCountForTesting(&profile_, kEventName));
- EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerImpl(&profile_));
+ EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerForTesting(&profile_));
}
namespace {
diff --git a/chromium/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chromium/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index 6b76ea8fcb3..5c19a78e7dc 100644
--- a/chromium/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -98,6 +98,7 @@
#include "content/public/test/url_loader_interceptor.h"
#include "content/public/test/url_loader_monitor.h"
#include "content/public/test/web_transport_simple_test_server.h"
+#include "extensions/browser/api/web_request/extension_web_request_event_router.h"
#include "extensions/browser/api/web_request/web_request_api.h"
#include "extensions/browser/background_script_executor.h"
#include "extensions/browser/blocked_action_type.h"
@@ -1290,8 +1291,8 @@ IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
// Check that reloading an extension that runs in incognito split mode and
// has two active background pages with registered events does not crash the
// browser. Regression test for http://crbug.com/224094
-// Flaky on linux-lacros. See http://crbug.com/1423252
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// Flaky on linux-lacros and Linux. See http://crbug.com/1423252
+#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX)
#define MAYBE_IncognitoSplitModeReload DISABLED_IncognitoSplitModeReload
#else
#define MAYBE_IncognitoSplitModeReload IncognitoSplitModeReload
@@ -2837,7 +2838,7 @@ IN_PROC_BROWSER_TEST_P(ExtensionWebRequestMockedClockTest,
LoadExtension(test_dir.AppendASCII("extension_1"));
ASSERT_TRUE(extension_1);
ASSERT_TRUE(ready_1_listener.WaitUntilSatisfied());
- const std::string extension_id_1 = extension_1->id();
+ const ExtensionId extension_id_1 = extension_1->id();
// Load the second extension.
ExtensionTestMessageListener ready_2_listener("ready_2");
@@ -2845,7 +2846,7 @@ IN_PROC_BROWSER_TEST_P(ExtensionWebRequestMockedClockTest,
LoadExtension(test_dir.AppendASCII("extension_2"));
ASSERT_TRUE(extension_2);
ASSERT_TRUE(ready_2_listener.WaitUntilSatisfied());
- const std::string extension_id_2 = extension_2->id();
+ const ExtensionId extension_id_2 = extension_2->id();
const ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
EXPECT_LT(prefs->GetLastUpdateTime(extension_id_1),
@@ -3667,8 +3668,14 @@ IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
// Ensure we don't strip off initiator incorrectly in web request events when
// both the normal and incognito contexts are active. Regression test for
// crbug.com/934398.
+// Flaky on Linux. See http://crbug.com/1423252
+#if BUILDFLAG(IS_LINUX)
+#define MAYBE_Initiator_SplitIncognito DISABLED_Initiator_SplitIncognito
+#else
+#define MAYBE_Initiator_SplitIncognito Initiator_SplitIncognito
+#endif
IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
- Initiator_SplitIncognito) {
+ MAYBE_Initiator_SplitIncognito) {
embedded_test_server()->ServeFilesFromSourceDirectory("chrome/test/data");
ASSERT_TRUE(embedded_test_server()->Start());
@@ -5602,6 +5609,7 @@ IN_PROC_BROWSER_TEST_F(ManifestV3WebRequestApiTest, WebRequestBlocking) {
EXPECT_EQ(net::OK, nav_observer.last_net_error_code());
}
+ base::HistogramTester histogram_tester;
// Now, navigate to block.example. This navigation should be blocked.
{
content::TestNavigationObserver nav_observer(web_contents);
@@ -5610,6 +5618,16 @@ IN_PROC_BROWSER_TEST_F(ManifestV3WebRequestApiTest, WebRequestBlocking) {
embedded_test_server()->GetURL("block.example", "/simple.html")));
EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, nav_observer.last_net_error_code());
}
+
+ // TODO(crbug.com/1441221): Create more targeted tests to confirm when metrics
+ // should be firing or not.
+ // Web request API events should not have metrics emitted for SW/MV3.
+ histogram_tester.ExpectTotalCount(
+ "Extensions.Events.DispatchToAckTime.ExtensionServiceWorker2",
+ /*expected_count=*/0);
+ histogram_tester.ExpectTotalCount(
+ "Extensions.Events.DispatchToAckLongTime.ExtensionServiceWorker2",
+ /*expected_count=*/0);
}
// Tests a service worker-based extension registering multiple webRequest events
@@ -6420,6 +6438,61 @@ IN_PROC_BROWSER_TEST_F(ManifestV3WebRequestApiTest,
<< errors[0]->message();
}
+// Tests that an extension that doesn't have the `webView` permission cannot
+// manually create and add a WebRequestEvent that specifies a webViewInstanceId.
+// TODO(tjudkins): It would be good to also stop this on the JS layer by not
+// allowing extensions to manually create and add WebRequestEvents.
+// Regression test for crbug.com/1472830
+IN_PROC_BROWSER_TEST_F(ManifestV3WebRequestApiTest,
+ TestWebviewIdSpecifiedOnEvent_NoPermission) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+
+ static constexpr char kManifest[] =
+ R"({
+ "name": "MV3 WebRequest",
+ "version": "0.1",
+ "manifest_version": 3,
+ "permissions": ["webRequest"],
+ "host_permissions": [ "http://example.com/*" ],
+ "background": {"service_worker": "background.js"}
+ })";
+ // The extension tries to add a listener; this will fail asynchronously
+ // as a part of the webRequestInternal API trying to add the listener.
+ // This results in runtime.lastError being set, but since it's an
+ // internal API, there's no way for the extension to catch the error.
+ static constexpr char kBackgroundJs[] =
+ R"(let event = new chrome.webRequest.onBeforeRequest.constructor(
+ 'webRequest.onBeforeRequest',
+ undefined,
+ undefined,
+ undefined,
+ 1); // webViewInstanceId
+ event.addListener(() => {},
+ {urls: ['*://*.example.com/*']});)";
+
+ // Since we can't catch the error in the extension's JS, we instead listen to
+ // the error come into the error console.
+ ErrorConsoleTestObserver error_observer(1u, profile());
+ error_observer.EnableErrorCollection();
+
+ // Load the extension and wait for the error to come.
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundJs);
+ const Extension* extension = LoadExtension(test_dir.UnpackedPath());
+
+ ASSERT_TRUE(extension);
+ error_observer.WaitForErrors();
+
+ const ErrorList& errors =
+ ErrorConsole::Get(profile())->GetErrorsForExtension(extension->id());
+ ASSERT_EQ(1u, errors.size());
+ EXPECT_EQ(u"Unchecked runtime.lastError: Missing webview permission.",
+ errors[0]->message());
+ EXPECT_EQ(0u, web_request_router()->GetListenerCountForTesting(
+ profile(), "webRequest.onBeforeRequest"));
+}
+
IN_PROC_BROWSER_TEST_F(ManifestV3WebRequestApiTest, RecordUkmOnNavigation) {
ASSERT_TRUE(StartEmbeddedTestServer());
TestExtensionDir test_dir1;
diff --git a/chromium/chrome/browser/extensions/api/web_view/chrome_web_view_internal_api.cc b/chromium/chrome/browser/extensions/api/web_view/chrome_web_view_internal_api.cc
index 020d47ebc04..b4f4a634e88 100644
--- a/chromium/chrome/browser/extensions/api/web_view/chrome_web_view_internal_api.cc
+++ b/chromium/chrome/browser/extensions/api/web_view/chrome_web_view_internal_api.cc
@@ -27,10 +27,9 @@ ChromeWebViewInternalContextMenusCreateFunction::Run() {
MenuItem::Id id(
Profile::FromBrowserContext(browser_context())->IsOffTheRecord(),
- MenuItem::ExtensionKey(
- extension_id(),
- GetSenderWebContents()->GetPrimaryMainFrame()->GetProcess()->GetID(),
- params->instance_id));
+ MenuItem::ExtensionKey(extension_id(),
+ render_frame_host()->GetProcess()->GetID(),
+ params->instance_id));
if (params->create_properties.id) {
id.string_uid = *params->create_properties.id;
@@ -62,10 +61,9 @@ ChromeWebViewInternalContextMenusUpdateFunction::Run() {
Profile* profile = Profile::FromBrowserContext(browser_context());
MenuItem::Id item_id(
profile->IsOffTheRecord(),
- MenuItem::ExtensionKey(
- extension_id(),
- GetSenderWebContents()->GetPrimaryMainFrame()->GetProcess()->GetID(),
- params->instance_id));
+ MenuItem::ExtensionKey(extension_id(),
+ render_frame_host()->GetProcess()->GetID(),
+ params->instance_id));
if (params->id.as_string)
item_id.string_uid = *params->id.as_string;
@@ -92,10 +90,9 @@ ChromeWebViewInternalContextMenusRemoveFunction::Run() {
MenuItem::Id id(
Profile::FromBrowserContext(browser_context())->IsOffTheRecord(),
- MenuItem::ExtensionKey(
- extension_id(),
- GetSenderWebContents()->GetPrimaryMainFrame()->GetProcess()->GetID(),
- params->instance_id));
+ MenuItem::ExtensionKey(extension_id(),
+ render_frame_host()->GetProcess()->GetID(),
+ params->instance_id));
if (params->menu_item_id.as_string) {
id.string_uid = *params->menu_item_id.as_string;
@@ -127,8 +124,7 @@ ChromeWebViewInternalContextMenusRemoveAllFunction::Run() {
MenuManager* menu_manager =
MenuManager::Get(Profile::FromBrowserContext(browser_context()));
menu_manager->RemoveAllContextItems(MenuItem::ExtensionKey(
- extension_id(),
- GetSenderWebContents()->GetPrimaryMainFrame()->GetProcess()->GetID(),
+ extension_id(), render_frame_host()->GetProcess()->GetID(),
params->instance_id));
return RespondNow(NoArguments());
diff --git a/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc b/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc
index ed1df85124e..dd65d77b192 100644
--- a/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h"
#include <memory>
+#include <string>
#include <utility>
#include <vector>
@@ -12,6 +13,8 @@
#include "base/lazy_instance.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
+#include "components/media_device_salt/media_device_salt_service.h"
#include "content/public/browser/audio_service.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@@ -23,6 +26,7 @@
#include "extensions/common/error_utils.h"
#include "extensions/common/permissions/permissions_data.h"
#include "media/audio/audio_system.h"
+#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -102,7 +106,12 @@ WebrtcAudioPrivateFunction::WebrtcAudioPrivateFunction() {}
WebrtcAudioPrivateFunction::~WebrtcAudioPrivateFunction() {}
+url::Origin WebrtcAudioPrivateFunction::GetExtensionOrigin() const {
+ return url::Origin::Create(source_url());
+}
+
std::string WebrtcAudioPrivateFunction::CalculateHMAC(
+ const std::string& extension_salt,
const std::string& raw_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -114,18 +123,40 @@ std::string WebrtcAudioPrivateFunction::CalculateHMAC(
if (media::AudioDeviceDescription::IsDefaultDevice(raw_id))
return media::AudioDeviceDescription::kDefaultDeviceId;
- url::Origin security_origin =
- url::Origin::Create(source_url().DeprecatedGetOriginAsURL());
- return content::GetHMACForMediaDeviceID(device_id_salt(), security_origin,
+ return content::GetHMACForMediaDeviceID(extension_salt, GetExtensionOrigin(),
raw_id);
}
-void WebrtcAudioPrivateFunction::InitDeviceIDSalt() {
- device_id_salt_ = browser_context()->GetMediaDeviceIDSalt();
+void WebrtcAudioPrivateFunction::GetSalt(
+ const url::Origin& origin,
+ base::OnceCallback<void(const std::string&)> salt_callback) {
+ media_device_salt::MediaDeviceSaltService* salt_service =
+ MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext(
+ browser_context());
+ if (!salt_service) {
+ std::move(salt_callback).Run(browser_context()->UniqueId());
+ return;
+ }
+
+ salt_service->GetSalt(blink::StorageKey::CreateFirstParty(origin),
+ std::move(salt_callback));
+}
+
+void WebrtcAudioPrivateFunction::GetSaltAndDeviceDescriptions(
+ const url::Origin& origin,
+ bool is_input_devices,
+ SaltAndDeviceDescriptionsCallback callback) {
+ GetSalt(origin, base::BindOnce(
+ &WebrtcAudioPrivateFunction::GotSaltForDeviceDescriptions,
+ this, is_input_devices, std::move(callback)));
}
-std::string WebrtcAudioPrivateFunction::device_id_salt() const {
- return device_id_salt_;
+void WebrtcAudioPrivateFunction::GotSaltForDeviceDescriptions(
+ bool is_input_devices,
+ SaltAndDeviceDescriptionsCallback callback,
+ const std::string& device_id_salt) {
+ GetAudioSystem()->GetDeviceDescriptions(
+ is_input_devices, base::BindOnce(std::move(callback), device_id_salt));
}
media::AudioSystem* WebrtcAudioPrivateFunction::GetAudioSystem() {
@@ -137,9 +168,9 @@ media::AudioSystem* WebrtcAudioPrivateFunction::GetAudioSystem() {
ExtensionFunction::ResponseAction WebrtcAudioPrivateGetSinksFunction::Run() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- InitDeviceIDSalt();
- GetAudioSystem()->GetDeviceDescriptions(
- false,
+ GetSaltAndDeviceDescriptions(
+ GetExtensionOrigin(),
+ /*is_input_devices=*/false,
base::BindOnce(
&WebrtcAudioPrivateGetSinksFunction::ReceiveOutputDeviceDescriptions,
this));
@@ -147,12 +178,13 @@ ExtensionFunction::ResponseAction WebrtcAudioPrivateGetSinksFunction::Run() {
}
void WebrtcAudioPrivateGetSinksFunction::ReceiveOutputDeviceDescriptions(
+ const std::string& extension_salt,
media::AudioDeviceDescriptions sink_devices) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto results = std::make_unique<SinkInfoVector>();
for (const media::AudioDeviceDescription& description : sink_devices) {
wap::SinkInfo info;
- info.sink_id = CalculateHMAC(description.unique_id);
+ info.sink_id = CalculateHMAC(extension_salt, description.unique_id);
info.sink_label = description.device_name;
// TODO(joi): Add other parameters.
results->push_back(std::move(info));
@@ -161,38 +193,37 @@ void WebrtcAudioPrivateGetSinksFunction::ReceiveOutputDeviceDescriptions(
}
WebrtcAudioPrivateGetAssociatedSinkFunction::
- WebrtcAudioPrivateGetAssociatedSinkFunction() {}
+ WebrtcAudioPrivateGetAssociatedSinkFunction() = default;
WebrtcAudioPrivateGetAssociatedSinkFunction::
- ~WebrtcAudioPrivateGetAssociatedSinkFunction() {}
+ ~WebrtcAudioPrivateGetAssociatedSinkFunction() = default;
ExtensionFunction::ResponseAction
WebrtcAudioPrivateGetAssociatedSinkFunction::Run() {
params_ = wap::GetAssociatedSink::Params::Create(args());
DCHECK_CURRENTLY_ON(BrowserThread::UI);
EXTENSION_FUNCTION_VALIDATE(params_);
- InitDeviceIDSalt();
-
- GetAudioSystem()->GetDeviceDescriptions(
- true, base::BindOnce(&WebrtcAudioPrivateGetAssociatedSinkFunction::
- ReceiveInputDeviceDescriptions,
- this));
+ url::Origin origin = url::Origin::Create(GURL(params_->security_origin));
+ GetSaltAndDeviceDescriptions(
+ origin, /*is_input_devices=*/true,
+ base::BindOnce(&WebrtcAudioPrivateGetAssociatedSinkFunction::
+ ReceiveInputDeviceDescriptions,
+ this, origin));
return RespondLater();
}
void WebrtcAudioPrivateGetAssociatedSinkFunction::
ReceiveInputDeviceDescriptions(
+ const url::Origin& origin,
+ const std::string& salt,
media::AudioDeviceDescriptions source_devices) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- url::Origin security_origin =
- url::Origin::Create(GURL(params_->security_origin));
std::string source_id_in_origin(params_->source_id_in_origin);
// Find the raw source ID for source_id_in_origin.
std::string raw_source_id;
for (const auto& device : source_devices) {
- if (content::DoesMediaDeviceIDMatchHMAC(device_id_salt(), security_origin,
- source_id_in_origin,
+ if (content::DoesMediaDeviceIDMatchHMAC(salt, origin, source_id_in_origin,
device.unique_id)) {
raw_source_id = device.unique_id;
DVLOG(2) << "Found raw ID " << raw_source_id
@@ -201,22 +232,32 @@ void WebrtcAudioPrivateGetAssociatedSinkFunction::
}
}
if (raw_source_id.empty()) {
- CalculateHMACAndReply(absl::nullopt);
+ Reply(media::AudioDeviceDescription::kDefaultDeviceId);
return;
}
+ GetSalt(GetExtensionOrigin(),
+ base::BindOnce(
+ &WebrtcAudioPrivateGetAssociatedSinkFunction::GotExtensionSalt,
+ this, raw_source_id));
+}
+
+void WebrtcAudioPrivateGetAssociatedSinkFunction::GotExtensionSalt(
+ const std::string& raw_source_id,
+ const std::string& extension_salt) {
GetAudioSystem()->GetAssociatedOutputDeviceID(
raw_source_id,
base::BindOnce(
&WebrtcAudioPrivateGetAssociatedSinkFunction::CalculateHMACAndReply,
- this));
+ this, extension_salt));
}
void WebrtcAudioPrivateGetAssociatedSinkFunction::CalculateHMACAndReply(
+ const std::string& extension_salt,
const absl::optional<std::string>& raw_sink_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!raw_sink_id || !raw_sink_id->empty());
// If no |raw_sink_id| is provided, the default device is used.
- Reply(CalculateHMAC(raw_sink_id.value_or(std::string())));
+ Reply(CalculateHMAC(extension_salt, raw_sink_id.value_or(std::string())));
}
void WebrtcAudioPrivateGetAssociatedSinkFunction::Reply(
diff --git a/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h b/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h
index 708e02161d3..8d5d6c7c83e 100644
--- a/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h
+++ b/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.h
@@ -52,31 +52,40 @@ class WebrtcAudioPrivateEventService
// Common base for WebrtcAudioPrivate functions, that provides a
// couple of optionally-used common implementations.
class WebrtcAudioPrivateFunction : public ExtensionFunction {
- protected:
- WebrtcAudioPrivateFunction();
-
+ public:
WebrtcAudioPrivateFunction(const WebrtcAudioPrivateFunction&) = delete;
WebrtcAudioPrivateFunction& operator=(const WebrtcAudioPrivateFunction&) =
delete;
+ protected:
+ WebrtcAudioPrivateFunction();
~WebrtcAudioPrivateFunction() override;
- protected:
- // Calculates a single HMAC, using the extension ID as the security origin.
- std::string CalculateHMAC(const std::string& raw_id);
+ using SaltAndDeviceDescriptionsCallback =
+ base::OnceCallback<void(const std::string&,
+ media::AudioDeviceDescriptions)>;
+ // Calculates the HMAC for `raw_id` using extension ID as the security origin.
+ // `extension_salt` must be the salt for the extension ID.
+ std::string CalculateHMAC(const std::string& extension_salt,
+ const std::string& raw_id);
- // Initializes |device_id_salt_|. Must be called on the UI thread,
- // before any calls to |device_id_salt()|.
- void InitDeviceIDSalt();
+ // Returns the extension ID as an origin.
+ url::Origin GetExtensionOrigin() const;
- // Callable from any thread. Must previously have called
- // |InitDeviceIDSalt()|.
- std::string device_id_salt() const;
+ void GetSalt(const url::Origin&,
+ base::OnceCallback<void(const std::string&)> salt_callback);
+
+ // Returns the device ID salt and device descriptions.
+ void GetSaltAndDeviceDescriptions(const url::Origin& security_origin,
+ bool is_input_devices,
+ SaltAndDeviceDescriptionsCallback callback);
media::AudioSystem* GetAudioSystem();
private:
- std::string device_id_salt_;
+ void GotSaltForDeviceDescriptions(bool is_input_devices,
+ SaltAndDeviceDescriptionsCallback callback,
+ const std::string& device_id_salt);
std::unique_ptr<media::AudioSystem> audio_system_;
};
@@ -95,6 +104,7 @@ class WebrtcAudioPrivateGetSinksFunction : public WebrtcAudioPrivateFunction {
// Receives output device descriptions, calculates HMACs for them and sends
// the response.
void ReceiveOutputDeviceDescriptions(
+ const std::string& extension_salt,
media::AudioDeviceDescriptions sink_devices);
};
@@ -116,10 +126,16 @@ class WebrtcAudioPrivateGetAssociatedSinkFunction
// Receives the input device descriptions, looks up the raw source device ID
// basing on |params|, and requests the associated raw sink ID for it.
void ReceiveInputDeviceDescriptions(
+ const url::Origin& origin,
+ const std::string& salt,
media::AudioDeviceDescriptions source_devices);
- // Receives the raw sink ID, calculates HMAC and calls Reply().
- void CalculateHMACAndReply(const absl::optional<std::string>& raw_sink_id);
+ void GotExtensionSalt(const std::string& raw_source_id,
+ const std::string& extension_salt);
+
+ // Calculates HMAC and calls Reply().
+ void CalculateHMACAndReply(const std::string& extension_salt,
+ const absl::optional<std::string>& raw_sink_id);
// Receives the associated sink ID as HMAC and sends the response.
void Reply(const std::string& hmac);
diff --git a/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc b/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
index f6c71b8346d..f3a5ab79336 100644
--- a/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc
@@ -23,6 +23,7 @@
#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/media/webrtc/media_device_salt_service_factory.h"
#include "chrome/browser/media/webrtc/webrtc_log_uploader.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/recently_audible_helper.h"
@@ -30,6 +31,7 @@
#include "chrome/common/buildflags.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
+#include "components/media_device_salt/media_device_salt_service.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "content/public/browser/audio_service.h"
#include "content/public/browser/browser_thread.h"
@@ -49,6 +51,7 @@
#include "net/test/embedded_test_server/http_response.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/common/storage_key/storage_key.h"
#if BUILDFLAG(IS_WIN)
#include "base/win/windows_version.h"
@@ -123,6 +126,16 @@ class WebrtcAudioPrivateTest : public AudioWaitingExtensionTest {
return RunFunctionAndReturnSingleResult(function.get(), "[]", profile());
}
+ std::string GetMediaDeviceIDSalt(const url::Origin& origin) {
+ media_device_salt::MediaDeviceSaltService* salt_service =
+ MediaDeviceSaltServiceFactory::GetInstance()->GetForBrowserContext(
+ profile());
+ base::test::TestFuture<const std::string&> future;
+ salt_service->GetSalt(blink::StorageKey::CreateFirstParty(origin),
+ future.GetCallback());
+ return future.Get();
+ }
+
GURL source_url_;
};
@@ -152,13 +165,12 @@ IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetSinks) {
const std::string* sink_id = dict.FindString("sinkId");
EXPECT_TRUE(sink_id);
+ url::Origin origin = url::Origin::Create(source_url_);
std::string expected_id =
media::AudioDeviceDescription::IsDefaultDevice(it->unique_id)
? media::AudioDeviceDescription::kDefaultDeviceId
- : content::GetHMACForMediaDeviceID(
- profile()->GetMediaDeviceIDSalt(),
- url::Origin::Create(source_url_.DeprecatedGetOriginAsURL()),
- it->unique_id);
+ : content::GetHMACForMediaDeviceID(GetMediaDeviceIDSalt(origin),
+ origin, it->unique_id);
EXPECT_EQ(expected_id, *sink_id);
const std::string* sink_label = dict.FindString("sinkLabel");
@@ -189,13 +201,13 @@ IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetAssociatedSink) {
std::string raw_device_id = device.unique_id;
VLOG(2) << "Trying to find associated sink for device " << raw_device_id;
- GURL origin(GURL("http://www.google.com/").DeprecatedGetOriginAsURL());
+ GURL gurl("http://www.google.com/");
+ url::Origin origin = url::Origin::Create(gurl);
std::string source_id_in_origin = content::GetHMACForMediaDeviceID(
- profile()->GetMediaDeviceIDSalt(), url::Origin::Create(origin),
- raw_device_id);
+ GetMediaDeviceIDSalt(origin), origin, raw_device_id);
base::Value::List parameters;
- parameters.Append(origin.spec());
+ parameters.Append(gurl.spec());
parameters.Append(source_id_in_origin);
std::string parameter_string;
JSONWriter::Write(parameters, &parameter_string);
diff --git a/chromium/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc b/chromium/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc
index db80d6505a6..7db82d71476 100644
--- a/chromium/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc
@@ -48,15 +48,16 @@ WebrtcDesktopCapturePrivateChooseDesktopMediaFunction::Run() {
absl::optional<Params> params = Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(params);
- content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
- params->request.guest_process_id,
- params->request.guest_render_frame_id);
+ content::RenderFrameHost* render_frame_host =
+ content::RenderFrameHost::FromID(params->request.guest_process_id,
+ params->request.guest_render_frame_id);
- if (!rfh) {
+ if (!render_frame_host) {
return RespondNow(Error(kTargetNotFoundError));
}
- GURL origin = rfh->GetLastCommittedURL().DeprecatedGetOriginAsURL();
+ GURL origin =
+ render_frame_host->GetLastCommittedURL().DeprecatedGetOriginAsURL();
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
::switches::kAllowHttpScreenCapture) &&
!network::IsUrlPotentiallyTrustworthy(origin)) {
@@ -74,8 +75,8 @@ WebrtcDesktopCapturePrivateChooseDesktopMediaFunction::Run() {
// suppressLocalAudioPlaybackIntended here.
return Execute(*sources, /*exclude_system_audio=*/false,
/*exclude_self_browser_surface=*/false,
- /*suppress_local_audio_playback_intended=*/false, rfh, origin,
- target_name);
+ /*suppress_local_audio_playback_intended=*/false,
+ render_frame_host, origin, target_name);
}
WebrtcDesktopCapturePrivateCancelChooseDesktopMediaFunction::
diff --git a/chromium/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc b/chromium/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
index 34fbd329f70..05b58430520 100644
--- a/chromium/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc
@@ -995,7 +995,7 @@ class WebrtcLoggingPrivateApiStartEventLoggingTestInIncognitoMode
bool WebRtcEventLogCollectionPolicy() const override { return true; }
private:
- raw_ptr<Browser, DanglingUntriaged> browser_{
+ raw_ptr<Browser, AcrossTasksDanglingUntriaged> browser_{
nullptr}; // Does not own the object.
};
diff --git a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
index 4da2a1cf861..6431da933a5 100644
--- a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -69,8 +69,6 @@
#include "url/gurl.h"
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-// TODO(https://crbug.com/1060801): Here and elsewhere, possibly switch build
-// flag to #if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/supervised_user/supervised_user_browser_utils.h"
#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
#include "components/supervised_user/core/browser/supervised_user_service.h"
@@ -223,17 +221,9 @@ const char kEphemeralAppLaunchingNotSupported[] =
"Ephemeral launching of apps is no longer supported.";
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-// Note that the following error doesn't mean an incorrect password was entered,
-// nor that the parent permisison request was canceled by the user, but rather
-// that the Parent permission request after credential entry and acceptance
-// failed due to either a network connection error or some unsatisfied invariant
-// that prevented the request from completing.
-const char kWebstoreParentPermissionFailedError[] =
- "Parent permission request failed";
-
const char kParentBlockedExtensionInstallError[] =
"Parent has blocked extension/app installation";
-#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
+#endif
// The number of user gestures to trace back for the referrer chain.
const int kExtensionReferrerUserGestureLimit = 2;
@@ -658,7 +648,9 @@ void WebstorePrivateBeginInstallWithManifest3Function::
OnExtensionApprovalCanceled() {
if (test_delegate) {
test_delegate->OnExtensionInstallFailure(
- dummy_extension_->id(), kWebstoreParentPermissionFailedError,
+ dummy_extension_->id(),
+ l10n_util::GetStringUTF8(
+ IDS_EXTENSIONS_SUPERVISED_USER_PARENTAL_PERMISSION_FAILURE),
WebstoreInstaller::FailureReason::FAILURE_REASON_CANCELLED);
}
@@ -669,12 +661,16 @@ void WebstorePrivateBeginInstallWithManifest3Function::
OnExtensionApprovalFailed() {
if (test_delegate) {
test_delegate->OnExtensionInstallFailure(
- dummy_extension_->id(), kWebstoreParentPermissionFailedError,
+ dummy_extension_->id(),
+ l10n_util::GetStringUTF8(
+ IDS_EXTENSIONS_SUPERVISED_USER_PARENTAL_PERMISSION_FAILURE),
WebstoreInstaller::FailureReason::FAILURE_REASON_OTHER);
}
- Respond(BuildResponse(api::webstore_private::RESULT_UNKNOWN_ERROR,
- kWebstoreParentPermissionFailedError));
+ Respond(BuildResponse(
+ api::webstore_private::RESULT_UNKNOWN_ERROR,
+ l10n_util::GetStringUTF8(
+ IDS_EXTENSIONS_SUPERVISED_USER_PARENTAL_PERMISSION_FAILURE)));
}
void WebstorePrivateBeginInstallWithManifest3Function::
@@ -856,12 +852,23 @@ WebstorePrivateBeginInstallWithManifest3Function::BuildResponse(
api::webstore_private::Result result,
const std::string& error) {
if (result != api::webstore_private::RESULT_SUCCESS) {
+ // TODO(tjudkins): We should not be using ErrorWithArguments here as it
+ // doesn't play well with promise based API calls (only emitting the error
+ // and dropping the arguments). In almost every case the error directly
+ // responds with the result enum value returned, so instead we should drop
+ // the error and have the caller just base logic on the enum value alone.
+ // In the cases where they do not correspond we should add a new enum value.
+ // We will need to ensure that the Webstore is entirely basing its logic on
+ // the result alone before removing the error.
return ErrorWithArguments(
BeginInstallWithManifest3::Results::Create(result), error);
}
- // The web store expects an empty string on success, so don't use
+ // The old Webstore expects an empty string on success, so don't use
// RESULT_SUCCESS here.
+ // TODO(crbug.com/709120): The new Webstore accepts either the empty string or
+ // RESULT_SUCCESS on success now, so once the old Webstore is turned down this
+ // can be changed over.
return ArgumentList(BeginInstallWithManifest3::Results::Create(
api::webstore_private::RESULT_EMPTY_STRING));
}
@@ -1264,11 +1271,11 @@ WebstorePrivateGetReferrerChainFunction::Run() {
return RespondNow(ArgumentList(
api::webstore_private::GetReferrerChain::Results::Create("")));
- content::RenderFrameHost* rfh = render_frame_host();
- content::RenderFrameHost* outermost_rfh =
- rfh ? rfh->GetOutermostMainFrame() : nullptr;
+ content::RenderFrameHost* outermost_render_frame_host =
+ render_frame_host() ? render_frame_host()->GetOutermostMainFrame()
+ : nullptr;
- if (!outermost_rfh) {
+ if (!outermost_render_frame_host) {
return RespondNow(ErrorWithArguments(
api::webstore_private::GetReferrerChain::Results::Create(""),
kWebstoreUserCancelledError));
@@ -1281,7 +1288,8 @@ WebstorePrivateGetReferrerChainFunction::Run() {
safe_browsing::ReferrerChain referrer_chain;
SafeBrowsingNavigationObserverManager::AttributionResult result =
navigation_observer_manager->IdentifyReferrerChainByRenderFrameHost(
- outermost_rfh, kExtensionReferrerUserGestureLimit, &referrer_chain);
+ outermost_render_frame_host, kExtensionReferrerUserGestureLimit,
+ &referrer_chain);
// If the referrer chain is incomplete we'll append the most recent
// navigations to referrer chain for diagnostic purposes. This only happens if
diff --git a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.h b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
index 957ab11765a..3626267125e 100644
--- a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
+++ b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
@@ -26,8 +26,6 @@
#include "third_party/skia/include/core/SkBitmap.h"
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-// TODO(https://crbug.com/1060801): Here and elsewhere, possibly switch build
-// flag to #if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/supervised_user/supervised_user_extensions_metrics_recorder.h"
#include "extensions/browser/supervised_user_extensions_delegate.h"
#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)