summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/extensions
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-09-29 16:16:15 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-11-09 10:04:06 +0000
commita95a7417ad456115a1ef2da4bb8320531c0821f1 (patch)
treeedcd59279e486d2fd4a8f88a7ed025bcf925c6e6 /chromium/chrome/browser/extensions
parent33fc33aa94d4add0878ec30dc818e34e1dd3cc2a (diff)
BASELINE: Update Chromium to 106.0.5249.126
Change-Id: Ib0bb21c437a7d1686e21c33f2d329f2ac425b7ab Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/438936 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/chrome/browser/extensions')
-rw-r--r--chromium/chrome/browser/extensions/BUILD.gn90
-rw-r--r--chromium/chrome/browser/extensions/api/DEPS2
-rw-r--r--chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc19
-rw-r--r--chromium/chrome/browser/extensions/api/alarms/alarms_apitest.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc71
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.cc11
-rw-r--r--chromium/chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h7
-rw-r--r--chromium/chrome/browser/extensions/api/automation/automation_apitest.cc42
-rw-r--r--chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc72
-rw-r--r--chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h4
-rw-r--r--chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_browsertest.cc72
-rw-r--r--chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc16
-rw-r--r--chromium/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers_unittest.cc90
-rw-r--r--chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc9
-rw-r--r--chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.h3
-rw-r--r--chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api_watcher.cc14
-rw-r--r--chromium/chrome/browser/extensions/api/browsing_data/browsing_data_api.cc95
-rw-r--r--chromium/chrome/browser/extensions/api/browsing_data/browsing_data_api.h8
-rw-r--r--chromium/chrome/browser/extensions/api/certificate_provider/OWNERS1
-rw-r--r--chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc29
-rw-r--r--chromium/chrome/browser/extensions/api/commands/command_service.cc74
-rw-r--r--chromium/chrome/browser/extensions/api/content_settings/content_settings_api.cc19
-rw-r--r--chromium/chrome/browser/extensions/api/content_settings/content_settings_apitest.cc22
-rw-r--r--chromium/chrome/browser/extensions/api/context_menus/context_menu_apitest.cc41
-rw-r--r--chromium/chrome/browser/extensions/api/context_menus/extension_context_menu_browsertest.cc14
-rw-r--r--chromium/chrome/browser/extensions/api/cookies/cookies_api.cc42
-rw-r--r--chromium/chrome/browser/extensions/api/cookies/cookies_api.h3
-rw-r--r--chromium/chrome/browser/extensions/api/cookies/cookies_unittest.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/crash_report_private/crash_report_private_apitest.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc44
-rw-r--r--chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc16
-rw-r--r--chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_browsertest.cc71
-rw-r--r--chromium/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/debugger/debugger_api.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/debugger/debugger_apitest.cc18
-rw-r--r--chromium/chrome/browser/extensions/api/declarative/declarative_apitest.cc49
-rw-r--r--chromium/chrome/browser/extensions/api/declarative_content/content_condition.cc20
-rw-r--r--chromium/chrome/browser/extensions/api/declarative_content/set_icon_apitest.cc223
-rw-r--r--chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc27
-rw-r--r--chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc103
-rw-r--r--chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_unittest.cc62
-rw-r--r--chromium/chrome/browser/extensions/api/desktop_capture/OWNERS3
-rw-r--r--chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc9
-rw-r--r--chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc37
-rw-r--r--chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.h9
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/developer_private_api.cc297
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/developer_private_api.h55
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc427
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/developer_private_apitest.cc107
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.cc97
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/extension_info_generator.h8
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/extension_info_generator_unittest.cc61
-rw-r--r--chromium/chrome/browser/extensions/api/developer_private/inspectable_views_finder.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/device_permissions_manager_unittest.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/document_scan/document_scan_api.h3
-rw-r--r--chromium/chrome/browser/extensions/api/downloads/downloads_api.cc183
-rw-r--r--chromium/chrome/browser/extensions/api/downloads/downloads_api.h25
-rw-r--r--chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc287
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_device_attributes/DIR_METADATA4
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_networking_attributes/enterprise_networking_attributes_ash_apitest.cc30
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc13
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc15
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_reporting_private/DEPS3
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.cc218
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.h68
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc228
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h85
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_apitest.cc234
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc587
-rw-r--r--chromium/chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.mm8
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc78
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc9
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/extension_action/page_action_apitest.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/favicon/favicon_util_unittest.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/file_browser_handler/file_browser_handler_flow_lacros.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.cc288
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h38
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.cc269
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.h56
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.cc342
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h61
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/consent_provider.cc142
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/consent_provider.h78
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/consent_provider_unittest.cc201
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/file_system_apitest.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/file_system_apitest_chromeos.cc46
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/request_file_system_notification.cc39
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/request_file_system_notification.h13
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.cc33
-rw-r--r--chromium/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.h47
-rw-r--r--chromium/chrome/browser/extensions/api/font_settings/font_settings_api.cc12
-rw-r--r--chromium/chrome/browser/extensions/api/font_settings/font_settings_api.h5
-rw-r--r--chromium/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.h2
-rw-r--r--chromium/chrome/browser/extensions/api/gcm/gcm_api.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/history/history_api.cc9
-rw-r--r--chromium/chrome/browser/extensions/api/history/history_api.h7
-rw-r--r--chromium/chrome/browser/extensions/api/i18n/i18n_apitest.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow.cc11
-rw-r--r--chromium/chrome/browser/extensions/api/identity/gaia_remote_consent_flow_unittest.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_apitest.cc287
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc155
-rw-r--r--chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h40
-rw-r--r--chromium/chrome/browser/extensions/api/identity/web_auth_flow.cc14
-rw-r--r--chromium/chrome/browser/extensions/api/idltest/idltest_api.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.h3
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/operation.h2
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc22
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos.cc25
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos_unittest.cc25
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/test_utils.cc54
-rw-r--r--chromium/chrome/browser/extensions/api/image_writer_private/test_utils.h18
-rw-r--r--chromium/chrome/browser/extensions/api/input_ime/input_ime_api.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc51
-rw-r--r--chromium/chrome/browser/extensions/api/language_settings_private/OWNERS2
-rw-r--r--chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api.cc31
-rw-r--r--chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc35
-rw-r--r--chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.cc11
-rw-r--r--chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.h6
-rw-r--r--chromium/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc13
-rw-r--r--chromium/chrome/browser/extensions/api/management/management_api_browsertest.cc9
-rw-r--r--chromium/chrome/browser/extensions/api/management/management_api_unittest.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/mdns/OWNERS4
-rw-r--r--chromium/chrome/browser/extensions/api/mdns/mdns_api.cc12
-rw-r--r--chromium/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc32
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc16
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/messaging_apitest.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/native_message_echo_host.h3
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc37
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.cc38
-rw-r--r--chromium/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h7
-rw-r--r--chromium/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc882
-rw-r--r--chromium/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/notifications/extension_notification_display_helper_factory.h6
-rw-r--r--chromium/chrome/browser/extensions/api/notifications/extension_notification_handler.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/notifications/notifications_api.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/notifications/notifications_apitest.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc351
-rw-r--r--chromium/chrome/browser/extensions/api/offscreen/offscreen_document_manager_browsertest.cc315
-rw-r--r--chromium/chrome/browser/extensions/api/omnibox/omnibox_api.cc43
-rw-r--r--chromium/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc12
-rw-r--r--chromium/chrome/browser/extensions/api/omnibox/suggestion_parser.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/page_capture/page_capture_api.cc55
-rw-r--r--chromium/chrome/browser/extensions/api/page_capture/page_capture_api.h9
-rw-r--r--chromium/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc48
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/OWNERS1
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.cc256
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate.h143
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/password_check_delegate_unittest.cc665
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc227
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.h121
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc94
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h97
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.cc5
-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.cc637
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h133
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_browsertest.cc79
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc548
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.cc21
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.h12
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.cc11
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h7
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils.cc39
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils.h32
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils_unittest.cc45
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.cc187
-rw-r--r--chromium/chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h83
-rw-r--r--chromium/chrome/browser/extensions/api/permissions/permissions_apitest.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h2
-rw-r--r--chromium/chrome/browser/extensions/api/preference/preference_api.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/preference/preference_api_lacros_browsertest.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/preference/preference_helpers.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/printing/print_job_submitter.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/printing/print_job_submitter.h9
-rw-r--r--chromium/chrome/browser/extensions/api/printing/printing_api_handler.h9
-rw-r--r--chromium/chrome/browser/extensions/api/printing/printing_api_handler_unittest.cc17
-rw-r--r--chromium/chrome/browser/extensions/api/processes/processes_api.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/processes/processes_api.h2
-rw-r--r--chromium/chrome/browser/extensions/api/proxy/proxy_apitest.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_api_unittest.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.h3
-rw-r--r--chromium/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h4
-rw-r--r--chromium/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate_unittest.cc19
-rw-r--r--chromium/chrome/browser/extensions/api/runtime/runtime_apitest.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc462
-rw-r--r--chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h99
-rw-r--r--chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc39
-rw-r--r--chromium/chrome/browser/extensions/api/scripting/scripting_api.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/scripting/scripting_apitest.cc21
-rw-r--r--chromium/chrome/browser/extensions/api/sessions/sessions_api.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/sessions/sessions_apitest.cc66
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/OWNERS2
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/generated_prefs.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc37
-rw-r--r--chromium/chrome/browser/extensions/api/shared_storage/shared_storage_private_api_ash.cc3
-rw-r--r--chromium/chrome/browser/extensions/api/shared_storage/shared_storage_private_apitest.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/side_panel/side_panel_api.cc59
-rw-r--r--chromium/chrome/browser/extensions/api/side_panel/side_panel_api.h53
-rw-r--r--chromium/chrome/browser/extensions/api/side_panel/side_panel_apitest.cc41
-rw-r--r--chromium/chrome/browser/extensions/api/side_panel/side_panel_service.cc112
-rw-r--r--chromium/chrome/browser/extensions/api/side_panel/side_panel_service.h63
-rw-r--r--chromium/chrome/browser/extensions/api/storage/policy_value_store.cc15
-rw-r--r--chromium/chrome/browser/extensions/api/storage/policy_value_store.h2
-rw-r--r--chromium/chrome/browser/extensions/api/storage/policy_value_store_unittest.cc15
-rw-r--r--chromium/chrome/browser/extensions/api/storage/settings_apitest.cc6
-rw-r--r--chromium/chrome/browser/extensions/api/storage/settings_sync_unittest.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/storage/sync_storage_backend.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.cc18
-rw-r--r--chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.h6
-rw-r--r--chromium/chrome/browser/extensions/api/streams_private/streams_private_api.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/system_display/system_display_extension_apitest.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/system_private/system_private_api.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/system_private/system_private_apitest.cc15
-rw-r--r--chromium/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.h2
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/execute_script_apitest.cc11
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_api.cc19
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_api.h2
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc10
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_apitest.cc22
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_event_router.cc85
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_event_router.h5
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc14
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/tabs_test.cc151
-rw-r--r--chromium/chrome/browser/extensions/api/tabs/windows_event_router.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/DIR_METADATA4
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/crostini_startup_status.cc189
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/crostini_startup_status.h62
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/crostini_startup_status_unittest.cc111
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/startup_status.cc148
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/startup_status.h83
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/startup_status_unittest.cc105
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/terminal_private_api.cc193
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/terminal_private_api.h37
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/terminal_private_apitest.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/terminal/terminal_private_browsertest.cc13
-rw-r--r--chromium/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc43
-rw-r--r--chromium/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h10
-rw-r--r--chromium/chrome/browser/extensions/api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.cc230
-rw-r--r--chromium/chrome/browser/extensions/api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.h76
-rw-r--r--chromium/chrome/browser/extensions/api/virtual_keyboard_private/virtual_keyboard_private_apitest.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc20
-rw-r--r--chromium/chrome/browser/extensions/api/web_accessible_resources_apitest.cc355
-rw-r--r--chromium/chrome/browser/extensions/api/web_authentication_proxy/value_conversions.cc182
-rw-r--r--chromium/chrome/browser/extensions/api/web_authentication_proxy/web_authentication_proxy_service.cc12
-rw-r--r--chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc26
-rw-r--r--chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc30
-rw-r--r--chromium/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc57
-rw-r--r--chromium/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc7
-rw-r--r--chromium/chrome/browser/extensions/api/web_request/web_request_apitest.cc1628
-rw-r--r--chromium/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc52
-rw-r--r--chromium/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc32
-rw-r--r--chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_api.cc2
-rw-r--r--chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc20
-rw-r--r--chromium/chrome/browser/extensions/api/webrtc_desktop_capture_private/webrtc_desktop_capture_private_api.cc5
-rw-r--r--chromium/chrome/browser/extensions/api/webstore_private/extension_install_status.cc4
-rw-r--r--chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc47
-rw-r--r--chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.h18
-rw-r--r--chromium/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc8
-rw-r--r--chromium/chrome/browser/extensions/api/webstore_private/webstore_private_unittest.cc126
280 files changed, 12320 insertions, 5999 deletions
diff --git a/chromium/chrome/browser/extensions/BUILD.gn b/chromium/chrome/browser/extensions/BUILD.gn
index 98a0ac50412..400d719eb17 100644
--- a/chromium/chrome/browser/extensions/BUILD.gn
+++ b/chromium/chrome/browser/extensions/BUILD.gn
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/chromebox_for_meetings/buildflags.gni")
import("//build/config/chromeos/ui_mode.gni")
import("//build/config/features.gni")
import("//build/config/ozone.gni")
@@ -141,6 +142,8 @@ static_library("extensions") {
"api/downloads_internal/downloads_internal_api.h",
"api/enterprise_hardware_platform/enterprise_hardware_platform_api.cc",
"api/enterprise_hardware_platform/enterprise_hardware_platform_api.h",
+ "api/enterprise_reporting_private/conversion_utils.cc",
+ "api/enterprise_reporting_private/conversion_utils.h",
"api/enterprise_reporting_private/enterprise_reporting_private_api.cc",
"api/enterprise_reporting_private/enterprise_reporting_private_api.h",
"api/extension_action/extension_action_api.cc",
@@ -336,6 +339,10 @@ static_library("extensions") {
"api/settings_private/settings_private_event_router.h",
"api/settings_private/settings_private_event_router_factory.cc",
"api/settings_private/settings_private_event_router_factory.h",
+ "api/side_panel/side_panel_api.cc",
+ "api/side_panel/side_panel_api.h",
+ "api/side_panel/side_panel_service.cc",
+ "api/side_panel/side_panel_service.h",
"api/storage/managed_value_store_cache.cc",
"api/storage/managed_value_store_cache.h",
"api/storage/policy_value_store.cc",
@@ -760,6 +767,7 @@ static_library("extensions") {
"//base",
"//build:branding_buildflags",
"//build:chromeos_buildflags",
+ "//build/config/chromebox_for_meetings:buildflags",
"//chrome:extra_resources",
"//chrome:resources",
"//chrome:strings",
@@ -773,6 +781,7 @@ static_library("extensions") {
"//chrome/browser:theme_properties",
"//chrome/browser/browsing_data:constants",
"//chrome/browser/devtools",
+ "//chrome/browser/favicon",
"//chrome/browser/first_party_sets",
"//chrome/browser/image_decoder",
"//chrome/browser/media/router",
@@ -784,8 +793,10 @@ static_library("extensions") {
"//chrome/browser/resource_coordinator:mojo_bindings",
"//chrome/browser/safe_browsing",
"//chrome/browser/safe_browsing:metrics_collector",
+ "//chrome/browser/ui/tabs:tab_enums",
"//chrome/browser/web_applications",
"//components/cbor:cbor",
+ "//components/device_reauth",
"//components/safe_browsing/content/browser",
"//components/safe_browsing/core/browser:safe_browsing_metrics_collector",
"//components/security_interstitials/content:security_interstitial_page",
@@ -809,6 +820,8 @@ static_library("extensions") {
"//components/content_settings/core/browser",
"//components/cookie_config:cookie_config",
"//components/crx_file",
+ "//components/device_signals/core/browser",
+ "//components/device_signals/core/common",
"//components/dom_distiller/core",
"//components/download/content/public",
"//components/download/public/common:public",
@@ -838,6 +851,7 @@ static_library("extensions") {
"//components/password_manager/content/browser",
"//components/password_manager/core/browser",
"//components/password_manager/core/browser:affiliation",
+ "//components/password_manager/core/browser:import_results",
"//components/password_manager/core/browser/leak_detection",
"//components/payments/core",
"//components/performance_manager",
@@ -855,7 +869,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/mojom",
+ "//components/services/app_service/public/cpp:app_types",
"//components/services/patch/content",
"//components/services/unzip/content",
"//components/services/unzip/public/cpp",
@@ -951,6 +965,8 @@ static_library("extensions") {
"api/system_indicator/system_indicator_manager_factory.cc",
"api/system_indicator/system_indicator_manager_factory.h",
]
+
+ deps += [ "//components/device_signals/core/common:features" ]
}
if (is_chromeos) {
@@ -969,6 +985,10 @@ static_library("extensions") {
"api/file_manager/file_selector.h",
"api/file_manager/file_selector_impl.cc",
"api/file_manager/file_selector_impl.h",
+ "api/file_system/consent_provider.cc",
+ "api/file_system/consent_provider.h",
+ "api/file_system/request_file_system_notification.cc",
+ "api/file_system/request_file_system_notification.h",
"api/messaging/native_message_built_in_host.cc",
"api/messaging/native_message_built_in_host.h",
"api/messaging/native_message_echo_host.cc",
@@ -982,8 +1002,18 @@ static_library("extensions") {
"api/printing/print_job_controller.cc",
"api/printing/print_job_controller.h",
"api/shared_storage/shared_storage_private_api.h",
+
+ # TODO(crbug.com/1340540): Find an appropriate spot for this.
+ "chromeos_browser_context_keyed_service_factories.cc",
+ "chromeos_browser_context_keyed_service_factories.h",
"clipboard_extension_helper_chromeos.cc",
"clipboard_extension_helper_chromeos.h",
+ "extension_keeplist_chromeos.cc",
+ "extension_keeplist_chromeos.h",
+ "system_display/display_info_provider_chromeos.cc",
+ "system_display/display_info_provider_chromeos.h",
+ "system_display/display_info_provider_utils.cc",
+ "system_display/display_info_provider_utils.h",
"system_display/system_display_serialization.cc",
"system_display/system_display_serialization.h",
]
@@ -1000,13 +1030,16 @@ static_library("extensions") {
]
deps += [
+ # TODO(crbug.com/1340540): Find an appropriate spot for printing_metrics.
+ "//chrome/browser/chromeos/extensions/printing_metrics",
"//chromeos/printing",
"//printing/backend",
]
}
deps += [
"//chrome/browser/chromeos/extensions:constants",
- "//chrome/browser/chromeos/extensions/login_screen",
+
+ # TODO(crbug.com/1340540): Find an appropriate spot for vpn_provider.
"//chrome/browser/chromeos/extensions/vpn_provider",
"//chromeos/components/disks:prefs",
"//chromeos/components/quick_answers/public/cpp:prefs",
@@ -1015,6 +1048,7 @@ static_library("extensions") {
"//chromeos/crosapi/cpp",
"//chromeos/crosapi/mojom",
"//chromeos/dbus/missive:missive",
+ "//chromeos/dbus/power",
"//remoting/host/it2me:chrome_os_host",
]
} else {
@@ -1057,10 +1091,8 @@ static_library("extensions") {
"api/file_handlers/non_native_file_system_delegate_chromeos.h",
"api/file_manager/file_browser_handler_api_ash.cc",
"api/file_manager/file_browser_handler_api_ash.h",
- "api/file_system/consent_provider.cc",
- "api/file_system/consent_provider.h",
- "api/file_system/request_file_system_notification.cc",
- "api/file_system/request_file_system_notification.h",
+ "api/file_system/chrome_file_system_delegate_ash.cc",
+ "api/file_system/chrome_file_system_delegate_ash.h",
"api/image_writer_private/operation_chromeos.cc",
"api/image_writer_private/removable_storage_provider_chromeos.cc",
"api/input_ime/input_ime_api.cc",
@@ -1083,8 +1115,8 @@ static_library("extensions") {
"api/settings_private/generated_time_zone_pref_base.cc",
"api/settings_private/generated_time_zone_pref_base.h",
"api/shared_storage/shared_storage_private_api_ash.cc",
- "api/terminal/crostini_startup_status.cc",
- "api/terminal/crostini_startup_status.h",
+ "api/terminal/startup_status.cc",
+ "api/terminal/startup_status.h",
"api/terminal/terminal_private_api.cc",
"api/terminal/terminal_private_api.h",
"api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc",
@@ -1096,10 +1128,6 @@ static_library("extensions") {
"extension_assets_manager_chromeos.h",
"extension_garbage_collector_chromeos.cc",
"extension_garbage_collector_chromeos.h",
- "extension_keeplist_ash.cc",
- "extension_keeplist_ash.h",
- "system_display/display_info_provider_chromeos.cc",
- "system_display/display_info_provider_chromeos.h",
"updater/chromeos_extension_cache_delegate.cc",
"updater/chromeos_extension_cache_delegate.h",
"updater/extension_cache_impl.cc",
@@ -1114,8 +1142,6 @@ static_library("extensions") {
deps += [
"//ash",
"//ash/components/arc",
- "//ash/components/attestation",
- "//ash/components/cryptohome",
"//ash/components/disks",
"//ash/components/enhanced_network_tts/mojom",
"//ash/components/login/auth",
@@ -1137,26 +1163,29 @@ static_library("extensions") {
"//chrome/browser/devtools",
"//chrome/browser/nearby_sharing/common",
"//chrome/browser/ui/webui/settings/chromeos/constants:mojom",
- "//chromeos/components/chromebox_for_meetings/buildflags",
+ "//chromeos/ash/components/attestation",
+ "//chromeos/ash/components/cryptohome",
+ "//chromeos/ash/components/dbus",
+ "//chromeos/ash/components/dbus/cicerone:cicerone",
+ "//chromeos/ash/components/dbus/cicerone:cicerone_proto",
+ "//chromeos/ash/components/dbus/cros_disks",
+ "//chromeos/ash/components/dbus/cryptohome",
+ "//chromeos/ash/components/dbus/image_burner",
+ "//chromeos/ash/components/dbus/update_engine",
+ "//chromeos/ash/components/network",
+ "//chromeos/ash/services/assistant/public/cpp",
"//chromeos/components/remote_apps/mojom",
- "//chromeos/dbus",
- "//chromeos/dbus/cryptohome",
- "//chromeos/dbus/image_burner",
- "//chromeos/dbus/power",
- "//chromeos/dbus/update_engine",
- "//chromeos/dbus/util",
"//chromeos/language/language_packs",
"//chromeos/language/public/mojom",
"//chromeos/login/login_state",
- "//chromeos/network",
"//chromeos/process_proxy",
- "//chromeos/services/assistant/public/cpp",
"//chromeos/services/machine_learning/public/cpp",
"//chromeos/services/machine_learning/public/mojom",
"//chromeos/services/media_perception/public/mojom",
"//chromeos/services/tts/public/mojom",
"//chromeos/system",
"//chromeos/ui/base",
+ "//chromeos/version",
"//components/constrained_window",
"//components/crash/content/browser/error_reporting",
"//components/drive",
@@ -1176,6 +1205,10 @@ static_library("extensions") {
"//ui/views",
]
allow_circular_includes_from += [ "//chrome/browser/ash/crosapi" ]
+
+ if (is_cfm) {
+ deps += [ "//chromeos/ash/components/chromebox_for_meetings" ]
+ }
}
if (is_chromeos_lacros) {
@@ -1188,6 +1221,10 @@ static_library("extensions") {
"api/file_browser_handler/file_browser_handler_flow_lacros.h",
"api/file_manager/file_browser_handler_api_lacros.cc",
"api/file_manager/file_browser_handler_api_lacros.h",
+ "api/file_system/chrome_file_system_delegate_lacros.cc",
+ "api/file_system/chrome_file_system_delegate_lacros.h",
+ "api/file_system/volume_list_provider_lacros.cc",
+ "api/file_system/volume_list_provider_lacros.h",
"api/image_writer_private/image_writer_controller_lacros.cc",
"api/image_writer_private/image_writer_controller_lacros.h",
"api/image_writer_private/operation_nonchromeos.cc",
@@ -1196,11 +1233,11 @@ static_library("extensions") {
"api/quick_unlock_private/quick_unlock_private_api_lacros.cc",
"api/quick_unlock_private/quick_unlock_private_api_lacros.h",
"api/shared_storage/shared_storage_private_api_lacros.cc",
+ "api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.cc",
+ "api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.h",
"chrome_kiosk_delegate.cc",
"preinstalled_apps.cc",
"preinstalled_apps.h",
- "system_display/display_info_provider_lacros.cc",
- "system_display/display_info_provider_lacros.h",
]
deps += [
"//chromeos/lacros",
@@ -1210,8 +1247,6 @@ static_library("extensions") {
"//components/enterprise/common/proto:connectors_proto",
"//components/keep_alive_registry",
]
- allow_circular_includes_from +=
- [ "//chrome/browser/chromeos/extensions/login_screen" ]
}
if (use_ozone) {
@@ -1262,6 +1297,7 @@ static_library("extensions") {
"system_display/display_info_provider_win.h",
]
deps += [
+ "//components/device_signals/core/common/win",
"//third_party/iaccessible2",
"//third_party/isimpledom",
]
diff --git a/chromium/chrome/browser/extensions/api/DEPS b/chromium/chrome/browser/extensions/api/DEPS
index c2f7fbe1a7b..aa705a34f93 100644
--- a/chromium/chrome/browser/extensions/api/DEPS
+++ b/chromium/chrome/browser/extensions/api/DEPS
@@ -2,7 +2,7 @@ include_rules = [
"+apps",
"+components/live_caption",
"+services/device/public",
-
+ "+components/device_reauth",
# Enable remote assistance on Chrome OS
"+remoting/host",
]
diff --git a/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc b/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc
index 1815aa6b3ad..57db92301eb 100644
--- a/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_api.cc
@@ -93,8 +93,8 @@ void ActivityLogAPI::OnExtensionActivity(scoped_refptr<Action> activity) {
value.Append(base::Value::FromUniquePtrValue(activity_arg.ToValue()));
auto event = std::make_unique<Event>(
events::ACTIVITY_LOG_PRIVATE_ON_EXTENSION_ACTIVITY,
- activity_log_private::OnExtensionActivity::kEventName,
- base::Value(std::move(value)).TakeListDeprecated(), browser_context_);
+ activity_log_private::OnExtensionActivity::kEventName, std::move(value),
+ browser_context_);
EventRouter::Get(browser_context_)->BroadcastEvent(std::move(event));
}
diff --git a/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc b/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc
index 107237f2721..db0ac5335c6 100644
--- a/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc
@@ -28,9 +28,9 @@ using api::activity_log_private::ExtensionActivity;
typedef testing::Test ActivityLogApiUnitTest;
TEST_F(ActivityLogApiUnitTest, ConvertChromeApiAction) {
- std::unique_ptr<base::ListValue> args(new base::ListValue());
- args->Append("hello");
- args->Append("world");
+ base::Value::List args;
+ args.Append("hello");
+ args.Append("world");
scoped_refptr<Action> action(new Action(kExtensionId,
base::Time::Now(),
Action::ACTION_API_CALL,
@@ -46,9 +46,9 @@ TEST_F(ActivityLogApiUnitTest, ConvertChromeApiAction) {
}
TEST_F(ActivityLogApiUnitTest, ConvertDomAction) {
- std::unique_ptr<base::ListValue> args(new base::ListValue());
- args->Append("hello");
- args->Append("world");
+ base::Value::List args;
+ args.Append("hello");
+ args.Append("world");
scoped_refptr<Action> action(new Action(kExtensionId,
base::Time::Now(),
Action::ACTION_DOM_ACCESS,
@@ -57,10 +57,9 @@ TEST_F(ActivityLogApiUnitTest, ConvertDomAction) {
action->set_args(std::move(args));
action->set_page_url(GURL("http://www.google.com"));
action->set_page_title("Title");
- action->mutable_other()->SetIntKey(activity_log_constants::kActionDomVerb,
- DomActionType::INSERTED);
- action->mutable_other()->SetBoolKey(activity_log_constants::kActionPrerender,
- false);
+ action->mutable_other().Set(activity_log_constants::kActionDomVerb,
+ DomActionType::INSERTED);
+ action->mutable_other().Set(activity_log_constants::kActionPrerender, false);
ExtensionActivity result = action->ConvertToExtensionActivity();
ASSERT_EQ(kExtensionId, *(result.extension_id.get()));
ASSERT_EQ("http://www.google.com/", *(result.page_url.get()));
diff --git a/chromium/chrome/browser/extensions/api/alarms/alarms_apitest.cc b/chromium/chrome/browser/extensions/api/alarms/alarms_apitest.cc
index fd888e4560c..01f3e0dd0ca 100644
--- a/chromium/chrome/browser/extensions/api/alarms/alarms_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/alarms/alarms_apitest.cc
@@ -31,7 +31,7 @@ class AlarmsApiTest : public ExtensionApiTest,
ASSERT_TRUE(StartEmbeddedTestServer());
}
- static std::vector<base::Value> BuildEventArguments(const bool last_message) {
+ static base::Value::List BuildEventArguments(const bool last_message) {
api::test::OnMessage::Info info;
info.data = "";
info.last_message = last_message;
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 a932bc2648c..c41b33c2595 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
@@ -8,7 +8,6 @@
#include <memory>
#include <utility>
-#include "base/containers/flat_map.h"
#include "base/guid.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/utf_string_conversions.h"
@@ -98,15 +97,15 @@ const char* GetStringFromAddressField(i18n::addressinput::AddressField type) {
}
// Serializes the AddressUiComponent a map from string to base::Value().
-base::flat_map<std::string, base::Value> AddressUiComponentAsValueMap(
+base::Value::Dict AddressUiComponentAsValueMap(
const i18n::addressinput::AddressUiComponent& address_ui_component) {
- base::flat_map<std::string, base::Value> info;
- info.emplace(kFieldNameKey, address_ui_component.name);
- info.emplace(kFieldTypeKey,
- GetStringFromAddressField(address_ui_component.field));
- info.emplace(kFieldLengthKey,
- address_ui_component.length_hint ==
- i18n::addressinput::AddressUiComponent::HINT_LONG);
+ base::Value::Dict info;
+ info.Set(kFieldNameKey, address_ui_component.name);
+ info.Set(kFieldTypeKey,
+ GetStringFromAddressField(address_ui_component.field));
+ info.Set(kFieldLengthKey,
+ address_ui_component.length_hint ==
+ i18n::addressinput::AddressUiComponent::HINT_LONG);
return info;
}
@@ -116,9 +115,7 @@ base::flat_map<std::string, base::Value> AddressUiComponentAsValueMap(
// number values.
void RemoveDuplicatePhoneNumberAtIndex(size_t index,
const std::string& country_code,
- base::Value* list_value) {
- DCHECK(list_value->is_list());
- base::Value::ListView list = list_value->GetListDeprecated();
+ base::Value::List& list) {
if (list.size() <= index) {
NOTREACHED() << "List should have a value at index " << index;
return;
@@ -138,7 +135,7 @@ void RemoveDuplicatePhoneNumberAtIndex(size_t index,
}
if (is_duplicate)
- list_value->EraseListIter(list.begin() + index);
+ list.erase(list.begin() + index);
}
autofill::AutofillManager* GetAutofillManager(
@@ -281,7 +278,7 @@ ExtensionFunction::ResponseAction AutofillPrivateSaveAddressFunction::Run() {
personal_data->AddProfile(profile);
}
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
////////////////////////////////////////////////////////////////////////////////
@@ -324,23 +321,23 @@ AutofillPrivateGetAddressComponentsFunction::Run() {
/*include_literals=*/false, &lines, &language_code);
// Convert std::vector<std::vector<::i18n::addressinput::AddressUiComponent>>
// to AddressComponents
- base::Value address_components(base::Value::Type::DICTIONARY);
- base::Value rows(base::Value::Type::LIST);
+ base::Value::Dict address_components;
+ base::Value::List rows;
for (auto& line : lines) {
- std::vector<base::Value> row_values;
+ base::Value::List row_values;
for (const ::i18n::addressinput::AddressUiComponent& component : line) {
- row_values.emplace_back(AddressUiComponentAsValueMap(component));
+ row_values.Append(AddressUiComponentAsValueMap(component));
}
- base::Value row(base::Value::Type::DICTIONARY);
- row.SetKey("row", base::Value(std::move(row_values)));
+ base::Value::Dict row;
+ row.Set("row", std::move(row_values));
rows.Append(std::move(row));
}
- address_components.SetKey("components", std::move(rows));
- address_components.SetKey("languageCode", base::Value(language_code));
+ address_components.Set("components", std::move(rows));
+ address_components.Set("languageCode", language_code);
- return RespondNow(OneArgument(std::move(address_components)));
+ return RespondNow(WithArguments(std::move(address_components)));
}
////////////////////////////////////////////////////////////////////////////////
@@ -417,7 +414,7 @@ ExtensionFunction::ResponseAction AutofillPrivateSaveCreditCardFunction::Run() {
if (use_existing_card) {
// Only updates when the card info changes.
if (existing_card && existing_card->Compare(credit_card) == 0)
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
// Record when nickname is updated.
if (credit_card.HasNonEmptyValidNickname() &&
@@ -437,7 +434,7 @@ ExtensionFunction::ResponseAction AutofillPrivateSaveCreditCardFunction::Run() {
}
}
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
////////////////////////////////////////////////////////////////////////////////
@@ -456,7 +453,7 @@ ExtensionFunction::ResponseAction AutofillPrivateRemoveEntryFunction::Run() {
personal_data->RemoveByGUID(parameters->guid);
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
////////////////////////////////////////////////////////////////////////////////
@@ -472,15 +469,15 @@ AutofillPrivateValidatePhoneNumbersFunction::Run() {
api::autofill_private::ValidatePhoneParams* params = &parameters->params;
// Extract the phone numbers into a ListValue.
- base::Value phone_numbers(base::Value::Type::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);
+ params->country_code, phone_numbers);
- return RespondNow(OneArgument(std::move(phone_numbers)));
+ return RespondNow(WithArguments(std::move(phone_numbers)));
}
////////////////////////////////////////////////////////////////////////////////
@@ -499,7 +496,7 @@ ExtensionFunction::ResponseAction AutofillPrivateMaskCreditCardFunction::Run() {
personal_data->ResetFullServerCard(parameters->guid);
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
////////////////////////////////////////////////////////////////////////////////
@@ -557,7 +554,7 @@ AutofillPrivateMigrateCreditCardsFunction::Run() {
local_card_migration_manager->GetMigratableCreditCards();
local_card_migration_manager->AttemptToOfferLocalCardMigration(
/*is_from_settings_page=*/true);
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
////////////////////////////////////////////////////////////////////////////////
@@ -573,7 +570,7 @@ AutofillPrivateLogServerCardLinkClickedFunction::Run() {
return RespondNow(Error(kErrorDataUnavailable));
personal_data->LogServerCardLinkClicked();
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
////////////////////////////////////////////////////////////////////////////////
@@ -599,7 +596,7 @@ AutofillPrivateSetCreditCardFIDOAuthEnabledStateFunction::Run() {
credit_card_access_manager->OnSettingsPageFIDOAuthToggled(
parameters->enabled);
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
////////////////////////////////////////////////////////////////////////////////
@@ -653,7 +650,7 @@ ExtensionFunction::ResponseAction AutofillPrivateAddVirtualCardFunction::Run() {
virtual_card_enrollment_manager->InitVirtualCardEnroll(
*card, autofill::VirtualCardEnrollmentSource::kSettingsPage);
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
////////////////////////////////////////////////////////////////////////////////
@@ -692,8 +689,10 @@ AutofillPrivateRemoveVirtualCardFunction::Run() {
->GetFormDataImporter()
->GetVirtualCardEnrollmentManager();
- virtual_card_enrollment_manager->Unenroll(card->instrument_id());
- return RespondNow(NoArguments());
+ virtual_card_enrollment_manager->Unenroll(
+ card->instrument_id(),
+ /*virtual_card_enrollment_update_response_callback=*/absl::nullopt);
+ return RespondNow(WithArguments());
}
} // namespace extensions
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 88ea1f7f579..03695611ef1 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
@@ -5,7 +5,6 @@
#include "chrome/browser/extensions/api/autofill_private/autofill_private_event_router_factory.h"
#include "chrome/browser/extensions/api/autofill_private/autofill_private_event_router.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/extension_system_provider.h"
#include "extensions/browser/extensions_browser_client.h"
@@ -27,9 +26,9 @@ AutofillPrivateEventRouterFactory::GetInstance() {
}
AutofillPrivateEventRouterFactory::AutofillPrivateEventRouterFactory()
- : BrowserContextKeyedServiceFactory(
+ : ProfileKeyedServiceFactory(
"AutofillPrivateEventRouter",
- BrowserContextDependencyManager::GetInstance()) {
+ ProfileSelections::BuildRedirectedInIncognito()) {
DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
}
@@ -38,12 +37,6 @@ KeyedService* AutofillPrivateEventRouterFactory::BuildServiceInstanceFor(
return AutofillPrivateEventRouter::Create(context);
}
-content::BrowserContext*
-AutofillPrivateEventRouterFactory::GetBrowserContextToUse(
- content::BrowserContext* context) const {
- return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
-}
-
bool AutofillPrivateEventRouterFactory::
ServiceIsCreatedWithBrowserContext() const {
return true;
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 e5d38f0970f..44f24f3019d 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
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_EVENT_ROUTER_FACTORY_H_
#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
namespace extensions {
@@ -15,8 +15,7 @@ class AutofillPrivateEventRouter;
// This is a factory class used by the BrowserContextDependencyManager
// to instantiate the autofillPrivate event router per profile (since the
// extension event router is per profile).
-class AutofillPrivateEventRouterFactory
- : public BrowserContextKeyedServiceFactory {
+class AutofillPrivateEventRouterFactory : public ProfileKeyedServiceFactory {
public:
// Returns the AutofillPrivateEventRouter for |profile|, creating it if
// it is not yet created.
@@ -33,8 +32,6 @@ class AutofillPrivateEventRouterFactory
protected:
// BrowserContextKeyedServiceFactory overrides:
- content::BrowserContext* GetBrowserContextToUse(
- content::BrowserContext* context) const override;
bool ServiceIsCreatedWithBrowserContext() const override;
private:
diff --git a/chromium/chrome/browser/extensions/api/automation/automation_apitest.cc b/chromium/chrome/browser/extensions/api/automation/automation_apitest.cc
index 316a9766461..bdbdc398cb8 100644
--- a/chromium/chrome/browser/extensions/api/automation/automation_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -26,6 +26,7 @@
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/tracing_controller.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/api/automation_internal/automation_event_router.h"
#include "extensions/common/api/automation_internal.h"
@@ -33,6 +34,7 @@
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
#include "ui/accessibility/accessibility_switches.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_serializable_tree.h"
@@ -209,7 +211,13 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, LineStartOffsets) {
<< message_;
}
-IN_PROC_BROWSER_TEST_F(AutomationApiCanvasTest, ImageData) {
+// Flaky on Mac: crbug.com/1338036
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
+#define MAYBE_ImageData DISABLED_ImageData
+#else
+#define MAYBE_ImageData ImageData
+#endif
+IN_PROC_BROWSER_TEST_F(AutomationApiCanvasTest, MAYBE_ImageData) {
StartEmbeddedTestServer();
ASSERT_TRUE(RunExtensionTest("automation/tests/tabs",
{.page_url = "image_data.html"}))
@@ -412,6 +420,38 @@ IN_PROC_BROWSER_TEST_F(AutomationApiTest, DesktopNotSupported) {
#endif // !defined(USE_AURA)
#if BUILDFLAG(IS_CHROMEOS_ASH)
+class AutomationApiFencedFrameTest
+ : public AutomationApiTest,
+ public testing::WithParamInterface<bool /* shadow_dom_fenced_frame */> {
+ protected:
+ AutomationApiFencedFrameTest() {
+ feature_list_.InitWithFeaturesAndParameters(
+ /*enabled_features=*/{{blink::features::kFencedFrames,
+ {{"implementation_type",
+ GetParam() ? "shadow_dom" : "mparch"}}},
+ {features::kPrivacySandboxAdsAPIsOverride, {}}},
+ /*disabled_features=*/{features::kSpareRendererForSitePerProcess});
+ }
+
+ ~AutomationApiFencedFrameTest() override = default;
+
+ public:
+ void SetUpOnMainThread() override { AutomationApiTest::SetUpOnMainThread(); }
+
+ base::test::ScopedFeatureList feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(AutomationApiFencedFrameTest,
+ AutomationApiFencedFrameTest,
+ testing::Bool());
+
+IN_PROC_BROWSER_TEST_P(AutomationApiFencedFrameTest, DesktopFindInFencedframe) {
+ StartEmbeddedTestServer();
+ ASSERT_TRUE(RunExtensionTest("automation/tests/desktop/fencedframe",
+ {.page_url = "focus_fencedframe.html"}))
+ << message_;
+}
+
IN_PROC_BROWSER_TEST_F(AutomationApiTest, Desktop) {
ASSERT_TRUE(RunExtensionTest("automation/tests/desktop",
{.page_url = "desktop.html"}))
diff --git a/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
index d4c0c5462a0..8e3b36929dd 100644
--- a/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc
@@ -16,6 +16,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/bookmarks/url_and_id.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h"
#include "chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.h"
@@ -24,6 +25,7 @@
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
#include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
@@ -42,6 +44,7 @@
#include "components/strings/grit/components_strings.h"
#include "components/undo/bookmark_undo_service.h"
#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
@@ -197,7 +200,7 @@ BookmarkManagerPrivateEventRouter::~BookmarkManagerPrivateEventRouter() {
void BookmarkManagerPrivateEventRouter::DispatchEvent(
events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> event_args) {
+ base::Value::List event_args) {
EventRouter::Get(browser_context_)
->BroadcastEvent(std::make_unique<Event>(histogram_value, event_name,
std::move(event_args)));
@@ -260,7 +263,7 @@ BookmarkManagerPrivateDragEventRouter::
void BookmarkManagerPrivateDragEventRouter::DispatchEvent(
events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> args) {
+ base::Value::List args) {
EventRouter* event_router = EventRouter::Get(profile_);
if (!event_router)
return;
@@ -337,7 +340,7 @@ ExtensionFunction::ResponseValue ClipboardBookmarkManagerFunction::CopyOrCut(
if (cut && HasPermanentNodes(nodes))
return Error(bookmark_keys::kModifySpecialError);
bookmarks::CopyToClipboard(model, nodes, cut);
- return NoArguments();
+ return WithArguments();
}
ExtensionFunction::ResponseValue
@@ -382,19 +385,17 @@ BookmarkManagerPrivatePasteFunction::RunOnReady() {
// No need to test return value, if we got an empty list, we insert at end.
if (params->selected_id_list)
GetNodesFromVector(model, *params->selected_id_list, &nodes);
- int highest_index = -1;
- for (size_t i = 0; i < nodes.size(); ++i) {
+ size_t highest_index = 0;
+ for (const BookmarkNode* node : nodes) {
// + 1 so that we insert after the selection.
- int index = parent_node->GetIndexOf(nodes[i]) + 1;
- if (index > highest_index)
- highest_index = index;
+ highest_index =
+ std::max(highest_index, parent_node->GetIndexOf(node).value() + 1);
}
- size_t insertion_index = (highest_index == -1)
- ? parent_node->children().size()
- : static_cast<size_t>(highest_index);
+ if (!highest_index)
+ highest_index = parent_node->children().size();
- bookmarks::PasteFromClipboard(model, parent_node, insertion_index);
- return NoArguments();
+ bookmarks::PasteFromClipboard(model, parent_node, highest_index);
+ return WithArguments();
}
ExtensionFunction::ResponseValue
@@ -405,7 +406,7 @@ BookmarkManagerPrivateCanPasteFunction::RunOnReady() {
PrefService* prefs = user_prefs::UserPrefs::Get(GetProfile());
if (!prefs->GetBoolean(bookmarks::prefs::kEditBookmarksEnabled))
- return OneArgument(base::Value(false));
+ return WithArguments(false);
BookmarkModel* model =
BookmarkModelFactory::GetForBrowserContext(GetProfile());
@@ -413,7 +414,7 @@ BookmarkManagerPrivateCanPasteFunction::RunOnReady() {
if (!parent_node)
return Error(bookmark_keys::kNoParentError);
bool can_paste = bookmarks::CanPasteFromClipboard(model, parent_node);
- return OneArgument(base::Value(can_paste));
+ return WithArguments(can_paste);
}
ExtensionFunction::ResponseValue
@@ -433,7 +434,7 @@ BookmarkManagerPrivateSortChildrenFunction::RunOnReady() {
if (!CanBeModified(parent_node, &error))
return Error(error);
model->SortChildren(parent_node);
- return NoArguments();
+ return WithArguments();
}
ExtensionFunction::ResponseValue
@@ -462,7 +463,7 @@ BookmarkManagerPrivateStartDragFunction::RunOnReady() {
GetProfile(), {std::move(nodes), params->drag_node_index, web_contents,
source, gfx::Point(params->x, params->y)});
- return NoArguments();
+ return WithArguments();
}
ExtensionFunction::ResponseValue
@@ -501,7 +502,7 @@ BookmarkManagerPrivateDropFunction::RunOnReady() {
GetProfile(), *drag_data, drop_parent, drop_index, copy);
router->ClearBookmarkNodeData();
- return NoArguments();
+ return WithArguments();
}
ExtensionFunction::ResponseValue
@@ -555,7 +556,7 @@ BookmarkManagerPrivateRemoveTreesFunction::RunOnReady() {
return Error(error);
}
- return NoArguments();
+ return WithArguments();
}
ExtensionFunction::ResponseValue
@@ -565,7 +566,7 @@ BookmarkManagerPrivateUndoFunction::RunOnReady() {
BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
Undo();
- return NoArguments();
+ return WithArguments();
}
ExtensionFunction::ResponseValue
@@ -575,7 +576,7 @@ BookmarkManagerPrivateRedoFunction::RunOnReady() {
BookmarkUndoServiceFactory::GetForProfile(GetProfile())->undo_manager()->
Redo();
- return NoArguments();
+ return WithArguments();
}
ExtensionFunction::ResponseValue
@@ -595,6 +596,7 @@ BookmarkManagerPrivateOpenInNewTabFunction::RunOnReady() {
ExtensionTabUtil::OpenTabParams options;
options.url = std::make_unique<std::string>(node->url().spec());
options.active = std::make_unique<bool>(params->active);
+ options.bookmark_id = std::make_unique<int>(node->id());
std::unique_ptr<base::DictionaryValue> result(
extensions::ExtensionTabUtil::OpenTab(this, options, user_gesture(),
@@ -602,7 +604,7 @@ BookmarkManagerPrivateOpenInNewTabFunction::RunOnReady() {
if (!result)
return Error(error);
- return NoArguments();
+ return WithArguments();
}
ExtensionFunction::ResponseValue
@@ -637,6 +639,18 @@ BookmarkManagerPrivateOpenInNewWindowFunction::RunOnReady() {
if (incognito_result == windows_util::IncognitoResult::kError)
return Error(std::move(error));
+ std::vector<UrlAndId> url_and_ids;
+ urls.reserve(nodes.size());
+ for (const auto* node : nodes) {
+ if (!base::Contains(urls, node->url()))
+ continue; // The URL was filtered out; ignore this node.
+ UrlAndId url_and_id;
+ url_and_id.url = node->url();
+ url_and_id.id = node->id();
+ url_and_ids.push_back(url_and_id);
+ }
+ DCHECK_EQ(urls.size(), url_and_ids.size());
+
DCHECK(!calling_profile->IsOffTheRecord());
Profile* window_profile =
incognito_result == windows_util::IncognitoResult::kIncognito
@@ -644,8 +658,8 @@ BookmarkManagerPrivateOpenInNewWindowFunction::RunOnReady() {
: calling_profile;
bool first_tab = true;
- for (auto& url : urls) {
- NavigateParams navigate_params(window_profile, url,
+ for (auto& url_and_id : url_and_ids) {
+ NavigateParams navigate_params(window_profile, url_and_id.url,
ui::PAGE_TRANSITION_LINK);
navigate_params.window_action = NavigateParams::WindowAction::SHOW_WINDOW;
navigate_params.disposition =
@@ -653,12 +667,18 @@ BookmarkManagerPrivateOpenInNewWindowFunction::RunOnReady() {
: WindowOpenDisposition::NEW_FOREGROUND_TAB;
if (params->incognito)
navigate_params.disposition = WindowOpenDisposition::OFF_THE_RECORD;
- Navigate(&navigate_params);
+ base::WeakPtr<content::NavigationHandle> handle =
+ Navigate(&navigate_params);
+ if (handle) {
+ ChromeNavigationUIData* ui_data =
+ static_cast<ChromeNavigationUIData*>(handle->GetNavigationUIData());
+ ui_data->set_bookmark_id(url_and_id.id);
+ }
first_tab = false;
}
- return NoArguments();
+ return WithArguments();
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(BookmarkManagerPrivateDragEventRouter);
diff --git a/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
index eef06087328..94d4c3211dd 100644
--- a/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
+++ b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h
@@ -50,7 +50,7 @@ class BookmarkManagerPrivateEventRouter
// Helper to actually dispatch an event to extension listeners.
void DispatchEvent(events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> event_args);
+ base::Value::List event_args);
// Remembers the previous meta info of a node before it was changed.
bookmarks::BookmarkNode::MetaInfoMap prev_meta_info_;
@@ -122,7 +122,7 @@ class BookmarkManagerPrivateDragEventRouter
// Helper to actually dispatch an event to extension listeners.
void DispatchEvent(events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> args);
+ base::Value::List args);
raw_ptr<Profile> profile_;
bookmarks::BookmarkNodeData bookmark_drag_data_;
diff --git a/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_browsertest.cc b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_browsertest.cc
new file mode 100644
index 00000000000..05938c1140d
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_browsertest.cc
@@ -0,0 +1,72 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/browser/bookmark_node.h"
+#include "components/bookmarks/test/bookmark_test_helpers.h"
+#include "content/public/test/browser_test.h"
+#include "extensions/browser/api_test_utils.h"
+
+using bookmarks::BookmarkModel;
+using bookmarks::BookmarkNode;
+
+namespace extensions {
+
+class BookmarkManagerPrivateApiBrowsertest : public InProcessBrowserTest {
+ public:
+ void SetUp() override { InProcessBrowserTest::SetUp(); }
+
+ void SetUpOnMainThread() override {
+ InProcessBrowserTest::SetUpOnMainThread();
+ model_ = WaitForBookmarkModel();
+ }
+
+ BookmarkModel* model() { return model_; }
+
+ private:
+ BookmarkModel* WaitForBookmarkModel() {
+ BookmarkModel* model =
+ BookmarkModelFactory::GetForBrowserContext(browser()->profile());
+ bookmarks::test::WaitForBookmarkModelToLoad(model);
+ return model;
+ }
+
+ BookmarkModel* model_;
+};
+
+IN_PROC_BROWSER_TEST_F(BookmarkManagerPrivateApiBrowsertest,
+ OpenURLInNewWindow) {
+ const BookmarkNode* node =
+ model()->AddURL(model()->bookmark_bar_node(), 0, u"Settings",
+ GURL(chrome::kChromeUISettingsURL));
+ std::string node_id = base::NumberToString(node->id());
+
+ auto new_window_function =
+ base::MakeRefCounted<BookmarkManagerPrivateOpenInNewWindowFunction>();
+ std::string args = base::StringPrintf(R"([["%s"], false])", node_id.c_str());
+ ASSERT_TRUE(api_test_utils::RunFunction(new_window_function.get(), args,
+ browser()->profile()));
+}
+
+IN_PROC_BROWSER_TEST_F(BookmarkManagerPrivateApiBrowsertest,
+ OpenURLInNewWindowIncognito) {
+ const BookmarkNode* node =
+ model()->AddURL(model()->bookmark_bar_node(), 0, u"Settings",
+ GURL(chrome::kChromeUIVersionURL));
+ std::string node_id = base::NumberToString(node->id());
+
+ auto new_window_function =
+ base::MakeRefCounted<BookmarkManagerPrivateOpenInNewWindowFunction>();
+ std::string args = base::StringPrintf(R"([["%s"], true])", node_id.c_str());
+ ASSERT_TRUE(api_test_utils::RunFunction(new_window_function.get(), args,
+ browser()->profile()));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc
index 7b2616b3578..5b5bf883213 100644
--- a/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_unittest.cc
@@ -127,13 +127,13 @@ TEST_F(BookmarkManagerPrivateApiUnitTest, RunOpenInNewTabFunctionFolder) {
}
TEST_F(BookmarkManagerPrivateApiUnitTest, RunOpenInNewWindowFunctionFolder) {
- auto new_tab_function =
+ auto new_window_function =
base::MakeRefCounted<BookmarkManagerPrivateOpenInNewWindowFunction>();
std::string node_id =
base::NumberToString(model()->bookmark_bar_node()->id());
std::string args = base::StringPrintf(R"([["%s"], false])", node_id.c_str());
EXPECT_EQ("Cannot open a folder in a new window.",
- api_test_utils::RunFunctionAndReturnError(new_tab_function.get(),
+ api_test_utils::RunFunctionAndReturnError(new_window_function.get(),
args, profile()));
}
@@ -143,11 +143,11 @@ TEST_F(BookmarkManagerPrivateApiUnitTest,
IncognitoModePrefs::SetAvailability(
profile()->GetPrefs(), IncognitoModePrefs::Availability::kDisabled);
- auto new_tab_function =
+ auto new_window_function =
base::MakeRefCounted<BookmarkManagerPrivateOpenInNewWindowFunction>();
std::string args = base::StringPrintf(R"([["%s"], true])", node_id().c_str());
EXPECT_EQ("Incognito mode is disabled.",
- api_test_utils::RunFunctionAndReturnError(new_tab_function.get(),
+ api_test_utils::RunFunctionAndReturnError(new_window_function.get(),
args, profile()));
}
@@ -157,12 +157,12 @@ TEST_F(BookmarkManagerPrivateApiUnitTest,
IncognitoModePrefs::SetAvailability(
profile()->GetPrefs(), IncognitoModePrefs::Availability::kForced);
- auto new_tab_function =
+ auto new_window_function =
base::MakeRefCounted<BookmarkManagerPrivateOpenInNewWindowFunction>();
std::string args =
base::StringPrintf(R"([["%s"], false])", node_id().c_str());
EXPECT_EQ("Incognito mode is forced. Cannot open normal windows.",
- api_test_utils::RunFunctionAndReturnError(new_tab_function.get(),
+ api_test_utils::RunFunctionAndReturnError(new_window_function.get(),
args, profile()));
}
@@ -172,11 +172,11 @@ TEST_F(BookmarkManagerPrivateApiUnitTest,
model()->other_node(), 0, u"history", GURL("chrome://history"));
std::string node_id = base::NumberToString(node->id());
- auto new_tab_function =
+ auto new_window_function =
base::MakeRefCounted<BookmarkManagerPrivateOpenInNewWindowFunction>();
std::string args = base::StringPrintf(R"([["%s"], true])", node_id.c_str());
EXPECT_EQ("Cannot open URL \"chrome://history/\" in an incognito window.",
- api_test_utils::RunFunctionAndReturnError(new_tab_function.get(),
+ api_test_utils::RunFunctionAndReturnError(new_window_function.get(),
args, profile()));
}
diff --git a/chromium/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.cc b/chromium/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.cc
index d694fed2914..10b74a8d915 100644
--- a/chromium/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.cc
+++ b/chromium/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.cc
@@ -65,8 +65,8 @@ void PopulateBookmarkTreeNode(
if (parent) {
out_bookmark_tree_node->parent_id =
std::make_unique<std::string>(base::NumberToString(parent->id()));
- out_bookmark_tree_node->index =
- std::make_unique<int>(parent->GetIndexOf(node));
+ out_bookmark_tree_node->index = std::make_unique<int>(
+ static_cast<int>(parent->GetIndexOf(node).value()));
}
if (!node->is_folder()) {
diff --git a/chromium/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers_unittest.cc b/chromium/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers_unittest.cc
index 9385e7cefa6..89d3ed0feaf 100644
--- a/chromium/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/bookmarks/bookmark_api_helpers_unittest.cc
@@ -179,57 +179,57 @@ TEST_F(ExtensionBookmarksTest, GetMetaInfo) {
EXPECT_EQ(8u, id_to_meta_info_map.DictSize());
// Verify top level node.
- const base::Value* value = NULL;
- EXPECT_TRUE(id_to_meta_info_map.Get(
- base::NumberToString(model_->other_node()->id()), &value));
- ASSERT_TRUE(NULL != value);
- const base::DictionaryValue* dictionary_value = NULL;
- EXPECT_TRUE(value->GetAsDictionary(&dictionary_value));
- ASSERT_TRUE(nullptr != dictionary_value);
- EXPECT_EQ(0u, dictionary_value->DictSize());
+ {
+ const base::Value* value = nullptr;
+ EXPECT_TRUE(id_to_meta_info_map.Get(
+ base::NumberToString(model_->other_node()->id()), &value));
+ ASSERT_TRUE(nullptr != value);
+ ASSERT_TRUE(value->is_dict());
+ const base::Value::Dict& dict = value->GetDict();
+ EXPECT_EQ(0u, dict.size());
+ }
// Verify bookmark with two meta info key/value pairs.
- value = NULL;
- EXPECT_TRUE(
- id_to_meta_info_map.Get(base::NumberToString(node_->id()), &value));
- ASSERT_TRUE(NULL != value);
- dictionary_value = NULL;
- EXPECT_TRUE(value->GetAsDictionary(&dictionary_value));
- ASSERT_TRUE(nullptr != dictionary_value);
- EXPECT_EQ(2u, dictionary_value->DictSize());
- std::string string_value;
- EXPECT_TRUE(dictionary_value->GetString("some_key1", &string_value));
- EXPECT_EQ("some_value1", string_value);
- EXPECT_TRUE(dictionary_value->GetString("some_key2", &string_value));
- EXPECT_EQ("some_value2", string_value);
+ {
+ const base::Value* value = nullptr;
+ EXPECT_TRUE(
+ id_to_meta_info_map.Get(base::NumberToString(node_->id()), &value));
+ ASSERT_TRUE(nullptr != value);
+ ASSERT_TRUE(value->is_dict());
+ const base::Value::Dict& dict = value->GetDict();
+ EXPECT_EQ(2u, dict.size());
+ ASSERT_TRUE(dict.FindString("some_key1"));
+ EXPECT_EQ("some_value1", *(dict.FindString("some_key1")));
+ ASSERT_TRUE(dict.FindString("some_key2"));
+ EXPECT_EQ("some_value2", *(dict.FindString("some_key2")));
+ }
// Verify folder with one meta info key/value pair.
- value = NULL;
- EXPECT_TRUE(
- id_to_meta_info_map.Get(base::NumberToString(folder_->id()), &value));
- ASSERT_TRUE(NULL != value);
- dictionary_value = NULL;
- EXPECT_TRUE(value->GetAsDictionary(&dictionary_value));
- ASSERT_TRUE(nullptr != dictionary_value);
- EXPECT_EQ(1u, dictionary_value->DictSize());
- EXPECT_TRUE(dictionary_value->GetString("some_key1", &string_value));
- EXPECT_EQ("some_value1", string_value);
+ {
+ const base::Value* value = nullptr;
+ EXPECT_TRUE(
+ id_to_meta_info_map.Get(base::NumberToString(folder_->id()), &value));
+ ASSERT_TRUE(nullptr != value);
+ ASSERT_TRUE(value->is_dict());
+ const base::Value::Dict& dict = value->GetDict();
+ EXPECT_EQ(1u, dict.size());
+ ASSERT_TRUE(dict.FindString("some_key1"));
+ EXPECT_EQ("some_value1", *(dict.FindString("some_key1")));
+ }
// Verify bookmark in a subfolder with one meta info key/value pairs.
- value = NULL;
- EXPECT_TRUE(
- id_to_meta_info_map.Get(base::NumberToString(node2_->id()), &value));
- ASSERT_TRUE(NULL != value);
- dictionary_value = NULL;
- EXPECT_TRUE(value->GetAsDictionary(&dictionary_value));
- ASSERT_TRUE(nullptr != dictionary_value);
- EXPECT_EQ(1u, dictionary_value->DictSize());
- string_value.clear();
- EXPECT_FALSE(dictionary_value->GetString("some_key1", &string_value));
- EXPECT_EQ("", string_value);
- EXPECT_TRUE(dictionary_value->GetString("some_key2", &string_value));
- EXPECT_EQ("some_value2", string_value);
-
+ {
+ const base::Value* value = nullptr;
+ EXPECT_TRUE(
+ id_to_meta_info_map.Get(base::NumberToString(node2_->id()), &value));
+ ASSERT_TRUE(nullptr != value);
+ ASSERT_TRUE(value->is_dict());
+ const base::Value::Dict& dict = value->GetDict();
+ EXPECT_EQ(1u, dict.size());
+ ASSERT_FALSE(dict.FindString("some_key1"));
+ ASSERT_TRUE(dict.FindString("some_key2"));
+ EXPECT_EQ("some_value2", *(dict.FindString("some_key2")));
+ }
}
} // namespace bookmark_api_helpers
diff --git a/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc b/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
index 619c9a4d2b9..33287dd0b3d 100644
--- a/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
+++ b/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
@@ -129,7 +129,6 @@ const BookmarkNode* BookmarksFunction::GetBookmarkNodeFromId(
const BookmarkNode* BookmarksFunction::CreateBookmarkNode(
BookmarkModel* model,
const CreateDetails& details,
- const BookmarkNode::MetaInfoMap* meta_info,
std::string* error) {
int64_t parent_id;
@@ -172,9 +171,9 @@ const BookmarkNode* BookmarksFunction::CreateBookmarkNode(
const BookmarkNode* node;
if (url_string.length()) {
- node = model->AddURL(parent, index, title, url, meta_info);
+ node = model->AddNewURL(parent, index, title, url);
} else {
- node = model->AddFolder(parent, index, title, meta_info);
+ node = model->AddFolder(parent, index, title);
model->SetDateFolderModified(parent, base::Time::Now());
}
@@ -248,7 +247,7 @@ BookmarkEventRouter::~BookmarkEventRouter() {
void BookmarkEventRouter::DispatchEvent(events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> event_args) {
+ base::Value::List event_args) {
EventRouter* event_router = EventRouter::Get(browser_context_);
if (event_router) {
event_router->BroadcastEvent(std::make_unique<extensions::Event>(
@@ -598,7 +597,7 @@ ExtensionFunction::ResponseValue BookmarksCreateFunction::RunOnReady() {
BookmarkModel* model =
BookmarkModelFactory::GetForBrowserContext(GetProfile());
const BookmarkNode* node =
- CreateBookmarkNode(model, params->bookmark, nullptr, &error);
+ CreateBookmarkNode(model, params->bookmark, &error);
if (!node)
return Error(error);
diff --git a/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.h b/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.h
index 47f0145abe3..9912ca1e967 100644
--- a/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.h
+++ b/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api.h
@@ -88,7 +88,7 @@ class BookmarkEventRouter : public bookmarks::BookmarkModelObserver {
// Helper to actually dispatch an event to extension listeners.
void DispatchEvent(events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> event_args);
+ base::Value::List event_args);
raw_ptr<content::BrowserContext> browser_context_;
raw_ptr<bookmarks::BookmarkModel> model_;
@@ -158,7 +158,6 @@ class BookmarksFunction : public ExtensionFunction,
const bookmarks::BookmarkNode* CreateBookmarkNode(
bookmarks::BookmarkModel* model,
const api::bookmarks::CreateDetails& details,
- const bookmarks::BookmarkNode::MetaInfoMap* meta_info,
std::string* error);
// Helper that checks if bookmark editing is enabled.
diff --git a/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api_watcher.cc b/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api_watcher.cc
index 9e1496598a9..0c541879b59 100644
--- a/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api_watcher.cc
+++ b/chromium/chrome/browser/extensions/api/bookmarks/bookmarks_api_watcher.cc
@@ -6,13 +6,12 @@
#include "base/memory/singleton.h"
#include "base/observer_list.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
namespace extensions {
namespace {
-class BookmarksApiWatcherFactory : public BrowserContextKeyedServiceFactory {
+class BookmarksApiWatcherFactory : public ProfileKeyedServiceFactory {
public:
static BookmarksApiWatcher* GetForBrowserContext(
content::BrowserContext* context) {
@@ -25,9 +24,9 @@ class BookmarksApiWatcherFactory : public BrowserContextKeyedServiceFactory {
}
BookmarksApiWatcherFactory()
- : BrowserContextKeyedServiceFactory(
+ : ProfileKeyedServiceFactory(
"BookmarksApiWatcher",
- BrowserContextDependencyManager::GetInstance()) {}
+ ProfileSelections::BuildForRegularAndIncognito()) {}
private:
// BrowserContextKeyedServiceFactory overrides
@@ -35,11 +34,6 @@ class BookmarksApiWatcherFactory : public BrowserContextKeyedServiceFactory {
content::BrowserContext* context) const override {
return new BookmarksApiWatcher();
}
-
- content::BrowserContext* GetBrowserContextToUse(
- content::BrowserContext* context) const override {
- return context;
- }
};
} // namespace
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 1f60641e7e7..e7f5a97ccc7 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
@@ -14,7 +14,6 @@
#include "base/bind.h"
#include "base/strings/stringprintf.h"
#include "base/task/thread_pool.h"
-#include "base/values.h"
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/account_reconcilor_factory.h"
@@ -161,15 +160,13 @@ ExtensionFunction::ResponseAction BrowsingDataSettingsFunction::Run() {
// REMOVE_SITE_DATA in browsing_data_remover.h, the former for the unprotected
// web, the latter for protected web data. There is no UI control for
// extension data.
- base::Value origin_types(base::Value::Type::DICTIONARY);
- origin_types.SetBoolKey(
- extension_browsing_data_api_constants::kUnprotectedWebKey,
- isDataTypeSelected(BrowsingDataType::COOKIES, tab));
- origin_types.SetBoolKey(
- extension_browsing_data_api_constants::kProtectedWebKey,
- isDataTypeSelected(BrowsingDataType::HOSTED_APPS_DATA, tab));
- origin_types.SetBoolKey(extension_browsing_data_api_constants::kExtensionsKey,
- false);
+ base::Value::Dict origin_types;
+ origin_types.Set(extension_browsing_data_api_constants::kUnprotectedWebKey,
+ isDataTypeSelected(BrowsingDataType::COOKIES, tab));
+ origin_types.Set(extension_browsing_data_api_constants::kProtectedWebKey,
+ isDataTypeSelected(BrowsingDataType::HOSTED_APPS_DATA, tab));
+ origin_types.Set(extension_browsing_data_api_constants::kExtensionsKey,
+ false);
// Fill deletion time period.
int period_pref =
@@ -183,14 +180,14 @@ ExtensionFunction::ResponseAction BrowsingDataSettingsFunction::Run() {
since = time.ToJsTime();
}
- base::Value options(base::Value::Type::DICTIONARY);
- options.SetKey(extension_browsing_data_api_constants::kOriginTypesKey,
- std::move(origin_types));
- options.SetDoubleKey(extension_browsing_data_api_constants::kSinceKey, since);
+ base::Value::Dict options;
+ options.Set(extension_browsing_data_api_constants::kOriginTypesKey,
+ std::move(origin_types));
+ options.Set(extension_browsing_data_api_constants::kSinceKey, since);
// Fill dataToRemove and dataRemovalPermitted.
- base::Value selected(base::Value::Type::DICTIONARY);
- base::Value permitted(base::Value::Type::DICTIONARY);
+ base::Value::Dict selected;
+ base::Value::Dict permitted;
bool delete_site_data =
isDataTypeSelected(BrowsingDataType::COOKIES, tab) ||
@@ -237,23 +234,23 @@ ExtensionFunction::ResponseAction BrowsingDataSettingsFunction::Run() {
extension_browsing_data_api_constants::kPasswordsKey,
isDataTypeSelected(BrowsingDataType::PASSWORDS, tab));
- base::Value result(base::Value::Type::DICTIONARY);
- result.SetKey(extension_browsing_data_api_constants::kOptionsKey,
- std::move(options));
- result.SetKey(extension_browsing_data_api_constants::kDataToRemoveKey,
- std::move(selected));
- result.SetKey(extension_browsing_data_api_constants::kDataRemovalPermittedKey,
- std::move(permitted));
- return RespondNow(OneArgument(std::move(result)));
+ base::Value::Dict result;
+ result.Set(extension_browsing_data_api_constants::kOptionsKey,
+ std::move(options));
+ result.Set(extension_browsing_data_api_constants::kDataToRemoveKey,
+ std::move(selected));
+ result.Set(extension_browsing_data_api_constants::kDataRemovalPermittedKey,
+ std::move(permitted));
+ return RespondNow(WithArguments(std::move(result)));
}
-void BrowsingDataSettingsFunction::SetDetails(base::Value* selected_dict,
- base::Value* permitted_dict,
+void BrowsingDataSettingsFunction::SetDetails(base::Value::Dict* selected_dict,
+ base::Value::Dict* permitted_dict,
const char* data_type,
bool is_selected) {
bool is_permitted = IsRemovalPermitted(MaskForKey(data_type), prefs_);
- selected_dict->SetBoolKey(data_type, is_selected && is_permitted);
- permitted_dict->SetBoolKey(data_type, is_permitted);
+ selected_dict->Set(data_type, is_selected && is_permitted);
+ permitted_dict->Set(data_type, is_permitted);
}
BrowsingDataRemoverFunction::BrowsingDataRemoverFunction() = default;
@@ -270,7 +267,7 @@ void BrowsingDataRemoverFunction::OnTaskFinished() {
return;
synced_data_deletion_.reset();
observation_.Reset();
- Respond(NoArguments());
+ Respond(WithArguments());
Release(); // Balanced in StartRemoving.
}
@@ -282,13 +279,13 @@ ExtensionFunction::ResponseAction BrowsingDataRemoverFunction::Run() {
// Grab the initial |options| parameter, and parse out the arguments.
EXTENSION_FUNCTION_VALIDATE(args().size() >= 1);
EXTENSION_FUNCTION_VALIDATE(args()[0].is_dict());
- const base::Value& options = args()[0];
+ const base::Value::Dict& options = args()[0].GetDict();
EXTENSION_FUNCTION_VALIDATE(ParseOriginTypeMask(options, &origin_type_mask_));
// If |ms_since_epoch| isn't set, default it to 0.
double ms_since_epoch =
- options.FindDoubleKey(extension_browsing_data_api_constants::kSinceKey)
+ options.FindDouble(extension_browsing_data_api_constants::kSinceKey)
.value_or(0);
// base::Time takes a double that represents seconds since epoch. JavaScript
@@ -298,9 +295,9 @@ ExtensionFunction::ResponseAction BrowsingDataRemoverFunction::Run() {
EXTENSION_FUNCTION_VALIDATE(GetRemovalMask(&removal_mask_));
- const base::Value* origins =
- options.FindListKey(extension_browsing_data_api_constants::kOriginsKey);
- const base::Value* exclude_origins = options.FindListKey(
+ const base::Value::List* origins =
+ options.FindList(extension_browsing_data_api_constants::kOriginsKey);
+ const base::Value::List* exclude_origins = options.FindList(
extension_browsing_data_api_constants::kExcludeOriginsKey);
// Check that only |origins| or |excludeOrigins| can be set.
@@ -402,29 +399,27 @@ void BrowsingDataRemoverFunction::StartRemoving() {
}
bool BrowsingDataRemoverFunction::ParseOriginTypeMask(
- const base::Value& options,
+ const base::Value::Dict& options,
uint64_t* origin_type_mask) {
- DCHECK(options.is_dict());
-
// Parse the |options| dictionary to generate the origin set mask. Default to
// UNPROTECTED_WEB if the developer doesn't specify anything.
*origin_type_mask = content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB;
const base::Value* origin_type_dict =
- options.FindKey(extension_browsing_data_api_constants::kOriginTypesKey);
+ options.Find(extension_browsing_data_api_constants::kOriginTypesKey);
if (!origin_type_dict)
return true;
if (!origin_type_dict->is_dict())
return false;
- const base::Value* option = nullptr;
+ const base::Value::Dict& origin_type = origin_type_dict->GetDict();
// The developer specified something! Reset to 0 and parse the dictionary.
*origin_type_mask = 0;
// Unprotected web.
- option = origin_type_dict->FindKey(
+ const base::Value* option = origin_type.Find(
extension_browsing_data_api_constants::kUnprotectedWebKey);
if (option) {
if (!option->is_bool())
@@ -437,8 +432,8 @@ bool BrowsingDataRemoverFunction::ParseOriginTypeMask(
}
// Protected web.
- option = origin_type_dict->FindKey(
- extension_browsing_data_api_constants::kProtectedWebKey);
+ option =
+ origin_type.Find(extension_browsing_data_api_constants::kProtectedWebKey);
if (option) {
if (!option->is_bool())
return false;
@@ -450,8 +445,8 @@ bool BrowsingDataRemoverFunction::ParseOriginTypeMask(
}
// Extensions.
- option = origin_type_dict->FindKey(
- extension_browsing_data_api_constants::kExtensionsKey);
+ option =
+ origin_type.Find(extension_browsing_data_api_constants::kExtensionsKey);
if (option) {
if (!option->is_bool())
return false;
@@ -464,12 +459,12 @@ bool BrowsingDataRemoverFunction::ParseOriginTypeMask(
return true;
}
-bool BrowsingDataRemoverFunction::ParseOrigins(const base::Value& list_value,
- std::vector<url::Origin>* result,
- ResponseValue* error_response) {
- DCHECK(list_value.is_list());
- result->reserve(list_value.GetListDeprecated().size());
- for (const auto& value : list_value.GetListDeprecated()) {
+bool BrowsingDataRemoverFunction::ParseOrigins(
+ const base::Value::List& list_value,
+ std::vector<url::Origin>* result,
+ ResponseValue* error_response) {
+ result->reserve(list_value.size());
+ for (const auto& value : list_value) {
if (!value.is_string()) {
*error_response = BadMessage();
return false;
diff --git a/chromium/chrome/browser/extensions/api/browsing_data/browsing_data_api.h b/chromium/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
index aa309afea3e..fd7ec8100d7 100644
--- a/chromium/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
+++ b/chromium/chrome/browser/extensions/api/browsing_data/browsing_data_api.h
@@ -76,8 +76,8 @@ class BrowsingDataSettingsFunction : public ExtensionFunction {
// indicating whether the data type is both selected and permitted to be
// removed; and a value in the |permitted_dict| with the |data_type| as a
// key, indicating only whether the data type is permitted to be removed.
- void SetDetails(base::Value* selected_dict,
- base::Value* permitted_dict,
+ void SetDetails(base::Value::Dict* selected_dict,
+ base::Value::Dict* permitted_dict,
const char* data_type,
bool is_selected);
@@ -127,13 +127,13 @@ class BrowsingDataRemoverFunction
// that can be used with the BrowsingDataRemover.
// Returns true if parsing was successful.
// Pre-condition: `options` is a dictionary.
- bool ParseOriginTypeMask(const base::Value& options,
+ bool ParseOriginTypeMask(const base::Value::Dict& options,
uint64_t* origin_type_mask);
// Parses the developer-provided list of origins into |result|.
// Returns whether or not parsing was successful. In case of parse failure,
// |error_response| will contain the error response.
- bool ParseOrigins(const base::Value& list_value,
+ bool ParseOrigins(const base::Value::List& list_value,
std::vector<url::Origin>* result,
ResponseValue* error_response);
diff --git a/chromium/chrome/browser/extensions/api/certificate_provider/OWNERS b/chromium/chrome/browser/extensions/api/certificate_provider/OWNERS
index 325f7c3fcd6..5f652fe7f8b 100644
--- a/chromium/chrome/browser/extensions/api/certificate_provider/OWNERS
+++ b/chromium/chrome/browser/extensions/api/certificate_provider/OWNERS
@@ -1 +1,2 @@
emaxx@chromium.org
+fabiansommer@chromium.org
diff --git a/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc b/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
index bbb0fd587fa..c0a6fb40d1e 100644
--- a/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
+++ b/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
@@ -498,7 +498,7 @@ ExtensionFunction::ResponseAction CertificateProviderRequestPinFunction::Run() {
void CertificateProviderRequestPinFunction::OnInputReceived(
const std::string& value) {
- std::vector<base::Value> create_results;
+ base::Value::List create_results;
chromeos::CertificateProviderService* const service =
chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
browser_context());
@@ -508,8 +508,7 @@ void CertificateProviderRequestPinFunction::OnInputReceived(
LOG(WARNING) << "PIN request succeeded";
api::certificate_provider::PinResponseDetails details;
details.user_input = std::make_unique<std::string>(value);
- create_results.emplace_back(
- base::Value::FromUniquePtrValue(details.ToValue()));
+ create_results.Append(base::Value::FromUniquePtrValue(details.ToValue()));
} else {
// TODO(crbug.com/1046860): Remove logging after stabilizing the feature.
LOG(WARNING) << "PIN request canceled";
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 a17bf5a807b..c84877724a1 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
@@ -18,6 +18,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/hash/sha1.h"
+#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/path_service.h"
#include "base/run_loop.h"
@@ -297,7 +298,8 @@ class CertificateProviderApiTest : public extensions::ExtensionApiTest {
protected:
testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_;
- chromeos::CertificateProviderService* cert_provider_service_ = nullptr;
+ raw_ptr<chromeos::CertificateProviderService> cert_provider_service_ =
+ nullptr;
policy::PolicyMap policy_map_;
private:
@@ -505,8 +507,8 @@ class CertificateProviderApiMockedExtensionTest
return certificate_data;
}
- content::WebContents* extension_contents_ = nullptr;
- const extensions::Extension* extension_ = nullptr;
+ raw_ptr<content::WebContents> extension_contents_ = nullptr;
+ raw_ptr<const extensions::Extension> extension_ = nullptr;
base::FilePath extension_path_;
};
@@ -612,7 +614,7 @@ class CertificateProviderRequestPinTest : public CertificateProviderApiTest {
extension_ = LoadExtension(extension_path);
}
- const extensions::Extension* extension_ = nullptr;
+ raw_ptr<const extensions::Extension> 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 7775713ac64..a3165a89bcd 100644
--- a/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc
+++ b/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -66,10 +66,16 @@
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/settings/cros_settings.h"
#include "chrome/browser/extensions/api/file_handlers/non_native_file_system_delegate_chromeos.h"
+#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.h"
#include "chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.h"
#include "chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h"
#endif
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h"
+#include "chrome/browser/extensions/api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.h"
+#endif
+
#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/extensions/clipboard_extension_helper_chromeos.h"
#endif
@@ -163,7 +169,9 @@ bool ChromeExtensionsAPIClient::ShouldHideBrowserNetworkRequest(
// Hide requests made by the NTP Instant renderer.
auto* instant_service =
- InstantServiceFactory::GetForProfile(static_cast<Profile*>(context));
+ context
+ ? InstantServiceFactory::GetForProfile(static_cast<Profile*>(context))
+ : nullptr;
if (instant_service) {
is_sensitive_request |=
instant_service->IsInstantProcess(request.render_process_id);
@@ -184,10 +192,10 @@ void ChromeExtensionsAPIClient::NotifyWebRequestWithheld(
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
if (!rfh)
return;
- // We don't count subframe 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->GetParent())
+ // 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())
return;
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(rfh);
@@ -350,6 +358,8 @@ ChromeExtensionsAPIClient::CreateVirtualKeyboardDelegate(
content::BrowserContext* browser_context) const {
#if BUILDFLAG(IS_CHROMEOS_ASH)
return std::make_unique<ChromeVirtualKeyboardDelegate>(browser_context);
+#elif BUILDFLAG(IS_CHROMEOS_LACROS)
+ return std::make_unique<LacrosVirtualKeyboardDelegate>();
#else
return nullptr;
#endif
@@ -382,8 +392,15 @@ MetricsPrivateDelegate* ChromeExtensionsAPIClient::GetMetricsPrivateDelegate() {
}
FileSystemDelegate* ChromeExtensionsAPIClient::GetFileSystemDelegate() {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ using ChromeFileSystemDelegate_Use = ChromeFileSystemDelegateAsh;
+#elif BUILDFLAG(IS_CHROMEOS_LACROS)
+ using ChromeFileSystemDelegate_Use = ChromeFileSystemDelegateLacros;
+#else
+ using ChromeFileSystemDelegate_Use = ChromeFileSystemDelegate;
+#endif
if (!file_system_delegate_)
- file_system_delegate_ = std::make_unique<ChromeFileSystemDelegate>();
+ file_system_delegate_ = std::make_unique<ChromeFileSystemDelegate_Use>();
return file_system_delegate_.get();
}
diff --git a/chromium/chrome/browser/extensions/api/commands/command_service.cc b/chromium/chrome/browser/extensions/api/commands/command_service.cc
index 37a16edb85d..0dd3a1d6cd0 100644
--- a/chromium/chrome/browser/extensions/api/commands/command_service.cc
+++ b/chromium/chrome/browser/extensions/api/commands/command_service.cc
@@ -82,7 +82,9 @@ void MergeSuggestedKeyPrefs(
if (extension_prefs->ReadPrefAsDictionary(extension_id,
kCommands,
&current_prefs)) {
- std::unique_ptr<base::DictionaryValue> new_prefs(current_prefs->DeepCopy());
+ std::unique_ptr<base::DictionaryValue> new_prefs =
+ base::DictionaryValue::From(
+ base::Value::ToUniquePtrValue(current_prefs->Clone()));
new_prefs->MergeDictionary(suggested_key_prefs.get());
suggested_key_prefs = std::move(new_prefs);
}
@@ -293,9 +295,9 @@ bool CommandService::SetScope(const std::string& extension_id,
Command CommandService::FindCommandByName(const std::string& extension_id,
const std::string& command) const {
- const base::Value* bindings =
- profile_->GetPrefs()->GetDictionary(prefs::kExtensionCommands);
- for (const auto it : bindings->DictItems()) {
+ const base::Value::Dict& bindings =
+ profile_->GetPrefs()->GetValueDict(prefs::kExtensionCommands);
+ for (const auto it : bindings) {
const std::string* extension = it.second.FindStringKey(kExtension);
if (!extension || *extension != extension_id)
continue;
@@ -552,22 +554,19 @@ void CommandService::UpdateExtensionSuggestedCommandPrefs(
void CommandService::RemoveDefunctExtensionSuggestedCommandPrefs(
const Extension* extension) {
ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_);
- const base::DictionaryValue* current_prefs = nullptr;
- extension_prefs->ReadPrefAsDictionary(extension->id(),
- kCommands,
- &current_prefs);
+ const base::Value::Dict* current_prefs =
+ extension_prefs->ReadPrefAsDict(extension->id(), kCommands);
if (current_prefs) {
- std::unique_ptr<base::DictionaryValue> suggested_key_prefs(
- current_prefs->DeepCopy());
+ base::Value::Dict suggested_key_prefs = current_prefs->Clone();
+
const CommandMap* named_commands =
CommandsInfo::GetNamedCommands(extension);
const Command* browser_action_command =
CommandsInfo::GetBrowserActionCommand(extension);
- for (base::DictionaryValue::Iterator it(*current_prefs);
- !it.IsAtEnd(); it.Advance()) {
- if (it.key() == manifest_values::kBrowserActionCommandEvent) {
+ for (const auto [key, _] : *current_prefs) {
+ if (key == manifest_values::kBrowserActionCommandEvent) {
// The browser action command may be defaulted to an unassigned
// accelerator if a browser action is specified by the extension but a
// keybinding is not declared. See
@@ -575,22 +574,23 @@ void CommandService::RemoveDefunctExtensionSuggestedCommandPrefs(
if (!browser_action_command ||
browser_action_command->accelerator().key_code() ==
ui::VKEY_UNKNOWN) {
- suggested_key_prefs->RemoveKey(it.key());
+ suggested_key_prefs.Remove(key);
}
- } else if (it.key() == manifest_values::kPageActionCommandEvent) {
+ } else if (key == manifest_values::kPageActionCommandEvent) {
if (!CommandsInfo::GetPageActionCommand(extension))
- suggested_key_prefs->RemoveKey(it.key());
- } else if (it.key() == manifest_values::kActionCommandEvent) {
+ suggested_key_prefs.Remove(key);
+ } else if (key == manifest_values::kActionCommandEvent) {
if (!CommandsInfo::GetActionCommand(extension))
- suggested_key_prefs->RemoveKey(it.key());
+ suggested_key_prefs.Remove(key);
} else if (named_commands) {
- if (named_commands->find(it.key()) == named_commands->end())
- suggested_key_prefs->RemoveKey(it.key());
+ if (named_commands->find(key) == named_commands->end())
+ suggested_key_prefs.Remove(key);
}
}
- extension_prefs->UpdateExtensionPref(extension->id(), kCommands,
- std::move(suggested_key_prefs));
+ extension_prefs->UpdateExtensionPref(
+ extension->id(), kCommands,
+ std::make_unique<base::Value>(std::move(suggested_key_prefs)));
}
}
@@ -601,20 +601,20 @@ bool CommandService::IsCommandShortcutUserModified(
ui::Accelerator suggested_key;
absl::optional<bool> suggested_key_was_assigned;
ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_);
- const base::DictionaryValue* commands_prefs = nullptr;
- if (extension_prefs->ReadPrefAsDictionary(extension->id(), kCommands,
- &commands_prefs)) {
- const base::Value* suggested_key_prefs =
- commands_prefs->FindDictPath(command_name);
+ const base::Value::Dict* commands_prefs =
+ extension_prefs->ReadPrefAsDict(extension->id(), kCommands);
+ if (commands_prefs) {
+ const base::Value::Dict* suggested_key_prefs =
+ commands_prefs->FindDict(command_name);
if (suggested_key_prefs) {
const std::string* suggested_key_string =
- suggested_key_prefs->FindStringKey(kSuggestedKey);
+ suggested_key_prefs->FindString(kSuggestedKey);
if (suggested_key_string) {
suggested_key =
Command::StringToAccelerator(*suggested_key_string, command_name);
}
suggested_key_was_assigned =
- suggested_key_prefs->FindBoolKey(kSuggestedKeyWasAssigned);
+ suggested_key_prefs->FindBool(kSuggestedKeyWasAssigned);
}
}
@@ -639,21 +639,17 @@ void CommandService::RemoveKeybindingPrefs(const std::string& extension_id,
if (!IsForCurrentPlatform(it.first))
continue;
- const base::DictionaryValue* item = nullptr;
- it.second.GetAsDictionary(&item);
-
- std::string extension;
- item->GetString(kExtension, &extension);
+ const base::Value::Dict& dict = it.second.GetDict();
+ const std::string* extension = dict.FindString(kExtension);
- if (extension == extension_id) {
+ if (extension && *extension == extension_id) {
// If |command_name| is specified, delete only that command. Otherwise,
// delete all commands.
- std::string command;
- item->GetString(kCommandName, &command);
- if (!command_name.empty() && command_name != command)
+ const std::string* command = dict.FindString(kCommandName);
+ if (command && !command_name.empty() && command_name != *command)
continue;
- removed_commands.push_back(FindCommandByName(extension_id, command));
+ removed_commands.push_back(FindCommandByName(extension_id, *command));
keys_to_remove.push_back(it.first);
}
}
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 b9bcc6e36b9..9d738a4e8e6 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
@@ -53,7 +53,7 @@ namespace pref_keys = extensions::preference_api_constants;
namespace {
-bool RemoveContentType(std::vector<base::Value>& args,
+bool RemoveContentType(base::Value::List& args,
ContentSettingsType* content_type) {
if (args.empty() || !args[0].is_string())
return false;
@@ -112,7 +112,7 @@ ContentSettingsContentSettingClearFunction::Run() {
store->ClearContentSettingsForExtensionAndContentType(extension_id(), scope,
content_type);
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
ExtensionFunction::ResponseAction
@@ -166,17 +166,18 @@ ContentSettingsContentSettingGetFunction::Run() {
ContentSetting setting =
content_type == ContentSettingsType::COOKIES
- ? cookie_settings->GetCookieSetting(primary_url, secondary_url,
- nullptr)
+ ? cookie_settings->GetCookieSetting(
+ primary_url, secondary_url, nullptr,
+ content_settings::CookieSettings::QueryReason::kSetting)
: map->GetContentSetting(primary_url, secondary_url, content_type);
- base::Value result(base::Value::Type::DICTIONARY);
+ base::Value::Dict result;
std::string setting_string =
content_settings::ContentSettingToString(setting);
DCHECK(!setting_string.empty());
- result.SetStringKey(ContentSettingsStore::kContentSettingKey, setting_string);
+ result.Set(ContentSettingsStore::kContentSettingKey, setting_string);
- return RespondNow(OneArgument(std::move(result)));
+ return RespondNow(WithArguments(std::move(result)));
}
ExtensionFunction::ResponseAction
@@ -301,7 +302,7 @@ ContentSettingsContentSettingSetFunction::Run() {
secondary_pattern, content_type, setting,
scope);
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
ExtensionFunction::ResponseAction
@@ -310,7 +311,7 @@ ContentSettingsContentSettingGetResourceIdentifiersFunction::Run() {
// plugins have been deprecated since Chrome 87, there are no resource
// identifiers for existing settings (but we retain the function for
// backwards and potential forwards compatibility).
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
} // namespace extensions
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 f90c84a85f1..5b419f0c423 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
@@ -50,6 +50,7 @@
namespace extensions {
using ContextType = ExtensionApiTest::ContextType;
+using QueryReason = content_settings::CookieSettings::QueryReason;
class ExtensionContentSettingsApiTest : public ExtensionApiTest {
public:
@@ -99,9 +100,10 @@ class ExtensionContentSettingsApiTest : public ExtensionApiTest {
// Check default content settings by using an unknown URL.
GURL example_url("http://www.example.com");
- EXPECT_TRUE(
- cookie_settings->IsFullCookieAccessAllowed(example_url, example_url));
- EXPECT_TRUE(cookie_settings->IsCookieSessionOnly(example_url));
+ EXPECT_TRUE(cookie_settings->IsFullCookieAccessAllowed(
+ example_url, example_url, QueryReason::kSetting));
+ EXPECT_TRUE(cookie_settings->IsCookieSessionOnly(example_url,
+ QueryReason::kSetting));
EXPECT_EQ(CONTENT_SETTING_ALLOW,
map->GetContentSetting(example_url, example_url,
ContentSettingsType::IMAGES));
@@ -132,7 +134,8 @@ class ExtensionContentSettingsApiTest : public ExtensionApiTest {
// Check content settings for www.google.com
GURL url("http://www.google.com");
- EXPECT_FALSE(cookie_settings->IsFullCookieAccessAllowed(url, url));
+ EXPECT_FALSE(cookie_settings->IsFullCookieAccessAllowed(
+ url, url, QueryReason::kSetting));
EXPECT_EQ(CONTENT_SETTING_ALLOW,
map->GetContentSetting(url, url, ContentSettingsType::IMAGES));
EXPECT_EQ(
@@ -167,8 +170,10 @@ class ExtensionContentSettingsApiTest : public ExtensionApiTest {
// Check content settings for www.google.com
GURL url("http://www.google.com");
- EXPECT_TRUE(cookie_settings->IsFullCookieAccessAllowed(url, url));
- EXPECT_FALSE(cookie_settings->IsCookieSessionOnly(url));
+ EXPECT_TRUE(cookie_settings->IsFullCookieAccessAllowed(
+ url, url, QueryReason::kSetting));
+ EXPECT_FALSE(
+ cookie_settings->IsCookieSessionOnly(url, QueryReason::kSetting));
EXPECT_EQ(CONTENT_SETTING_ALLOW,
map->GetContentSetting(url, url, ContentSettingsType::IMAGES));
EXPECT_EQ(
@@ -204,9 +209,10 @@ class ExtensionContentSettingsApiTest : public ExtensionApiTest {
content_settings::CookieSettings* cookie_settings =
CookieSettingsFactory::GetForProfile(profile_).get();
+ content_settings.push_back(cookie_settings->IsFullCookieAccessAllowed(
+ url, url, QueryReason::kSetting));
content_settings.push_back(
- cookie_settings->IsFullCookieAccessAllowed(url, url));
- content_settings.push_back(cookie_settings->IsCookieSessionOnly(url));
+ cookie_settings->IsCookieSessionOnly(url, QueryReason::kSetting));
content_settings.push_back(
map->GetContentSetting(url, url, ContentSettingsType::IMAGES));
content_settings.push_back(
diff --git a/chromium/chrome/browser/extensions/api/context_menus/context_menu_apitest.cc b/chromium/chrome/browser/extensions/api/context_menus/context_menu_apitest.cc
index e15e657eb8c..d20b85b989f 100644
--- a/chromium/chrome/browser/extensions/api/context_menus/context_menu_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/context_menus/context_menu_apitest.cc
@@ -123,8 +123,7 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuApiTestWithContextType,
class ExtensionContextMenuVisibilityApiTest
: public ExtensionContextMenuApiTest {
public:
- ExtensionContextMenuVisibilityApiTest()
- : top_level_model_(nullptr), menu_(nullptr), top_level_index_(-1) {}
+ ExtensionContextMenuVisibilityApiTest() = default;
ExtensionContextMenuVisibilityApiTest(
const ExtensionContextMenuVisibilityApiTest&) = delete;
@@ -155,7 +154,7 @@ class ExtensionContextMenuVisibilityApiTest
menu_->extension_items().ConvertToExtensionsCustomCommandId(0),
&top_level_model_, &top_level_index_);
- EXPECT_GT(top_level_index(), 0);
+ EXPECT_GT(top_level_index(), 0u);
return valid_setup;
}
@@ -175,14 +174,14 @@ class ExtensionContextMenuVisibilityApiTest
void VerifyNumExtensionItemsInMenuModel(int num_items,
ui::MenuModel::ItemType type) {
int num_found = 0;
- for (int i = 0; i < top_level_model_->GetItemCount(); i++) {
+ for (size_t i = 0; i < top_level_model_->GetItemCount(); ++i) {
int command_id = top_level_model_->GetCommandIdAt(i);
if (ContextMenuMatcher::IsExtensionsCustomCommandId(command_id) &&
top_level_model_->GetTypeAt(i) == type) {
- num_found++;
+ ++num_found;
}
}
- ASSERT_TRUE(num_found == num_items);
+ ASSERT_EQ(num_found, num_items);
}
// Verifies that the context menu is valid and contains the given number of
@@ -196,7 +195,7 @@ class ExtensionContextMenuVisibilityApiTest
// Verifies a context menu item's visibility, title, and item type.
void VerifyMenuItem(const std::string& title,
ui::MenuModel* model,
- int index,
+ size_t index,
ui::MenuModel::ItemType type,
bool visible) {
EXPECT_EQ(base::ASCIIToUTF16(title), model->GetLabelAt(index));
@@ -204,13 +203,13 @@ class ExtensionContextMenuVisibilityApiTest
EXPECT_EQ(visible, model->IsVisibleAt(index));
}
- int top_level_index() { return top_level_index_; }
+ size_t top_level_index() const { return top_level_index_; }
TestRenderViewContextMenu* menu() { return menu_.get(); }
const Extension* extension() { return extension_; }
- ui::MenuModel* top_level_model_;
+ ui::MenuModel* top_level_model_ = nullptr;
private:
content::WebContents* GetBackgroundPage(const std::string& extension_id) {
@@ -221,9 +220,9 @@ class ExtensionContextMenuVisibilityApiTest
ProcessManager* process_manager() { return ProcessManager::Get(profile()); }
- raw_ptr<const Extension> extension_;
+ raw_ptr<const Extension> extension_ = nullptr;
std::unique_ptr<TestRenderViewContextMenu> menu_;
- int top_level_index_;
+ size_t top_level_index_ = 0;
};
// Tests showing a single visible menu item in the top-level menu model, which
@@ -287,7 +286,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuVisibilityApiTest,
ui::MenuModel* submodel =
top_level_model_->GetSubmenuModelAt(top_level_index());
ASSERT_TRUE(submodel);
- EXPECT_EQ(2, submodel->GetItemCount());
+ EXPECT_EQ(2u, submodel->GetItemCount());
VerifyMenuItem("child1", submodel, 0, ui::MenuModel::TYPE_COMMAND, false);
VerifyMenuItem("child2", submodel, 1, ui::MenuModel::TYPE_COMMAND, false);
@@ -317,7 +316,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuVisibilityApiTest,
ui::MenuModel* submodel =
top_level_model_->GetSubmenuModelAt(top_level_index());
ASSERT_TRUE(submodel);
- EXPECT_EQ(2, submodel->GetItemCount());
+ EXPECT_EQ(2u, submodel->GetItemCount());
// Though the children's internal visibility state remains unchanged, the ui
// code will hide the children if the parent is hidden.
@@ -347,7 +346,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuVisibilityApiTest,
ui::MenuModel* submodel =
top_level_model_->GetSubmenuModelAt(top_level_index());
ASSERT_TRUE(submodel);
- EXPECT_EQ(2, submodel->GetItemCount());
+ EXPECT_EQ(2u, submodel->GetItemCount());
VerifyMenuItem("child1", submodel, 0, ui::MenuModel::TYPE_COMMAND, false);
VerifyMenuItem("child2", submodel, 1, ui::MenuModel::TYPE_COMMAND, false);
@@ -375,7 +374,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuVisibilityApiTest,
ui::MenuModel* submodel =
top_level_model_->GetSubmenuModelAt(top_level_index());
ASSERT_TRUE(submodel);
- EXPECT_EQ(2, submodel->GetItemCount());
+ EXPECT_EQ(2u, submodel->GetItemCount());
VerifyMenuItem("child1", submodel, 0, ui::MenuModel::TYPE_COMMAND, true);
VerifyMenuItem("child2", submodel, 1, ui::MenuModel::TYPE_COMMAND, false);
@@ -407,7 +406,7 @@ IN_PROC_BROWSER_TEST_F(
ui::MenuModel* submodel =
top_level_model_->GetSubmenuModelAt(top_level_index());
ASSERT_TRUE(submodel);
- EXPECT_EQ(1, submodel->GetItemCount());
+ EXPECT_EQ(1u, submodel->GetItemCount());
// When a parent item is specified by the developer (as opposed to generated),
// its visibility is determined by the specified state.
@@ -415,7 +414,7 @@ IN_PROC_BROWSER_TEST_F(
submodel = submodel->GetSubmenuModelAt(0);
ASSERT_TRUE(submodel);
- EXPECT_EQ(2, submodel->GetItemCount());
+ EXPECT_EQ(2u, submodel->GetItemCount());
VerifyMenuItem("child2", submodel, 0, ui::MenuModel::TYPE_COMMAND, false);
VerifyMenuItem("child3", submodel, 1, ui::MenuModel::TYPE_COMMAND, false);
@@ -443,7 +442,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuVisibilityApiTest,
ui::MenuModel* submodel =
top_level_model_->GetSubmenuModelAt(top_level_index());
ASSERT_TRUE(submodel);
- EXPECT_EQ(3, submodel->GetItemCount());
+ EXPECT_EQ(3u, submodel->GetItemCount());
VerifyMenuItem("item1", submodel, 0, ui::MenuModel::TYPE_COMMAND, false);
VerifyMenuItem("item2", submodel, 1, ui::MenuModel::TYPE_COMMAND, false);
@@ -472,7 +471,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuVisibilityApiTest,
ui::MenuModel* submodel =
top_level_model_->GetSubmenuModelAt(top_level_index());
ASSERT_TRUE(submodel);
- EXPECT_EQ(1, submodel->GetItemCount());
+ EXPECT_EQ(1u, submodel->GetItemCount());
VerifyMenuItem("child1", submodel, 0, ui::MenuModel::TYPE_COMMAND, false);
// Update child1 to visible.
@@ -526,7 +525,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuVisibilityApiTest,
ui::MenuModel* submodel =
top_level_model_->GetSubmenuModelAt(top_level_index());
ASSERT_TRUE(submodel);
- EXPECT_EQ(3, submodel->GetItemCount());
+ EXPECT_EQ(3u, submodel->GetItemCount());
VerifyMenuItem("item1", submodel, 0, ui::MenuModel::TYPE_COMMAND, true);
VerifyMenuItem("item2", submodel, 1, ui::MenuModel::TYPE_COMMAND, true);
@@ -534,7 +533,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuVisibilityApiTest,
ui::MenuModel* item3_submodel = submodel->GetSubmenuModelAt(2);
ASSERT_TRUE(item3_submodel);
- EXPECT_EQ(2, item3_submodel->GetItemCount());
+ EXPECT_EQ(2u, item3_submodel->GetItemCount());
// Though the children's internal visibility state remains unchanged, the ui
// code will hide the children if the parent is hidden.
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 c226e5bf65c..7507e8ece7c 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
@@ -216,7 +216,7 @@ class ExtensionContextMenuBrowserTest
return false;
MenuModel* model = nullptr;
- int index = -1;
+ size_t index = 0;
if (!menu->GetMenuModelAndItemIndex(command_id, &model, &index)) {
return false;
}
@@ -656,7 +656,7 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, TopLevel) {
std::unique_ptr<TestRenderViewContextMenu> menu(
TestRenderViewContextMenu::Create(GetWebContents(), url, GURL(), GURL()));
- int index = 0;
+ size_t index = 0;
MenuModel* model = nullptr;
ASSERT_TRUE(menu->GetMenuModelAndItemIndex(
@@ -676,7 +676,7 @@ IN_PROC_BROWSER_TEST_P(ExtensionContextMenuLazyTest, TopLevel) {
static void ExpectLabelAndType(const char* expected_label,
MenuModel::ItemType expected_type,
const MenuModel& menu,
- int index) {
+ size_t index) {
EXPECT_EQ(expected_type, menu.GetTypeAt(index));
EXPECT_EQ(base::UTF8ToUTF16(expected_label), menu.GetLabelAt(index));
}
@@ -698,11 +698,11 @@ static void VerifyMenuForSeparatorsTest(const MenuModel& menu) {
// --separator--
// normal3
- int index = 0;
+ size_t index = 0;
#if BUILDFLAG(IS_CHROMEOS_ASH)
- ASSERT_EQ(7, menu.GetItemCount());
+ ASSERT_EQ(7u, menu.GetItemCount());
#else
- ASSERT_EQ(11, menu.GetItemCount());
+ ASSERT_EQ(11u, menu.GetItemCount());
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
ExpectLabelAndType("radio1", MenuModel::TYPE_RADIO, menu, index++);
ExpectLabelAndType("radio2", MenuModel::TYPE_RADIO, menu, index++);
@@ -747,7 +747,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionContextMenuPersistentTest, Separators) {
// The top-level item should be an "automagic parent" with the extension's
// name.
MenuModel* model = nullptr;
- int index = 0;
+ size_t index = 0;
std::u16string label;
ASSERT_TRUE(menu->GetMenuModelAndItemIndex(
ContextMenuMatcher::ConvertToExtensionsCustomCommandId(0),
diff --git a/chromium/chrome/browser/extensions/api/cookies/cookies_api.cc b/chromium/chrome/browser/extensions/api/cookies/cookies_api.cc
index f30e82d97b9..43eb3bc0da3 100644
--- a/chromium/chrome/browser/extensions/api/cookies/cookies_api.cc
+++ b/chromium/chrome/browser/extensions/api/cookies/cookies_api.cc
@@ -14,7 +14,6 @@
#include "base/json/json_writer.h"
#include "base/lazy_instance.h"
#include "base/time/time.h"
-#include "base/values.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/api/cookies/cookies_api_constants.h"
#include "chrome/browser/extensions/api/cookies/cookies_helpers.h"
@@ -118,17 +117,18 @@ void CookiesEventRouter::OnCookieChange(bool otr,
const net::CookieChangeInfo& change) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- std::unique_ptr<base::ListValue> args(new base::ListValue());
- base::Value dict(base::Value::Type::DICTIONARY);
- dict.SetBoolKey(cookies_api_constants::kRemovedKey,
- change.cause != net::CookieChangeCause::INSERTED);
+ base::Value::List args;
+ base::Value::Dict dict;
+ dict.Set(cookies_api_constants::kRemovedKey,
+ change.cause != net::CookieChangeCause::INSERTED);
Profile* profile =
otr ? profile_->GetPrimaryOTRProfile(/*create_if_needed=*/true)
: profile_->GetOriginalProfile();
api::cookies::Cookie cookie = cookies_helpers::CreateCookie(
change.cookie, cookies_helpers::GetStoreIdFromProfile(profile));
- dict.SetKey(cookies_api_constants::kCookieKey, std::move(*cookie.ToValue()));
+ dict.Set(cookies_api_constants::kCookieKey,
+ base::Value::FromUniquePtrValue(cookie.ToValue()));
// Map the internal cause to an external string.
std::string cause_dict_entry;
@@ -159,9 +159,9 @@ void CookiesEventRouter::OnCookieChange(bool otr,
case net::CookieChangeCause::UNKNOWN_DELETION:
NOTREACHED();
}
- dict.SetStringKey(cookies_api_constants::kCauseKey, cause_dict_entry);
+ dict.Set(cookies_api_constants::kCauseKey, cause_dict_entry);
- args->Append(std::move(dict));
+ args.Append(std::move(dict));
DispatchEvent(profile, events::COOKIES_ON_CHANGED,
api::cookies::OnChanged::kEventName, std::move(args),
@@ -215,18 +215,16 @@ void CookiesEventRouter::OnConnectionError(
MaybeStartListening();
}
-void CookiesEventRouter::DispatchEvent(
- content::BrowserContext* context,
- events::HistogramValue histogram_value,
- const std::string& event_name,
- std::unique_ptr<base::ListValue> event_args,
- const GURL& cookie_domain) {
- EventRouter* router = context ? EventRouter::Get(context) : NULL;
+void CookiesEventRouter::DispatchEvent(content::BrowserContext* context,
+ events::HistogramValue histogram_value,
+ const std::string& event_name,
+ base::Value::List event_args,
+ const GURL& cookie_domain) {
+ EventRouter* router = context ? EventRouter::Get(context) : nullptr;
if (!router)
return;
- auto event = std::make_unique<Event>(
- histogram_value, event_name, std::move(*event_args).TakeListDeprecated(),
- context);
+ auto event = std::make_unique<Event>(histogram_value, event_name,
+ std::move(event_args), context);
event->event_url = cookie_domain;
router->BroadcastEvent(std::move(event));
}
@@ -280,7 +278,7 @@ void CookiesGetFunction::GetCookieListCallback(
}
// The cookie doesn't exist; return null.
- Respond(OneArgument(base::Value()));
+ Respond(WithArguments(base::Value()));
}
CookiesGetAllFunction::CookiesGetAllFunction() {
@@ -337,7 +335,7 @@ void CookiesGetAllFunction::GetAllCookiesCallback(
ArgumentList(api::cookies::GetAll::Results::Create(match_vector));
} else {
// TODO(devlin): When can |extension()| be null for this function?
- response = NoArguments();
+ response = WithArguments();
}
Respond(std::move(response));
}
@@ -356,7 +354,7 @@ void CookiesGetAllFunction::GetCookieListCallback(
ArgumentList(api::cookies::GetAll::Results::Create(match_vector));
} else {
// TODO(devlin): When can |extension()| be null for this function?
- response = NoArguments();
+ response = WithArguments();
}
Respond(std::move(response));
}
@@ -498,7 +496,7 @@ void CookiesSetFunction::GetCookieListCallback(
}
}
- Respond(value ? std::move(value) : NoArguments());
+ Respond(value ? std::move(value) : WithArguments());
}
CookiesRemoveFunction::CookiesRemoveFunction() {
diff --git a/chromium/chrome/browser/extensions/api/cookies/cookies_api.h b/chromium/chrome/browser/extensions/api/cookies/cookies_api.h
index 33f64d5b1e5..c0a2701716b 100644
--- a/chromium/chrome/browser/extensions/api/cookies/cookies_api.h
+++ b/chromium/chrome/browser/extensions/api/cookies/cookies_api.h
@@ -13,6 +13,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
+#include "base/values.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/common/extensions/api/cookies.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
@@ -79,7 +80,7 @@ class CookiesEventRouter : public BrowserListObserver {
void DispatchEvent(content::BrowserContext* context,
events::HistogramValue histogram_value,
const std::string& event_name,
- std::unique_ptr<base::ListValue> event_args,
+ base::Value::List event_args,
const GURL& cookie_domain);
raw_ptr<Profile> profile_;
diff --git a/chromium/chrome/browser/extensions/api/cookies/cookies_unittest.cc b/chromium/chrome/browser/extensions/api/cookies/cookies_unittest.cc
index c2b5547b76f..08eddf075ec 100644
--- a/chromium/chrome/browser/extensions/api/cookies/cookies_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/cookies/cookies_unittest.cc
@@ -176,10 +176,10 @@ TEST_F(ExtensionCookiesTest, DomainMatching) {
for (size_t i = 0; i < std::size(tests); ++i) {
// Build up the Params struct.
- std::vector<base::Value> args;
- base::Value dict(base::Value::Type::DICTIONARY);
- dict.SetStringKey(keys::kDomainKey, std::string(tests[i].filter));
- args.emplace_back(std::move(dict));
+ base::Value::List args;
+ base::Value::Dict dict;
+ dict.Set(keys::kDomainKey, tests[i].filter);
+ args.Append(std::move(dict));
std::unique_ptr<GetAll::Params> params(GetAll::Params::Create(args));
cookies_helpers::MatchFilter filter(&params->details);
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 ef734bfc51a..020bde63e9f 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
@@ -8,7 +8,7 @@
#include "base/system/sys_info.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
-#include "chrome/browser/ash/web_applications/system_web_app_integration_test.h"
+#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_integration_test.h"
#include "chrome/browser/devtools/devtools_window_testing.h"
#include "chrome/browser/error_reporting/mock_chrome_js_error_report_processor.h"
#include "chrome/browser/extensions/api/crash_report_private/crash_report_private_api.h"
@@ -308,7 +308,7 @@ IN_PROC_BROWSER_TEST_F(CrashReportPrivateApiTest, CalledFromWebContentsInTab) {
EXPECT_EQ(report.content, "");
}
-using CrashReportPrivateCalledFromSwaTest = SystemWebAppIntegrationTest;
+using CrashReportPrivateCalledFromSwaTest = ash::SystemWebAppIntegrationTest;
// Test WEB_APP is detected when |CrashReportPrivate| is called from an app
// window.
diff --git a/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc b/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc
index 969f24f155e..6fad739f111 100644
--- a/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc
@@ -57,13 +57,13 @@ constexpr const char* kGoogleGstaticAppIds[] = {
// ContainsAppIdByHash returns true iff the SHA-256 hash of one of the
// elements of |list| equals |hash|.
-bool ContainsAppIdByHash(const base::Value& list,
+bool ContainsAppIdByHash(const base::Value::List& list,
const std::vector<uint8_t>& hash) {
if (hash.size() != crypto::kSHA256Length) {
return false;
}
- for (const auto& i : list.GetListDeprecated()) {
+ for (const auto& i : list) {
const std::string& s = i.GetString();
if (s.find('/') == std::string::npos) {
// No slashes mean that this is a webauthn RP ID, not a U2F AppID.
@@ -122,7 +122,7 @@ CryptotokenPrivateCanOriginAssertAppIdFunction::Run() {
}
if (origin_url == app_id_url) {
- return RespondNow(OneArgument(base::Value(true)));
+ return RespondNow(WithArguments(true));
}
// Fetch the eTLD+1 of both.
@@ -143,7 +143,7 @@ CryptotokenPrivateCanOriginAssertAppIdFunction::Run() {
"Could not find an eTLD for appId *", params->app_id_url)));
}
if (origin_etldp1 == app_id_etldp1) {
- return RespondNow(OneArgument(base::Value(true)));
+ return RespondNow(WithArguments(true));
}
// For legacy purposes, allow google.com origins to assert certain
// gstatic.com appIds.
@@ -151,10 +151,10 @@ CryptotokenPrivateCanOriginAssertAppIdFunction::Run() {
if (origin_etldp1 == kGoogleDotCom) {
for (const char* id : kGoogleGstaticAppIds) {
if (params->app_id_url == id)
- return RespondNow(OneArgument(base::Value(true)));
+ return RespondNow(WithArguments(true));
}
}
- return RespondNow(OneArgument(base::Value(false)));
+ return RespondNow(WithArguments(false));
}
CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction::
@@ -170,12 +170,12 @@ CryptotokenPrivateIsAppIdHashInEnterpriseContextFunction::Run() {
Profile* const profile = Profile::FromBrowserContext(browser_context());
const PrefService* const prefs = profile->GetPrefs();
- const base::Value* const permit_attestation =
- prefs->GetList(prefs::kSecurityKeyPermitAttestation);
+ const base::Value::List& permit_attestation =
+ prefs->GetValueList(prefs::kSecurityKeyPermitAttestation);
return RespondNow(ArgumentList(
cryptotoken_private::IsAppIdHashInEnterpriseContext::Results::Create(
- ContainsAppIdByHash(*permit_attestation, params->app_id_hash))));
+ ContainsAppIdByHash(permit_attestation, params->app_id_hash))));
}
CryptotokenPrivateCanAppIdGetAttestationFunction::
@@ -200,12 +200,12 @@ CryptotokenPrivateCanAppIdGetAttestationFunction::Run() {
// prompt is shown.
Profile* const profile = Profile::FromBrowserContext(browser_context());
const PrefService* const prefs = profile->GetPrefs();
- const base::Value* const permit_attestation =
- prefs->GetList(prefs::kSecurityKeyPermitAttestation);
+ const base::Value::List& permit_attestation =
+ prefs->GetValueList(prefs::kSecurityKeyPermitAttestation);
- for (const auto& entry : permit_attestation->GetListDeprecated()) {
+ for (const auto& entry : permit_attestation) {
if (entry.GetString() == app_id)
- return RespondNow(OneArgument(base::Value(true)));
+ return RespondNow(WithArguments(true));
}
// If the origin is blocked, reject attestation.
@@ -213,14 +213,14 @@ CryptotokenPrivateCanAppIdGetAttestationFunction::Run() {
device::fido_filter::Operation::MAKE_CREDENTIAL, origin.Serialize(),
/*device=*/absl::nullopt, /*id=*/absl::nullopt) ==
device::fido_filter::Action::NO_ATTESTATION) {
- return RespondNow(OneArgument(base::Value(false)));
+ return RespondNow(WithArguments(false));
}
// If prompting is disabled, allow attestation because that is the historical
// behavior.
if (!base::FeatureList::IsEnabled(
::features::kSecurityKeyAttestationPrompt)) {
- return RespondNow(OneArgument(base::Value(true)));
+ return RespondNow(WithArguments(true));
}
#if BUILDFLAG(IS_WIN)
@@ -236,7 +236,7 @@ CryptotokenPrivateCanAppIdGetAttestationFunction::Run() {
device::WinWebAuthnApi::GetDefault()->IsAvailable() &&
device::WinWebAuthnApi::GetDefault()->Version() >=
WEBAUTHN_API_VERSION_2) {
- return RespondNow(OneArgument(base::Value(true)));
+ return RespondNow(WithArguments(true));
}
#endif // BUILDFLAG(IS_WIN)
@@ -272,7 +272,7 @@ CryptotokenPrivateCanAppIdGetAttestationFunction::Run() {
}
void CryptotokenPrivateCanAppIdGetAttestationFunction::Complete(bool result) {
- Respond(OneArgument(base::Value(result)));
+ Respond(WithArguments(result));
}
CryptotokenPrivateCanMakeU2fApiRequestFunction::
@@ -294,7 +294,7 @@ CryptotokenPrivateCanMakeU2fApiRequestFunction::Run() {
if (!ash::ProfileHelper::IsRegularProfile(
Profile::FromBrowserContext(browser_context()))) {
DCHECK_EQ(params->options.tab_id, api::tabs::TAB_ID_NONE);
- return RespondNow(OneArgument(base::Value(true)));
+ return RespondNow(WithArguments(true));
}
#endif
@@ -336,7 +336,7 @@ CryptotokenPrivateCanMakeU2fApiRequestFunction::Run() {
// (crbug.com/1257293).
if (!base::FeatureList::IsEnabled(device::kU2fPermissionPrompt) ||
u2f_api_origin_trial_enabled) {
- return RespondNow(OneArgument(base::Value(true)));
+ return RespondNow(WithArguments(true));
}
permissions::PermissionRequestManager* permission_request_manager =
@@ -361,7 +361,7 @@ CryptotokenPrivateCanMakeU2fApiRequestFunction::Run() {
}
void CryptotokenPrivateCanMakeU2fApiRequestFunction::Complete(bool result) {
- Respond(OneArgument(base::Value(result)));
+ Respond(WithArguments(result));
}
ExtensionFunction::ResponseAction
@@ -378,7 +378,7 @@ CryptotokenPrivateRecordRegisterRequestFunction::Run() {
page_load_metrics::MetricsWebContentsObserver::RecordFeatureUsage(
frame, blink::mojom::WebFeature::kU2FCryptotokenRegister);
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
ExtensionFunction::ResponseAction
@@ -394,7 +394,7 @@ CryptotokenPrivateRecordSignRequestFunction::Run() {
page_load_metrics::MetricsWebContentsObserver::RecordFeatureUsage(
frame, blink::mojom::WebFeature::kU2FCryptotokenSign);
- return RespondNow(NoArguments());
+ return RespondNow(WithArguments());
}
} // namespace api
diff --git a/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc b/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc
index 96ced8a81bc..7cee4fe4494 100644
--- a/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_api_unittest.cc
@@ -151,10 +151,10 @@ TEST_F(CryptoTokenPrivateApiTest, IsAppIdHashInEnterpriseContext) {
ASSERT_TRUE(GetAppIdHashInEnterpriseContext(rp_id_hash, &result));
EXPECT_FALSE(result);
- base::Value::ListStorage permitted_list;
- permitted_list.emplace_back(example_com);
- profile()->GetPrefs()->Set(prefs::kSecurityKeyPermitAttestation,
- base::Value(permitted_list));
+ base::Value::List permitted_list;
+ permitted_list.Append(example_com);
+ profile()->GetPrefs()->SetList(prefs::kSecurityKeyPermitAttestation,
+ std::move(permitted_list));
ASSERT_TRUE(GetAppIdHashInEnterpriseContext(example_com_hash, &result));
EXPECT_TRUE(result);
@@ -350,10 +350,10 @@ TEST_F(CryptoTokenPermissionTest, AttestationPrompt) {
TEST_F(CryptoTokenPermissionTest, PolicyOverridesAttestationPrompt) {
const std::string example_com("https://example.com");
- base::Value::ListStorage permitted_list;
- permitted_list.emplace_back(example_com);
- profile()->GetPrefs()->Set(prefs::kSecurityKeyPermitAttestation,
- base::Value(permitted_list));
+ base::Value::List permitted_list;
+ permitted_list.Append(example_com);
+ profile()->GetPrefs()->SetList(prefs::kSecurityKeyPermitAttestation,
+ std::move(permitted_list));
// If an appId is configured by enterprise policy then attestation requests
// should be permitted without showing a prompt.
diff --git a/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_browsertest.cc b/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_browsertest.cc
index 003d8a4478a..6b758d1c1cd 100644
--- a/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/cryptotoken_private/cryptotoken_private_browsertest.cc
@@ -10,6 +10,7 @@
#include "base/test/with_feature_override.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/component_loader.h"
+#include "chrome/browser/policy/policy_test_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
@@ -18,6 +19,8 @@
#include "components/embedder_support/switches.h"
#include "components/permissions/permission_request_manager.h"
#include "components/permissions/test/permission_request_observer.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/policy_constants.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
@@ -25,6 +28,7 @@
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/url_loader_interceptor.h"
#include "device/fido/features.h"
+#include "extensions/browser/extension_registry.h"
#include "extensions/browser/pref_names.h"
#include "extensions/common/extension_features.h"
#include "net/dns/mock_host_resolver.h"
@@ -55,10 +59,16 @@ class CryptotokenBrowserTest : public base::test::WithFeatureOverride,
CryptotokenBrowserTest()
: base::test::WithFeatureOverride(
extensions_features::kU2FSecurityKeyAPI) {
+ // Enable the feature flag to load the cryptoken component extension at
+ // startup.
+ scoped_feature_list_.InitWithFeatures(
+ /*enabled_features=*/{extensions_features::kLoadCryptoTokenExtension},
+ /*disabled_features=*/{
#if BUILDFLAG(IS_WIN)
- // Don't dispatch requests to the native Windows API.
- scoped_feature_list_.InitAndDisableFeature(device::kWebAuthUseNativeWinApi);
+ // Don't dispatch requests to the native Windows API.
+ device::kWebAuthUseNativeWinApi
#endif
+ });
}
void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -266,9 +276,7 @@ class CryptotokenBrowserTest : public base::test::WithFeatureOverride,
return true;
}
-#if BUILDFLAG(IS_WIN)
base::test::ScopedFeatureList scoped_feature_list_;
-#endif
std::unique_ptr<content::URLLoaderInterceptor> url_loader_interceptor_;
};
@@ -405,5 +413,60 @@ IN_PROC_BROWSER_TEST_P(CryptotokenBrowserTest, SandboxedPageDoesNotSign) {
INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(CryptotokenBrowserTest);
+// Test that the `kLoadCryptoTokenExtension` feature controls loading of the
+// component extension.
+class CryptotokenLoadFeatureBrowserTest
+ : public base::test::WithFeatureOverride,
+ public InProcessBrowserTest {
+ protected:
+ CryptotokenLoadFeatureBrowserTest()
+ : base::test::WithFeatureOverride(
+ extensions_features::kLoadCryptoTokenExtension) {}
+
+ void SetUp() override {
+ ComponentLoader::EnableBackgroundExtensionsForTesting();
+ InProcessBrowserTest::SetUp();
+ }
+};
+
+IN_PROC_BROWSER_TEST_P(CryptotokenLoadFeatureBrowserTest, IsLoaded) {
+ EXPECT_EQ(ExtensionRegistry::Get(browser()->profile())
+ ->GenerateInstalledExtensionsSet()
+ ->GetByID(kCryptoTokenExtensionId) != nullptr,
+ IsParamFeatureEnabled());
+}
+
+INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE(CryptotokenLoadFeatureBrowserTest);
+
+// Test that `extensions_prefs::kLoadCryptoTokenExtension` also controls loading
+// of the component extension.
+class CryptotokenLoadPolicyBrowserTest : public policy::PolicyTest {
+ protected:
+ void SetUpInProcessBrowserTestFixture() override {
+ PolicyTest::SetUpInProcessBrowserTestFixture();
+
+ policy::PolicyMap policies;
+ policies.Set(policy::key::kLoadCryptoTokenExtension,
+ policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
+ policy::POLICY_SOURCE_CLOUD, base::Value(true), nullptr);
+ UpdateProviderPolicy(policies);
+ }
+
+ void SetUp() override {
+ ComponentLoader::EnableBackgroundExtensionsForTesting();
+ policy::PolicyTest::SetUp();
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(CryptotokenLoadPolicyBrowserTest, IsLoaded) {
+ // The policy controls the extension even if the feature is disabled.
+ EXPECT_FALSE(base::FeatureList::IsEnabled(
+ extensions_features::kLoadCryptoTokenExtension));
+ EXPECT_NE(ExtensionRegistry::Get(browser()->profile())
+ ->GenerateInstalledExtensionsSet()
+ ->GetByID(kCryptoTokenExtensionId),
+ nullptr);
+}
+
} // namespace
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc b/chromium/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc
index dcb4ff0918a..1553d8ebc41 100644
--- a/chromium/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/dashboard_private/dashboard_private_api.cc
@@ -175,8 +175,7 @@ ExtensionFunction::ResponseValue
DashboardPrivateShowPermissionPromptForDelegatedInstallFunction::BuildResponse(
api::dashboard_private::Result result, const std::string& error) {
// The web store expects an empty string on success.
- std::vector<base::Value> args =
- ShowPermissionPromptForDelegatedInstall::Results::Create(result);
+ auto args = ShowPermissionPromptForDelegatedInstall::Results::Create(result);
if (result == api::dashboard_private::RESULT_EMPTY_STRING)
return ArgumentList(std::move(args));
return ErrorWithArguments(std::move(args), error);
diff --git a/chromium/chrome/browser/extensions/api/debugger/debugger_api.cc b/chromium/chrome/browser/extensions/api/debugger/debugger_api.cc
index 4b303f27232..a4ece96a9c7 100644
--- a/chromium/chrome/browser/extensions/api/debugger/debugger_api.cc
+++ b/chromium/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -824,6 +824,11 @@ ExtensionFunction::ResponseAction DebuggerGetTargetsFunction::Run() {
base::Value::List result;
Profile* profile = Profile::FromBrowserContext(browser_context());
for (auto& host : list) {
+ // TODO(crbug.com/1348385): hide all Tab targets for now to avoid
+ // compatibility problems. Consider exposing them later when they're fully
+ // supported, and compatibility considerations are better understood.
+ if (host->GetType() == DevToolsAgentHost::kTypeTab)
+ continue;
if (!ExtensionMayAttachToTargetProfile(
profile, include_incognito_information(), *host)) {
continue;
@@ -831,7 +836,7 @@ ExtensionFunction::ResponseAction DebuggerGetTargetsFunction::Run() {
result.Append(SerializeTarget(host));
}
- return RespondNow(OneArgument(base::Value(std::move(result))));
+ return RespondNow(WithArguments(std::move(result)));
}
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/debugger/debugger_apitest.cc b/chromium/chrome/browser/extensions/api/debugger/debugger_apitest.cc
index b629239fdf4..a568046deba 100644
--- a/chromium/chrome/browser/extensions/api/debugger/debugger_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/debugger/debugger_apitest.cc
@@ -156,7 +156,9 @@ testing::AssertionResult DebuggerApiTest::RunAttachFunction(
if (id == tab_id) {
const base::DictionaryValue& target_dict =
base::Value::AsDictionaryValue(target_value);
- EXPECT_TRUE(target_dict.GetString("id", &debugger_target_id));
+ const std::string* id_str = target_dict.GetDict().FindString("id");
+ EXPECT_TRUE(id_str);
+ debugger_target_id = *id_str;
break;
}
}
@@ -263,7 +265,8 @@ class TestInterstitialPage
void OnInterstitialClosing() override {}
protected:
- void PopulateInterstitialStrings(base::Value* load_time_data) override {}
+ void PopulateInterstitialStrings(base::Value::Dict& load_time_data) override {
+ }
std::unique_ptr<security_interstitials::MetricsHelper>
CreateTestMetricsHelper(content::WebContents* web_contents) {
@@ -719,6 +722,17 @@ IN_PROC_BROWSER_TEST_F(DebuggerExtensionApiTest, NavigateToForbiddenUrl) {
<< message_;
}
+IN_PROC_BROWSER_TEST_F(DebuggerExtensionApiTest, NavigateToUntrustedWebUIUrl) {
+ ASSERT_TRUE(RunExtensionTest("debugger_navigate_to_untrusted_webui_url"))
+ << message_;
+}
+
+// Tests that Target.createTarget to WebUI origins are blocked.
+IN_PROC_BROWSER_TEST_F(DebuggerExtensionApiTest, CreateTargetToUntrustedWebUI) {
+ ASSERT_TRUE(RunExtensionTest("debugger_create_target_to_untrusted_webui"))
+ << message_;
+}
+
IN_PROC_BROWSER_TEST_F(DebuggerExtensionApiTest, IsDeveloperModeTrueHistogram) {
profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);
base::HistogramTester histograms;
diff --git a/chromium/chrome/browser/extensions/api/declarative/declarative_apitest.cc b/chromium/chrome/browser/extensions/api/declarative/declarative_apitest.cc
index e8206eb6e19..139c7b64c51 100644
--- a/chromium/chrome/browser/extensions/api/declarative/declarative_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/declarative/declarative_apitest.cc
@@ -121,55 +121,6 @@ class DeclarativeApiTest : public ExtensionApiTest {
}
};
-// Copied from origin_policy_browsertest.cc.
-const base::FilePath::CharType kDataRoot[] =
- FILE_PATH_LITERAL("chrome/test/data/origin_policy_browsertest");
-
-class DeclarativeApiTestWithOriginPolicy : public DeclarativeApiTest {
- protected:
- std::u16string NavigateToAndReturnTitle(const char* url) {
- EXPECT_TRUE(server());
- EXPECT_TRUE(
- ui_test_utils::NavigateToURL(browser(), GURL(server()->GetURL(url))));
- std::u16string title;
- ui_test_utils::GetCurrentTabTitle(browser(), &title);
- return title;
- }
-
- private:
- void SetUpInProcessBrowserTestFixture() override {
- server_ = std::make_unique<net::test_server::EmbeddedTestServer>(
- net::test_server::EmbeddedTestServer::TYPE_HTTPS);
- server_->AddDefaultHandlers(base::FilePath(kDataRoot));
- feature_list_.InitAndEnableFeature(features::kOriginPolicy);
- EXPECT_TRUE(server()->Start());
- DeclarativeApiTest::SetUpInProcessBrowserTestFixture();
- }
-
- void TearDownInProcessBrowserTestFixture() override { server_.reset(); }
-
- net::test_server::EmbeddedTestServer* server() { return server_.get(); }
-
- std::unique_ptr<net::test_server::EmbeddedTestServer> server_;
- base::test::ScopedFeatureList feature_list_;
-};
-
-// Regression test for crbug.com/1047275.
-IN_PROC_BROWSER_TEST_F(DeclarativeApiTestWithOriginPolicy,
- OriginPolicyEnabled) {
- // Navigate to a page with an origin policy. It should load correctly.
- EXPECT_EQ(u"Page With Policy",
- NavigateToAndReturnTitle("/page-with-policy.html"));
-
- // Load an extension that has the |declarativeWebRequest| permission.
- ASSERT_TRUE(RunExtensionTest("declarative/api")) << message_;
-
- // Future navigations to the page with the origin policy should still work,
- // and not throw an interstitial.
- EXPECT_EQ(u"Page With Policy",
- NavigateToAndReturnTitle("/page-with-policy.html"));
-}
-
IN_PROC_BROWSER_TEST_F(DeclarativeApiTest, DeclarativeApi) {
ASSERT_TRUE(RunExtensionTest("declarative/api")) << message_;
diff --git a/chromium/chrome/browser/extensions/api/declarative_content/content_condition.cc b/chromium/chrome/browser/extensions/api/declarative_content/content_condition.cc
index d85a0981653..121c39a0fee 100644
--- a/chromium/chrome/browser/extensions/api/declarative_content/content_condition.cc
+++ b/chromium/chrome/browser/extensions/api/declarative_content/content_condition.cc
@@ -38,29 +38,29 @@ std::unique_ptr<ContentCondition> CreateContentCondition(
const std::map<std::string, ContentPredicateFactory*>& predicate_factories,
const base::Value& api_condition,
std::string* error) {
- const base::DictionaryValue* api_condition_dict = nullptr;
- if (!api_condition.GetAsDictionary(&api_condition_dict)) {
+ if (!api_condition.is_dict()) {
*error = kExpectedDictionary;
return nullptr;
}
+ const base::Value::Dict& api_condition_dict = api_condition.GetDict();
+
// Verify that we are dealing with a Condition whose type we understand.
- std::string instance_type;
- if (!api_condition_dict->GetString(
- declarative_content_constants::kInstanceType, &instance_type)) {
+ const std::string* instance_type = api_condition_dict.FindString(
+ declarative_content_constants::kInstanceType);
+ if (!instance_type) {
*error = kConditionWithoutInstanceType;
return nullptr;
}
- if (instance_type != declarative_content_constants::kPageStateMatcherType) {
+ if (*instance_type != declarative_content_constants::kPageStateMatcherType) {
*error = kExpectedOtherConditionType;
return nullptr;
}
std::vector<std::unique_ptr<const ContentPredicate>> predicates;
- for (base::DictionaryValue::Iterator iter(*api_condition_dict);
- !iter.IsAtEnd(); iter.Advance()) {
- const std::string& predicate_name = iter.key();
- const base::Value& predicate_value = iter.value();
+ for (const auto iter : api_condition_dict) {
+ const std::string& predicate_name = iter.first;
+ const base::Value& predicate_value = iter.second;
if (predicate_name == declarative_content_constants::kInstanceType)
continue;
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 ed5bda388af..ca28e3f93f7 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
@@ -8,32 +8,28 @@
#include "components/version_info/version_info.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/browser_test.h"
+#include "content/public/test/prerender_test_util.h"
#include "extensions/browser/api/declarative/rules_registry.h"
#include "extensions/browser/api/declarative/rules_registry_service.h"
#include "extensions/browser/extension_action_manager.h"
#include "extensions/common/features/feature_channel.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/test_extension_dir.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
#include "ui/gfx/image/image.h"
namespace extensions {
namespace {
-const char kDeclarativeContentManifest[] =
- "{\n"
- " \"name\": \"Declarative Content apitest\",\n"
- " \"version\": \"0.1\",\n"
- " \"manifest_version\": 2,\n"
- " \"description\": \n"
- " \"end-to-end browser test for the declarative Content API\",\n"
- " \"background\": {\n"
- " \"scripts\": [\"background.js\"]\n"
- " },\n"
- " \"page_action\": {},\n"
- " \"permissions\": [\n"
- " \"declarativeContent\"\n"
- " ]\n"
- "}\n";
+const char kDeclarativeContentManifest[] = R"({
+ "name": "Declarative Content apitest",
+ "version": "0.1",
+ "manifest_version": 2,
+ "description": "end-to-end browser test for the declarative Content API",
+ "background": {"scripts": ["background.js"]},
+ "page_action": {},
+ "permissions": ["declarativeContent"]
+})";
constexpr char kOneByOneImageData[] =
"GAAAAAAAAAAQAAAAAAAAADAAAAAAAAAAKAAAAAAAAAACAAAAAQAAAAEAAAAAAAAAAAAAAAAAAA"
@@ -44,88 +40,159 @@ class SetIconAPITest : public ExtensionApiTest {
SetIconAPITest()
// Set the channel to "trunk" since declarativeContent is restricted
// to trunk.
- : current_channel_(version_info::Channel::UNKNOWN) {
- }
+ : current_channel_(version_info::Channel::UNKNOWN) {}
~SetIconAPITest() override {}
+ protected:
+ const Extension* LoadTestExtension() {
+ ext_dir_.WriteManifest(kDeclarativeContentManifest);
+ ext_dir_.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
+ var declarative = chrome.declarative;
+
+ var PageStateMatcher = chrome.declarativeContent.PageStateMatcher;
+ var SetIcon = chrome.declarativeContent.SetIcon;
+
+ var canvas = document.createElement("canvas");
+ var ctx = canvas.getContext("2d");
+ var imageData = ctx.createImageData(1, 1);
+
+ var rule0 = {
+ conditions: [new PageStateMatcher({pageUrl: {queryContains: "show"}})],
+ actions: [new SetIcon({"imageData": imageData})]
+ };
+ var testEvent = chrome.declarativeContent.onPageChanged;
+
+ testEvent.removeRules(undefined, function() {
+ testEvent.addRules([rule0], function() {
+ chrome.test.sendMessage("ready", function(reply) {});
+ });
+ });
+)");
+ ExtensionTestMessageListener ready("ready");
+ const Extension* extension = LoadExtension(ext_dir_.UnpackedPath());
+ if (!extension)
+ return nullptr;
+
+ // Wait for declarative rules to be set up.
+ profile()->GetDefaultStoragePartition()->FlushNetworkInterfaceForTesting();
+ EXPECT_TRUE(GetExtensionAction(*extension));
+
+ EXPECT_TRUE(ready.WaitUntilSatisfied());
+
+ return extension;
+ }
+
+ const ExtensionAction* GetExtensionAction(const Extension& extension) {
+ return ExtensionActionManager::Get(profile())->GetExtensionAction(
+ extension);
+ }
+
+ content::WebContents* GetActiveWebContents() {
+ return browser()->tab_strip_model()->GetWebContentsAt(0);
+ }
+
+ private:
extensions::ScopedCurrentChannel current_channel_;
TestExtensionDir ext_dir_;
};
IN_PROC_BROWSER_TEST_F(SetIconAPITest, Overview) {
- ext_dir_.WriteManifest(kDeclarativeContentManifest);
- ext_dir_.WriteFile(
- FILE_PATH_LITERAL("background.js"),
- "var declarative = chrome.declarative;\n"
- "\n"
- "var PageStateMatcher = chrome.declarativeContent.PageStateMatcher;\n"
- "var SetIcon = chrome.declarativeContent.SetIcon;\n"
- "\n"
- "var canvas = document.createElement(\'canvas\');\n"
- "var ctx = canvas.getContext(\"2d\");"
- "var imageData = ctx.createImageData(1, 1);\n"
- "\n"
- "var rule0 = {\n"
- " conditions: [new PageStateMatcher({\n"
- " pageUrl: {hostPrefix: \"test1\"}})],\n"
- " actions: [new SetIcon({\"imageData\": imageData})]\n"
- "}\n"
- "\n"
- "var testEvent = chrome.declarativeContent.onPageChanged;\n"
- "\n"
- "testEvent.removeRules(undefined, function() {\n"
- " testEvent.addRules([rule0], function() {\n"
- " chrome.test.sendMessage(\"ready\", function(reply) {\n"
- " })\n"
- " });\n"
- "});\n");
- ExtensionTestMessageListener ready("ready");
- const Extension* extension = LoadExtension(ext_dir_.UnpackedPath());
+ const Extension* extension = LoadTestExtension();
ASSERT_TRUE(extension);
- // Wait for declarative rules to be set up.
- profile()->GetDefaultStoragePartition()->FlushNetworkInterfaceForTesting();
- const ExtensionAction* action =
- ExtensionActionManager::Get(browser()->profile())
- ->GetExtensionAction(*extension);
+
+ content::WebContents* const tab = GetActiveWebContents();
+ const int tab_id = ExtensionTabUtil::GetTabId(tab);
+
+ // There should be no declarative icon until we navigate to a matched page.
+ const ExtensionAction* action = GetExtensionAction(*extension);
ASSERT_TRUE(action);
- ASSERT_TRUE(ready.WaitUntilSatisfied());
-
- // Regression test for crbug.com/1231027.
- {
- scoped_refptr<RulesRegistry> rules_registry =
- extensions::RulesRegistryService::Get(browser()->profile())
- ->GetRulesRegistry(RulesRegistryService::kDefaultRulesRegistryID,
- "declarativeContent.onPageChanged");
- ASSERT_TRUE(rules_registry);
-
- std::vector<const api::events::Rule*> rules;
- rules_registry->GetAllRules(extension->id(), &rules);
- ASSERT_EQ(1u, rules.size());
- ASSERT_EQ(rules[0]->actions.size(), 1u);
-
- base::Value& action_value = *rules[0]->actions[0];
- base::Value* action_instance_type = action_value.FindPath("instanceType");
- ASSERT_TRUE(action_instance_type);
- EXPECT_EQ("declarativeContent.SetIcon", action_instance_type->GetString());
-
- base::Value* image_data_value = action_value.FindPath({"imageData", "1"});
- ASSERT_TRUE(image_data_value);
- EXPECT_EQ(kOneByOneImageData, image_data_value->GetString());
+ EXPECT_TRUE(action->GetDeclarativeIcon(tab_id).IsEmpty());
+ EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://example.com/?show")));
+ EXPECT_FALSE(action->GetDeclarativeIcon(tab_id).IsEmpty());
+
+ // Navigating to an unmatched page should reset the icon.
+ EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://example.com/?hide")));
+ EXPECT_TRUE(action->GetDeclarativeIcon(tab_id).IsEmpty());
+}
+
+// Regression test for crbug.com/1231027.
+IN_PROC_BROWSER_TEST_F(SetIconAPITest, Parameter) {
+ const Extension* extension = LoadTestExtension();
+ ASSERT_TRUE(extension);
+
+ scoped_refptr<RulesRegistry> rules_registry =
+ extensions::RulesRegistryService::Get(browser()->profile())
+ ->GetRulesRegistry(RulesRegistryService::kDefaultRulesRegistryID,
+ "declarativeContent.onPageChanged");
+ ASSERT_TRUE(rules_registry);
+
+ std::vector<const api::events::Rule*> rules;
+ rules_registry->GetAllRules(extension->id(), &rules);
+ ASSERT_EQ(1u, rules.size());
+ ASSERT_EQ(rules[0]->actions.size(), 1u);
+
+ base::Value& action_value = *rules[0]->actions[0];
+ base::Value* action_instance_type = action_value.FindPath("instanceType");
+ ASSERT_TRUE(action_instance_type);
+ EXPECT_EQ("declarativeContent.SetIcon", action_instance_type->GetString());
+
+ base::Value* image_data_value = action_value.FindPath({"imageData", "1"});
+ ASSERT_TRUE(image_data_value);
+ EXPECT_EQ(kOneByOneImageData, image_data_value->GetString());
+}
+
+class SetIconAPIPrerenderingTest : public SetIconAPITest {
+ public:
+ SetIconAPIPrerenderingTest()
+ : prerender_helper_(base::BindRepeating(
+ &SetIconAPIPrerenderingTest::GetActiveWebContents,
+ base::Unretained(this))) {}
+ ~SetIconAPIPrerenderingTest() override = default;
+
+ protected:
+ int Prerender(const GURL& url) { return prerender_helper_.AddPrerender(url); }
+ void Activate(const GURL& url) { prerender_helper_.NavigatePrimaryPage(url); }
+
+ private:
+ void SetUp() override {
+ prerender_helper_.SetUp(embedded_test_server());
+ ExtensionApiTest::SetUp();
}
- content::WebContents* const tab =
- browser()->tab_strip_model()->GetWebContentsAt(0);
+ content::test::PrerenderTestHelper prerender_helper_;
+};
+
+IN_PROC_BROWSER_TEST_F(SetIconAPIPrerenderingTest, Overview) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ const Extension* extension = LoadTestExtension();
+ ASSERT_TRUE(extension);
+
+ content::WebContents* const tab = GetActiveWebContents();
const int tab_id = ExtensionTabUtil::GetTabId(tab);
// There should be no declarative icon until we navigate to a matched page.
+ const ExtensionAction* action = GetExtensionAction(*extension);
+ ASSERT_TRUE(action);
+
EXPECT_TRUE(action->GetDeclarativeIcon(tab_id).IsEmpty());
- EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test1/")));
+
+ const GURL kInitialUrl = embedded_test_server()->GetURL("/empty.html?show");
+ EXPECT_TRUE(NavigateInRenderer(tab, kInitialUrl));
EXPECT_FALSE(action->GetDeclarativeIcon(tab_id).IsEmpty());
- // Navigating to an unmatched page should reset the icon.
- EXPECT_FALSE(NavigateInRenderer(tab, GURL("http://test2/")));
+ // Prerendering an unmatched page should not reset the icon.
+ const GURL kPrerenderingUrl =
+ embedded_test_server()->GetURL("/empty.html?hide");
+ int host_id = Prerender(kPrerenderingUrl);
+ ASSERT_NE(content::RenderFrameHost::kNoFrameTreeNodeId, host_id);
+ EXPECT_FALSE(action->GetDeclarativeIcon(tab_id).IsEmpty());
+
+ // Activating the unmatched page should reset the icon.
+ Activate(kPrerenderingUrl);
EXPECT_TRUE(action->GetDeclarativeIcon(tab_id).IsEmpty());
+ EXPECT_EQ(tab->GetLastCommittedURL(), kPrerenderingUrl);
}
+
} // namespace
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc b/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc
index e7e52d8a57f..214ffd7f16e 100644
--- a/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_apitest.cc
@@ -12,7 +12,9 @@
#include "components/version_info/version_info.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
+#include "content/public/test/prerender_test_util.h"
#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
#include "third_party/blink/public/common/features.h"
namespace {
@@ -151,4 +153,29 @@ INSTANTIATE_TEST_SUITE_P(DeclarativeNetRequestApiFencedFrameTest,
DeclarativeNetRequestApiFencedFrameTest,
testing::Bool());
+class DeclarativeNetRequestApiPrerenderingTest
+ : public DeclarativeNetRequestLazyApiTest {
+ public:
+ DeclarativeNetRequestApiPrerenderingTest() = default;
+ ~DeclarativeNetRequestApiPrerenderingTest() override = default;
+
+ private:
+ content::test::ScopedPrerenderFeatureList scoped_feature_list_;
+};
+
+INSTANTIATE_TEST_SUITE_P(PersistentBackground,
+ DeclarativeNetRequestApiPrerenderingTest,
+ ::testing::Values(ContextType::kPersistentBackground));
+INSTANTIATE_TEST_SUITE_P(EventPage,
+ DeclarativeNetRequestApiPrerenderingTest,
+ ::testing::Values(ContextType::kEventPage));
+INSTANTIATE_TEST_SUITE_P(ServiceWorker,
+ DeclarativeNetRequestApiPrerenderingTest,
+ ::testing::Values(ContextType::kServiceWorker));
+
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestApiPrerenderingTest,
+ PrerenderedPageInterception) {
+ ASSERT_TRUE(RunExtensionTest("prerendering")) << message_;
+}
+
} // namespace
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 beb8fa58755..4a50258cbb2 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
@@ -4904,8 +4904,10 @@ class DeclarativeNetRequestAllowAllRequestsBrowserTest
};
};
+// TODO(crbug.com/1345215): Re-enable this test. It was disabled because of
+// flakiness.
IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestAllowAllRequestsBrowserTest,
- Test1) {
+ DISABLED_Test1) {
std::vector<RuleData> rule_data = {
{1, 4, "allowAllRequests", "page_with_two_frames\\.html", true,
std::vector<std::string>({"main_frame"})},
@@ -4967,8 +4969,10 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestAllowAllRequestsBrowserTest,
{requests[1], requests[2], requests[3], requests[4], requests[5]});
}
+// TODO(crbug.com/1345215): Re-enable this test. It was disabled because of
+// flakiness.
IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestAllowAllRequestsBrowserTest,
- Test4) {
+ DISABLED_Test4) {
std::vector<RuleData> rule_data = {
{1, 6, "allowAllRequests", "page_with_two_frames\\.html", true,
std::vector<std::string>({"main_frame"})},
@@ -5018,8 +5022,14 @@ IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestAllowAllRequestsBrowserTest,
{}, true);
}
+// TODO(crbug.com/1344372): Re-enable this test on MAC
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_TestPostNavigationNotMatched DISABLED_TestPostNavigationNotMatched
+#else
+#define MAYBE_TestPostNavigationNotMatched TestPostNavigationNotMatched
+#endif
IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestAllowAllRequestsBrowserTest,
- TestPostNavigationNotMatched) {
+ MAYBE_TestPostNavigationNotMatched) {
std::vector<RuleData> rule_data = {
{1, 6, "allowAllRequests", "page_with_two_frames\\.html", true,
std::vector<std::string>({"main_frame"}),
@@ -5504,6 +5514,93 @@ class DeclarativeNetRequestSubresourceWebBundlesBrowserTest
base::test::ScopedFeatureList feature_list_;
};
+// Test for https://crbug.com/1355162.
+// Ensure the following happens when DeclarativeNetRequest API blocks a
+// WebBundle:
+// - A request for the WebBundle fails.
+// - A subresource request associated with the bundle fail.
+// - A window.load is fired. In other words, any request shouldn't remain
+// pending forever.
+IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestSubresourceWebBundlesBrowserTest,
+ WebBundleRequestCanceled) {
+ // Add a rule to block the bundle.
+ TestRule rule = CreateGenericRule();
+ std::vector<TestRule> rules;
+ rule.id = kMinValidID;
+ rule.condition->url_filter = "web_bundle.wbn|";
+ rule.priority = 1;
+ rules.push_back(rule);
+ ASSERT_NO_FATAL_FAILURE(LoadExtensionWithRules(rules));
+
+ const char kPageHtml[] = R"(
+ <title>Loaded</title>
+ <body>
+ <script>
+ (async () => {
+ const window_load = new Promise((resolve) => {
+ window.addEventListener("load", () => {
+ resolve();
+ });
+ });
+
+ const wbn_url =
+ new URL('./web_bundle.wbn', location.href).toString();
+ const pass_js_url = new URL('./pass.js', location.href).toString();
+ const script_web_bundle = document.createElement('script');
+ script_web_bundle.type = 'webbundle';
+ script_web_bundle.textContent = JSON.stringify({
+ source: wbn_url,
+ resources: [pass_js_url]
+ });
+
+ const web_bundle_error = new Promise((resolve) => {
+ script_web_bundle.addEventListener("error", () => {
+ resolve();
+ });
+ });
+
+ document.body.appendChild(script_web_bundle);
+
+ const script_js = document.createElement('script');
+ script_js.src = pass_js_url;
+
+ const script_js_error = new Promise((resolve) => {
+ script_js.addEventListener("error", () => {
+ resolve();
+ });
+ });
+
+ document.body.appendChild(script_js);
+
+ await Promise.all([window_load, web_bundle_error, script_js_error]);
+ document.title = "success";
+ })();
+ </script>
+ </body>
+ )";
+
+ std::string web_bundle;
+ RegisterWebBundleRequestHandler("/web_bundle.wbn", &web_bundle);
+ RegisterRequestHandler("/test.html", "text/html", kPageHtml);
+ ASSERT_TRUE(embedded_test_server()->Start());
+
+ // Create a web bundle, which can be empty in this test.
+ web_package::WebBundleBuilder builder;
+ std::vector<uint8_t> bundle = builder.CreateBundle();
+ web_bundle = std::string(bundle.begin(), bundle.end());
+
+ GURL page_url = embedded_test_server()->GetURL("/test.html");
+ content::WebContents* web_contents =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), page_url));
+ EXPECT_EQ(page_url, web_contents->GetLastCommittedURL());
+
+ std::u16string expected_title = u"success";
+ content::TitleWatcher title_watcher(web_contents, expected_title);
+
+ EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+}
+
// Ensure DeclarativeNetRequest API can block the requests for the subresources
// inside the web bundle.
IN_PROC_BROWSER_TEST_P(DeclarativeNetRequestSubresourceWebBundlesBrowserTest,
diff --git a/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_unittest.cc b/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_unittest.cc
index 75be9f5211e..2b3fb999eb8 100644
--- a/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_unittest.cc
@@ -2150,6 +2150,68 @@ TEST_P(MultipleRulesetsTest, UpdateAndGetEnabledRulesets_RuleCountExceeded) {
CheckExtensionAllocationInPrefs(extension()->id(), 200);
}
+TEST_P(MultipleRulesetsTest,
+ UpdateAndGetEnabledRulesets_KeepEnabledStaticRulesetsAfterReload) {
+ AddRuleset(CreateRuleset(kId1, 90, 0, false));
+ AddRuleset(CreateRuleset(kId2, 60, 0, false));
+ AddRuleset(CreateRuleset(kId3, 150, 0, false));
+
+ RulesetManagerObserver ruleset_waiter(manager());
+
+ DeclarativeNetRequestUnittest::LoadAndExpectSuccess(
+ 300, 0, false /* expect_rulesets_indexed */);
+
+ ruleset_waiter.WaitForExtensionsWithRulesetsCount(0);
+
+ RunUpdateEnabledRulesetsFunction(*extension(), {}, {kId2, kId3},
+ absl::nullopt /* expected_error */);
+ VerifyPublicRulesetIDs(*extension(), {kId2, kId3});
+ VerifyGetEnabledRulesetsFunction(*extension(), {kId2, kId3});
+
+ // Ensure the set of enabled rulesets persists across extension reloads.
+ // Regression test for crbug.com/1346185.
+ const ExtensionId extension_id = extension()->id();
+ service()->DisableExtension(extension_id,
+ disable_reason::DISABLE_USER_ACTION);
+
+ ruleset_waiter.WaitForExtensionsWithRulesetsCount(0);
+
+ service()->EnableExtension(extension_id);
+
+ ruleset_waiter.WaitForExtensionsWithRulesetsCount(1);
+
+ const Extension* extension =
+ registry()->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
+ ASSERT_TRUE(extension);
+ VerifyPublicRulesetIDs(*extension, {kId2, kId3});
+ VerifyGetEnabledRulesetsFunction(*extension, {kId2, kId3});
+}
+
+// Tests attempting to disable rulesets when there are no rulesets active.
+// Regression test for https://crbug.com/1354385.
+TEST_P(MultipleRulesetsTest,
+ UpdateAndGetEnabledRulesets_DisableRulesetsWhenEmptyEnabledRulesets) {
+ AddRuleset(CreateRuleset(kId1, 90, 0, false));
+ AddRuleset(CreateRuleset(kId2, 60, 0, false));
+ AddRuleset(CreateRuleset(kId3, 150, 0, false));
+
+ RulesetManagerObserver ruleset_waiter(manager());
+
+ DeclarativeNetRequestUnittest::LoadAndExpectSuccess(
+ 300, 0, false /* expect_rulesets_indexed */);
+
+ ruleset_waiter.WaitForExtensionsWithRulesetsCount(0);
+
+ // Even though rulesets kId2 and kId3 are already disabled, the service
+ // can't know about that right away because there could be pending calls to
+ // complete. This means the service will still (appropriately) try and
+ // disable these rulesets.
+ RunUpdateEnabledRulesetsFunction(*extension(), {kId2, kId3}, {},
+ absl::nullopt /* expected_error */);
+ ASSERT_FALSE(manager()->GetMatcherForExtension(extension()->id()));
+ VerifyGetEnabledRulesetsFunction(*extension(), {});
+}
+
// Test that getAvailableStaticRuleCount returns the correct number of rules an
// extension can still enable.
TEST_P(MultipleRulesetsTest, GetAvailableStaticRuleCount) {
diff --git a/chromium/chrome/browser/extensions/api/desktop_capture/OWNERS b/chromium/chrome/browser/extensions/api/desktop_capture/OWNERS
index 39013c0907e..da4c2853d50 100644
--- a/chromium/chrome/browser/extensions/api/desktop_capture/OWNERS
+++ b/chromium/chrome/browser/extensions/api/desktop_capture/OWNERS
@@ -1,4 +1,3 @@
-# Please send the changes to braveyao@chromium.org first.
sergeyu@chromium.org
wez@chromium.org
-braveyao@chromium.org
+eladalon@chromium.org
diff --git a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
index 588e510e510..264398347f5 100644
--- a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
+++ b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
@@ -102,8 +102,13 @@ DesktopCaptureChooseDesktopMediaFunction::Run() {
if (!target_render_frame_host)
return RespondNow(Error(kTargetTabRequiredFromServiceWorker));
- return Execute(params->sources, target_render_frame_host, origin,
- target_name);
+ const bool exclude_system_audio =
+ params->options &&
+ params->options->system_audio ==
+ api::desktop_capture::SYSTEM_AUDIO_PREFERENCE_ENUM_EXCLUDE;
+
+ return Execute(params->sources, exclude_system_audio,
+ target_render_frame_host, origin, target_name);
}
std::string DesktopCaptureChooseDesktopMediaFunction::GetExtensionTargetName()
diff --git a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc
index 00a662a78ea..d91524ae6df 100644
--- a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h"
@@ -275,7 +276,33 @@ IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, ServiceWorkerMustSpecifyTab) {
ASSERT_TRUE(RunExtensionTest(test_dir.UnpackedPath(), {}, {})) << message_;
}
-IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, FromServiceWorker) {
+class DesktopCaptureApiTestWithSystemAudioValue
+ : public DesktopCaptureApiTest,
+ public testing::WithParamInterface<std::string> {
+ public:
+ DesktopCaptureApiTestWithSystemAudioValue()
+ : system_audio_preference_(GetParam()) {
+ DesktopCaptureChooseDesktopMediaFunction::SetPickerFactoryForTests(
+ &picker_factory_);
+ }
+
+ ~DesktopCaptureApiTestWithSystemAudioValue() override = default;
+
+ protected:
+ const std::string system_audio_preference_;
+};
+
+// |options| itself is optional, as is its member (systemAudio), and so will
+// future members be (e.g. selfBrowserSurface).
+INSTANTIATE_TEST_SUITE_P(_,
+ DesktopCaptureApiTestWithSystemAudioValue,
+ ::testing::Values("",
+ "{},",
+ "{systemAudio: \"include\"},",
+ "{systemAudio: \"exclude\"},"));
+
+IN_PROC_BROWSER_TEST_P(DesktopCaptureApiTestWithSystemAudioValue,
+ FromServiceWorker) {
static constexpr char kManifest[] =
R"({
"name": "Desktop Capture",
@@ -285,24 +312,26 @@ IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, FromServiceWorker) {
"permissions": ["desktopCapture", "tabs"]
})";
- static constexpr char kWorker[] =
+ const std::string worker = base::StringPrintf(
R"(chrome.test.runTests([
function tabIdSpecified() {
chrome.tabs.query({}, function(tabs) {
chrome.test.assertTrue(tabs.length == 1);
chrome.desktopCapture.chooseDesktopMedia(
["tab"], tabs[0],
+ %s
function(id) {
chrome.test.assertEq("string", typeof id);
chrome.test.assertTrue(id != "");
chrome.test.succeed();
});
});
- }]))";
+ }]))",
+ system_audio_preference_.c_str());
TestExtensionDir test_dir;
test_dir.WriteManifest(kManifest);
- test_dir.WriteFile(FILE_PATH_LITERAL("worker.js"), kWorker);
+ test_dir.WriteFile(FILE_PATH_LITERAL("worker.js"), worker);
// Open a tab to capture.
embedded_test_server()->ServeFilesFromDirectory(GetTestResourcesParentDir());
diff --git a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
index b68d6ca99fe..2a713ccf1d9 100644
--- a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
+++ b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc
@@ -81,6 +81,7 @@ void DesktopCaptureChooseDesktopMediaFunctionBase::Cancel() {
ExtensionFunction::ResponseAction
DesktopCaptureChooseDesktopMediaFunctionBase::Execute(
const std::vector<api::desktop_capture::DesktopCaptureSourceType>& sources,
+ bool exclude_system_audio,
content::RenderFrameHost* render_frame_host,
const GURL& origin,
const std::u16string target_name) {
@@ -157,6 +158,7 @@ DesktopCaptureChooseDesktopMediaFunctionBase::Execute(
picker_params.app_name = base::UTF8ToUTF16(GetCallerDisplayName());
picker_params.target_name = target_name;
picker_params.request_audio = request_audio;
+ picker_params.exclude_system_audio = exclude_system_audio;
picker_controller_ =
std::make_unique<DesktopMediaPickerController>(g_picker_factory);
picker_params.restricted_by_policy =
diff --git a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.h b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.h
index b1f067d7119..f97c711188e 100644
--- a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.h
+++ b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.h
@@ -36,13 +36,18 @@ class DesktopCaptureChooseDesktopMediaFunctionBase : public ExtensionFunction {
static const char kTargetNotFoundError[];
- // |web_contents| is the WebContents for which the stream is created, and will
- // also be used to determine where to show the picker's UI.
+ // |exclude_system_audio| is piped from the original call. It is a constraint
+ // that needs to be applied before the picker is shown to the user, as it
+ // affects the picker. It is therefore provided to the extension function
+ // rather than to getUserMedia(), as is the case for other constraints.
+ //
// |origin| is the origin for which the stream is created.
+ //
// |target_name| is the display name of the stream target.
ResponseAction Execute(
const std::vector<api::desktop_capture::DesktopCaptureSourceType>&
sources,
+ bool exclude_system_audio,
content::RenderFrameHost* render_frame_host,
const GURL& origin,
const std::u16string target_name);
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 3f8450294a8..4003cca955f 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
@@ -100,6 +100,7 @@
#include "extensions/common/manifest_url_handlers.h"
#include "extensions/common/permissions/permissions_data.h"
#include "net/base/filename_util.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "storage/browser/blob/shareable_file_reference.h"
#include "storage/browser/file_system/external_mount_points.h"
#include "storage/browser/file_system/file_system_context.h"
@@ -274,6 +275,109 @@ developer::UserSiteSettings ConvertToUserSiteSettings(
return user_site_settings;
}
+std::string GetETldPlusOne(const GURL& site) {
+ DCHECK(site.is_valid());
+ std::string etld_plus_one =
+ net::registry_controlled_domains::GetDomainAndRegistry(
+ site, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+ return etld_plus_one.empty() ? site.spec() : etld_plus_one;
+}
+
+developer::SiteInfo CreateSiteInfo(
+ const std::string& site,
+ absl::optional<developer::UserSiteSet> site_set) {
+ developer::SiteInfo site_info;
+ site_info.site = site;
+ if (site_set.has_value())
+ site_info.site_list = *site_set;
+ else
+ site_info.num_extensions = 1;
+ return site_info;
+}
+
+// Adds `site` grouped under `etld_plus_one` into `site_groups`.
+void AddSiteToSiteGroups(
+ std::map<std::string, developer::SiteGroup>* site_groups,
+ const std::string& site,
+ const std::string& etld_plus_one,
+ absl::optional<developer::UserSiteSet> site_set) {
+ auto [it, inserted] = site_groups->try_emplace(etld_plus_one);
+ if (inserted) {
+ it->second.etld_plus_one = etld_plus_one;
+ it->second.sites.push_back(CreateSiteInfo(site, site_set));
+ } else {
+ auto site_info = std::find_if(
+ it->second.sites.begin(), it->second.sites.end(),
+ [site](const developer::SiteInfo& info) { return info.site == site; });
+
+ if (site_info == it->second.sites.end())
+ it->second.sites.push_back(CreateSiteInfo(site, site_set));
+ else
+ site_info->num_extensions++;
+ }
+}
+
+// Adds an extension's granted host permissions to `site_groups`,
+void ProcessSitesForRuntimeHostPermissions(
+ std::map<std::string, developer::SiteGroup>* site_groups,
+ const URLPatternSet& user_specified_sites,
+ const developer::RuntimeHostPermissions& permissions) {
+ // Track the set of eTLD+1s covered by the extension's granted host
+ // permissions.
+ std::set<std::string> etld_plus_ones;
+ for (const auto& host : permissions.hosts) {
+ // Convert the host permission pattern back to a URLPattern so it can
+ // be easily modified for comparing against user specified sites and for
+ // fetching the eTLD+1.
+ URLPattern pattern(Extension::kValidHostPermissionSchemes, host.host);
+ pattern.SetPath("");
+
+ // Ignore patterns that are empty, are not granted, or match with user
+ // specified sites.
+ if (pattern.host().empty() || !host.granted ||
+ user_specified_sites.ContainsPattern(pattern)) {
+ continue;
+ }
+
+ pattern.SetMatchSubdomains(false);
+ pattern.SetScheme("http");
+
+ std::string etld_plus_one = GetETldPlusOne(GURL(pattern.GetAsString()));
+ etld_plus_ones.insert(etld_plus_one);
+ AddSiteToSiteGroups(site_groups, host.host, etld_plus_one, absl::nullopt);
+ }
+
+ // Increment the extension count for each eTLD+1 covered by this extension's
+ // host permissions.
+ for (const auto& etld_plus_one : etld_plus_ones)
+ (*site_groups)[etld_plus_one].num_extensions++;
+}
+
+// Updates numExtensions counts in `site_groups` for `extension`. Note that this
+// should only be called for extensions with effective all hosts access.
+void UpdateSiteGroupCountsForExtension(
+ std::map<std::string, developer::SiteGroup>* site_groups,
+ const Extension* extension) {
+ const URLPatternSet extension_patterns =
+ extension->permissions_data()->GetEffectiveHostPermissions();
+ for (auto& entry : *site_groups) {
+ bool can_run_on_site_group = false;
+ for (developer::SiteInfo& site_info : entry.second.sites) {
+ if (site_info.site_list)
+ continue;
+
+ URLPattern pattern(Extension::kValidHostPermissionSchemes,
+ site_info.site);
+ if (extension_patterns.ContainsPattern(pattern)) {
+ can_run_on_site_group = true;
+ site_info.num_extensions++;
+ }
+ }
+ if (can_run_on_site_group)
+ entry.second.num_extensions++;
+ }
+}
+
} // namespace
namespace ChoosePath = api::developer_private::ChoosePath;
@@ -386,9 +490,6 @@ DeveloperPrivateEventRouter::DeveloperPrivateEventRouter(Profile* profile)
prefs::kExtensionsUIDeveloperMode,
base::BindRepeating(&DeveloperPrivateEventRouter::OnProfilePrefChanged,
base::Unretained(this)));
- notification_registrar_.Add(
- this, extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
- content::Source<Profile>(profile_.get()));
}
DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {
@@ -525,13 +626,13 @@ void DeveloperPrivateEventRouter::OnExtensionAllowlistWarningStateChanged(
}
void DeveloperPrivateEventRouter::OnExtensionManagementSettingsChanged() {
- std::vector<base::Value> args;
- args.push_back(base::Value::FromUniquePtrValue(
+ base::Value::List args;
+ args.Append(base::Value::FromUniquePtrValue(
DeveloperPrivateAPI::CreateProfileInfo(profile_)->ToValue()));
- std::unique_ptr<Event> event(
- new Event(events::DEVELOPER_PRIVATE_ON_PROFILE_STATE_CHANGED,
- developer::OnProfileStateChanged::kEventName, std::move(args)));
+ auto event = std::make_unique<Event>(
+ events::DEVELOPER_PRIVATE_ON_PROFILE_STATE_CHANGED,
+ developer::OnProfileStateChanged::kEventName, std::move(args));
event_router_->BroadcastEvent(std::move(event));
}
@@ -541,12 +642,12 @@ void DeveloperPrivateEventRouter::ExtensionWarningsChanged(
BroadcastItemStateChanged(developer::EVENT_TYPE_WARNINGS_CHANGED, id);
}
-void DeveloperPrivateEventRouter::UserPermissionsSettingsChanged(
+void DeveloperPrivateEventRouter::OnUserPermissionsSettingsChanged(
const PermissionsManager::UserPermissionsSettings& settings) {
developer::UserSiteSettings user_site_settings =
ConvertToUserSiteSettings(settings);
- std::vector<base::Value> args;
- args.push_back(base::Value::FromUniquePtrValue(user_site_settings.ToValue()));
+ base::Value::List args;
+ args.Append(base::Value::FromUniquePtrValue(user_site_settings.ToValue()));
auto event = std::make_unique<Event>(
events::DEVELOPER_PRIVATE_ON_USER_SITE_SETTINGS_CHANGED,
@@ -554,25 +655,21 @@ void DeveloperPrivateEventRouter::UserPermissionsSettingsChanged(
event_router_->BroadcastEvent(std::move(event));
}
-void DeveloperPrivateEventRouter::Observe(
- int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- DCHECK_EQ(NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED, type);
-
- UpdatedExtensionPermissionsInfo* info =
- content::Details<UpdatedExtensionPermissionsInfo>(details).ptr();
+void DeveloperPrivateEventRouter::OnExtensionPermissionsUpdated(
+ const Extension& extension,
+ const PermissionSet& permissions,
+ PermissionsManager::UpdateReason reason) {
BroadcastItemStateChanged(developer::EVENT_TYPE_PERMISSIONS_CHANGED,
- info->extension->id());
+ extension.id());
}
void DeveloperPrivateEventRouter::OnProfilePrefChanged() {
- std::vector<base::Value> args;
- args.push_back(base::Value::FromUniquePtrValue(
+ base::Value::List args;
+ args.Append(base::Value::FromUniquePtrValue(
DeveloperPrivateAPI::CreateProfileInfo(profile_)->ToValue()));
- std::unique_ptr<Event> event(
- new Event(events::DEVELOPER_PRIVATE_ON_PROFILE_STATE_CHANGED,
- developer::OnProfileStateChanged::kEventName, std::move(args)));
+ auto event = std::make_unique<Event>(
+ events::DEVELOPER_PRIVATE_ON_PROFILE_STATE_CHANGED,
+ developer::OnProfileStateChanged::kEventName, std::move(args));
event_router_->BroadcastEvent(std::move(event));
// The following properties are updated when dev mode is toggled.
@@ -622,8 +719,8 @@ void DeveloperPrivateEventRouter::BroadcastItemStateChangedHelper(
std::make_unique<developer::ExtensionInfo>(std::move(infos[0]));
}
- std::vector<base::Value> args;
- args.push_back(base::Value::FromUniquePtrValue(event_data.ToValue()));
+ base::Value::List args;
+ args.Append(base::Value::FromUniquePtrValue(event_data.ToValue()));
std::unique_ptr<Event> event(
new Event(events::DEVELOPER_PRIVATE_ON_ITEM_STATE_CHANGED,
developer::OnItemStateChanged::kEventName, std::move(args)));
@@ -2235,6 +2332,152 @@ DeveloperPrivateRemoveUserSpecifiedSitesFunction::Run() {
return RespondNow(NoArguments());
}
+DeveloperPrivateGetUserAndExtensionSitesByEtldFunction::
+ DeveloperPrivateGetUserAndExtensionSitesByEtldFunction() = default;
+DeveloperPrivateGetUserAndExtensionSitesByEtldFunction::
+ ~DeveloperPrivateGetUserAndExtensionSitesByEtldFunction() = default;
+
+ExtensionFunction::ResponseAction
+DeveloperPrivateGetUserAndExtensionSitesByEtldFunction::Run() {
+ std::map<std::string, developer::SiteGroup> site_groups;
+ const PermissionsManager::UserPermissionsSettings& settings =
+ PermissionsManager::Get(browser_context())->GetUserPermissionsSettings();
+ URLPatternSet user_specified_sites;
+ for (const url::Origin& site : settings.permitted_sites) {
+ user_specified_sites.AddOrigin(Extension::kValidHostPermissionSchemes,
+ site.GetURL());
+ AddSiteToSiteGroups(&site_groups, site.Serialize(),
+ GetETldPlusOne(site.GetURL()),
+ developer::USER_SITE_SET_PERMITTED);
+ }
+
+ for (const url::Origin& site : settings.restricted_sites) {
+ user_specified_sites.AddOrigin(Extension::kValidHostPermissionSchemes,
+ site.GetURL());
+ AddSiteToSiteGroups(&site_groups, site.Serialize(),
+ GetETldPlusOne(site.GetURL()),
+ developer::USER_SITE_SET_RESTRICTED);
+ }
+
+ std::vector<const Extension*> extensions_with_all_hosts;
+ ExtensionRegistry* registry = ExtensionRegistry::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.
+ if (!ui_util::ShouldDisplayInExtensionSettings(*extension) ||
+ !ScriptingPermissionsModifier(browser_context(), extension)
+ .CanAffectExtension()) {
+ continue;
+ }
+
+ developer::RuntimeHostPermissions permissions =
+ ExtensionInfoGenerator::CreateRuntimeHostPermissionsInfo(
+ browser_context(), *extension);
+
+ bool has_specific_hosts =
+ (!permissions.has_all_hosts &&
+ permissions.host_access == developer::HOST_ACCESS_ON_ALL_SITES) ||
+ permissions.host_access == developer::HOST_ACCESS_ON_SPECIFIC_SITES;
+
+ if (permissions.host_access == developer::HOST_ACCESS_ON_ALL_SITES &&
+ permissions.has_all_hosts) {
+ extensions_with_all_hosts.push_back(extension.get());
+ } else if (has_specific_hosts) {
+ ProcessSitesForRuntimeHostPermissions(&site_groups, user_specified_sites,
+ permissions);
+ }
+ }
+
+ // Specifying a "broad enough" host permission like "*://*.com/*" makes an
+ // extension "match all hosts". However, the extension does not truly have
+ // access to all sites, hence we iterate over all populated sites in
+ // `site_groups` and update the count for the extension for each site that it
+ // has access to.
+ for (const Extension* extension : extensions_with_all_hosts)
+ UpdateSiteGroupCountsForExtension(&site_groups, extension);
+
+ std::vector<developer::SiteGroup> site_group_list;
+ site_group_list.reserve(site_groups.size());
+ for (auto& entry : site_groups) {
+ // Sort the sites in each SiteGroup in ascending order by site.
+ std::sort(entry.second.sites.begin(), entry.second.sites.end(),
+ [](const developer::SiteInfo& a, const developer::SiteInfo& b) {
+ return b.site > a.site;
+ });
+ site_group_list.push_back(std::move(entry.second));
+ }
+
+ return RespondNow(
+ ArgumentList(developer::GetUserAndExtensionSitesByEtld::Results::Create(
+ site_group_list)));
+}
+
+DeveloperPrivateGetMatchingExtensionsForSiteFunction::
+ DeveloperPrivateGetMatchingExtensionsForSiteFunction() = default;
+DeveloperPrivateGetMatchingExtensionsForSiteFunction::
+ ~DeveloperPrivateGetMatchingExtensionsForSiteFunction() = default;
+
+ExtensionFunction::ResponseAction
+DeveloperPrivateGetMatchingExtensionsForSiteFunction::Run() {
+ std::unique_ptr<developer::GetMatchingExtensionsForSite::Params> params(
+ developer::GetMatchingExtensionsForSite::Params::Create(args()));
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ URLPattern parsed_site(Extension::kValidHostPermissionSchemes);
+ if (parsed_site.Parse(params->site) != URLPattern::ParseResult::kSuccess)
+ return RespondNow(Error("Invalid site: " + params->site));
+
+ std::vector<developer::MatchingExtensionInfo> matching_extensions;
+ URLPatternSet site_pattern({parsed_site});
+ std::unique_ptr<ExtensionSet> all_extensions =
+ ExtensionRegistry::Get(browser_context())
+ ->GenerateInstalledExtensionsSet();
+ for (const auto& extension : *all_extensions) {
+ const URLPatternSet& extension_withheld_sites =
+ extension->permissions_data()->withheld_permissions().effective_hosts();
+ const URLPatternSet granted_intersection =
+ URLPatternSet::CreateIntersection(
+ site_pattern,
+ extension->permissions_data()->GetEffectiveHostPermissions(),
+ URLPatternSet::IntersectionBehavior::kDetailed);
+ const URLPatternSet withheld_intersection =
+ URLPatternSet::CreateIntersection(
+ site_pattern, extension_withheld_sites,
+ URLPatternSet::IntersectionBehavior::kDetailed);
+
+ if (granted_intersection.is_empty() && withheld_intersection.is_empty())
+ continue;
+
+ // By default, return ON_CLICK if the extension has requested but does not
+ // have access to any sites that match `site_pattern`.
+ developer::HostAccess host_access = developer::HOST_ACCESS_ON_CLICK;
+
+ // 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.
+ if (!granted_intersection.is_empty()) {
+ host_access = extension_withheld_sites.is_empty()
+ ? developer::HOST_ACCESS_ON_ALL_SITES
+ : developer::HOST_ACCESS_ON_SPECIFIC_SITES;
+ }
+
+ developer::MatchingExtensionInfo matching_info;
+ matching_info.site_access = host_access;
+ matching_info.id = extension->id();
+ matching_extensions.push_back(std::move(matching_info));
+ }
+
+ return RespondNow(
+ ArgumentList(developer::GetMatchingExtensionsForSite::Results::Create(
+ matching_extensions)));
+}
+
} // 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 9a6547ad22f..4b971104c70 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
@@ -23,8 +23,6 @@
#include "chrome/common/extensions/api/developer_private.h"
#include "chrome/common/extensions/webstore_install_result.h"
#include "components/prefs/pref_change_registrar.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
#include "extensions/browser/api/file_system/file_system_api.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
@@ -72,7 +70,6 @@ class DeveloperPrivateEventRouter : public ExtensionRegistryObserver,
public ExtensionAllowlist::Observer,
public ExtensionManagement::Observer,
public WarningService::Observer,
- public content::NotificationObserver,
public PermissionsManager::Observer {
public:
explicit DeveloperPrivateEventRouter(Profile* profile);
@@ -142,14 +139,13 @@ class DeveloperPrivateEventRouter : public ExtensionRegistryObserver,
void ExtensionWarningsChanged(
const ExtensionIdSet& affected_extensions) override;
- // content::NotificationObserver:
- void Observe(int notification_type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) override;
-
// PermissionsManager::Observer:
- void UserPermissionsSettingsChanged(
+ void OnUserPermissionsSettingsChanged(
const PermissionsManager::UserPermissionsSettings& settings) override;
+ void OnExtensionPermissionsUpdated(
+ const Extension& extension,
+ const PermissionSet& permissions,
+ PermissionsManager::UpdateReason reason) override;
// Handles a profile preference change.
void OnProfilePrefChanged();
@@ -198,8 +194,6 @@ class DeveloperPrivateEventRouter : public ExtensionRegistryObserver,
PrefChangeRegistrar pref_change_registrar_;
- content::NotificationRegistrar notification_registrar_;
-
base::WeakPtrFactory<DeveloperPrivateEventRouter> weak_factory_{this};
};
@@ -210,7 +204,7 @@ class DeveloperPrivateAPI : public BrowserContextKeyedAPI,
using UnpackedRetryId = std::string;
static BrowserContextKeyedAPIFactory<DeveloperPrivateAPI>*
- GetFactoryInstance();
+ GetFactoryInstance();
static std::unique_ptr<api::developer_private::ProfileInfo> CreateProfileInfo(
Profile* profile);
@@ -641,7 +635,6 @@ class DeveloperPrivateChoosePathFunction
class DeveloperPrivatePackDirectoryFunction
: public DeveloperPrivateAPIFunction,
public PackExtensionJob::Client {
-
public:
DECLARE_EXTENSION_FUNCTION("developerPrivate.packDirectory",
DEVELOPERPRIVATE_PACKDIRECTORY)
@@ -926,6 +919,42 @@ class DeveloperPrivateRemoveUserSpecifiedSitesFunction
ResponseAction Run() override;
};
+class DeveloperPrivateGetUserAndExtensionSitesByEtldFunction
+ : public DeveloperPrivateAPIFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("developerPrivate.getUserAndExtensionSitesByEtld",
+ DEVELOPERPRIVATE_GETUSERANDEXTENSIONSITESBYETLD)
+ DeveloperPrivateGetUserAndExtensionSitesByEtldFunction();
+
+ DeveloperPrivateGetUserAndExtensionSitesByEtldFunction(
+ const DeveloperPrivateGetUserAndExtensionSitesByEtldFunction&) = delete;
+ DeveloperPrivateGetUserAndExtensionSitesByEtldFunction& operator=(
+ const DeveloperPrivateGetUserAndExtensionSitesByEtldFunction&) = delete;
+
+ private:
+ ~DeveloperPrivateGetUserAndExtensionSitesByEtldFunction() override;
+
+ ResponseAction Run() override;
+};
+
+class DeveloperPrivateGetMatchingExtensionsForSiteFunction
+ : public DeveloperPrivateAPIFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("developerPrivate.getMatchingExtensionsForSite",
+ DEVELOPERPRIVATE_GETMATCHINGEXTENSIONSFORSITE)
+ DeveloperPrivateGetMatchingExtensionsForSiteFunction();
+
+ DeveloperPrivateGetMatchingExtensionsForSiteFunction(
+ const DeveloperPrivateGetMatchingExtensionsForSiteFunction&) = delete;
+ DeveloperPrivateGetMatchingExtensionsForSiteFunction& operator=(
+ const DeveloperPrivateGetMatchingExtensionsForSiteFunction&) = delete;
+
+ private:
+ ~DeveloperPrivateGetMatchingExtensionsForSiteFunction() override;
+
+ ResponseAction Run() override;
+};
+
} // 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 15609e7db96..11a868758d4 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
@@ -12,6 +12,7 @@
#include "base/scoped_observation.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
+#include "base/test/values_test_util.h"
#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "chrome/browser/extensions/error_console/error_console.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
@@ -97,11 +98,9 @@ bool WasItemChangedEventDispatched(
return false;
const Event& event = *iter->second;
- CHECK(event.event_args);
- CHECK_GE(1u, event.event_args->GetListDeprecated().size());
+ CHECK_GE(1u, event.event_args.size());
std::unique_ptr<api::developer_private::EventData> event_data =
- api::developer_private::EventData::FromValue(
- event.event_args->GetListDeprecated()[0]);
+ api::developer_private::EventData::FromValue(event.event_args[0]);
if (!event_data)
return false;
@@ -124,10 +123,9 @@ bool WasUserSiteSettingsChangedEventDispatched(
return false;
const Event& event = *iter->second;
- CHECK(event.event_args);
- CHECK_GE(1u, event.event_args->GetListDeprecated().size());
- auto site_settings = api::developer_private::UserSiteSettings::FromValue(
- event.event_args->GetListDeprecated()[0]);
+ CHECK_GE(1u, event.event_args.size());
+ auto site_settings =
+ api::developer_private::UserSiteSettings::FromValue(event.event_args[0]);
if (!site_settings)
return false;
@@ -159,6 +157,66 @@ void RemoveUserSpecifiedSites(Profile* profile,
<< function->GetError();
}
+void AddExtensionAndGrantPermissions(Profile* profile,
+ ExtensionService* service,
+ const Extension& extension) {
+ PermissionsUpdater updater(profile);
+ updater.InitializePermissions(&extension);
+ updater.GrantActivePermissions(&extension);
+ service->AddExtension(&extension);
+}
+
+void RunAddHostPermission(Profile* profile,
+ const Extension& extension,
+ base::StringPiece host,
+ bool should_succeed,
+ const char* expected_error) {
+ SCOPED_TRACE(host);
+ scoped_refptr<ExtensionFunction> function =
+ base::MakeRefCounted<api::DeveloperPrivateAddHostPermissionFunction>();
+
+ std::string args = base::StringPrintf(R"(["%s", "%s"])",
+ extension.id().c_str(), host.data());
+ if (should_succeed) {
+ EXPECT_TRUE(api_test_utils::RunFunction(function.get(), args, profile))
+ << function->GetError();
+ } else {
+ EXPECT_EQ(expected_error, api_test_utils::RunFunctionAndReturnError(
+ function.get(), args, profile));
+ }
+}
+
+void GetMatchingExtensionsForSite(
+ Profile* profile,
+ const std::string& site,
+ std::vector<api::developer_private::MatchingExtensionInfo>* infos) {
+ scoped_refptr<ExtensionFunction> function = base::MakeRefCounted<
+ api::DeveloperPrivateGetMatchingExtensionsForSiteFunction>();
+ EXPECT_TRUE(api_test_utils::RunFunction(
+ function.get(), base::StringPrintf(R"(["%s"])", site.c_str()), profile))
+ << function->GetError();
+ const base::Value::List* results = function->GetResultList();
+ ASSERT_EQ(1u, results->size());
+ ASSERT_TRUE((*results)[0].is_list());
+
+ infos->clear();
+ for (const auto& value : (*results)[0].GetList()) {
+ infos->push_back(std::move(
+ *api::developer_private::MatchingExtensionInfo::FromValue(value)));
+ }
+}
+
+auto MatchMatchingExtensionInfo(
+ const std::string& extension_id,
+ const api::developer_private::HostAccess& host_access) {
+ return testing::AllOf(
+ testing::Field(&api::developer_private::MatchingExtensionInfo::id,
+ extension_id),
+ testing::Field(
+ &api::developer_private::MatchingExtensionInfo::site_access,
+ host_access));
+}
+
} // namespace
class DeveloperPrivateApiUnitTest : public ExtensionServiceTestWithInstall {
@@ -518,10 +576,9 @@ TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivatePackFunction) {
// Try to pack a final time when omitting (an existing) pem file. We should
// get an error.
base::DeleteFile(crx_path);
- EXPECT_TRUE(pack_args.EraseListIter(pack_args.GetListDeprecated().begin() +
- 1u)); // Remove the pem key argument.
- EXPECT_TRUE(pack_args.EraseListIter(pack_args.GetListDeprecated().begin() +
- 1u)); // Remove the flags argument.
+ // Remove the pem key and flags arguments.
+ pack_args.GetList().erase(pack_args.GetList().begin() + 1,
+ pack_args.GetList().begin() + 3);
EXPECT_TRUE(TestPackExtensionFunction(
pack_args, api::developer_private::PACK_STATUS_ERROR, 0));
}
@@ -1427,50 +1484,37 @@ TEST_F(DeveloperPrivateApiUnitTest, GrantHostPermission) {
EXPECT_FALSE(modifier.HasWithheldHostPermissions());
modifier.SetWithholdHostPermissions(true);
- auto run_add_host_permission = [this, extension](base::StringPiece host,
- bool should_succeed,
- const char* expected_error) {
- SCOPED_TRACE(host);
- scoped_refptr<ExtensionFunction> function =
- base::MakeRefCounted<api::DeveloperPrivateAddHostPermissionFunction>();
-
- std::string args = base::StringPrintf(R"(["%s", "%s"])",
- extension->id().c_str(), host.data());
- if (should_succeed) {
- EXPECT_TRUE(api_test_utils::RunFunction(function.get(), args, profile()))
- << function->GetError();
- } else {
- EXPECT_EQ(expected_error, api_test_utils::RunFunctionAndReturnError(
- function.get(), args, profile()));
- }
- };
-
const GURL kExampleCom("https://example.com/");
EXPECT_FALSE(modifier.HasGrantedHostPermission(kExampleCom));
- run_add_host_permission("https://example.com/*", true, nullptr);
+ RunAddHostPermission(profile(), *extension, "https://example.com/*",
+ /*should_succeed=*/true, nullptr);
EXPECT_TRUE(modifier.HasGrantedHostPermission(kExampleCom));
const GURL kGoogleCom("https://google.com");
const GURL kMapsGoogleCom("https://maps.google.com/");
EXPECT_FALSE(modifier.HasGrantedHostPermission(kGoogleCom));
EXPECT_FALSE(modifier.HasGrantedHostPermission(kMapsGoogleCom));
- run_add_host_permission("https://*.google.com/*", true, nullptr);
+ RunAddHostPermission(profile(), *extension, "https://*.google.com/*",
+ /*should_succeed=*/true, nullptr);
EXPECT_TRUE(modifier.HasGrantedHostPermission(kGoogleCom));
EXPECT_TRUE(modifier.HasGrantedHostPermission(kMapsGoogleCom));
- run_add_host_permission(kInvalidHost, false, kInvalidHostError);
+ RunAddHostPermission(profile(), *extension, kInvalidHost,
+ /*should_succeed=*/false, kInvalidHostError);
// Path of the pattern must exactly match "/*".
- run_add_host_permission("https://example.com/", false, kInvalidHostError);
- run_add_host_permission("https://example.com/foobar", false,
- kInvalidHostError);
- run_add_host_permission("https://example.com/#foobar", false,
- kInvalidHostError);
- run_add_host_permission("https://example.com/*foobar", false,
- kInvalidHostError);
+ RunAddHostPermission(profile(), *extension, "https://example.com/",
+ /*should_succeed=*/false, kInvalidHostError);
+ RunAddHostPermission(profile(), *extension, "https://example.com/foobar",
+ /*should_succeed=*/false, kInvalidHostError);
+ RunAddHostPermission(profile(), *extension, "https://example.com/#foobar",
+ /*should_succeed=*/false, kInvalidHostError);
+ RunAddHostPermission(profile(), *extension, "https://example.com/*foobar",
+ /*should_succeed=*/false, kInvalidHostError);
// Cannot grant chrome:-scheme URLs.
GURL chrome_host("chrome://settings/*");
- run_add_host_permission(chrome_host.spec(), false, kInvalidHostError);
+ RunAddHostPermission(profile(), *extension, chrome_host.spec(),
+ /*should_succeed=*/false, kInvalidHostError);
EXPECT_FALSE(modifier.HasGrantedHostPermission(chrome_host));
}
@@ -1971,6 +2015,307 @@ TEST_F(DeveloperPrivateApiUnitTest, OnUserSiteSettingsChanged) {
EXPECT_TRUE(settings.restricted_sites.empty());
}
+TEST_F(DeveloperPrivateApiUnitTest,
+ DeveloperPrivateGetUserAndExtensionSitesByEtld_UserSites) {
+ PermissionsManager* manager = PermissionsManager::Get(browser_context());
+
+ // Add two sites under the eTLD+1 example.com, and one under eTLD+1 google.ca.
+ manager->AddUserPermittedSite(
+ url::Origin::Create(GURL("http://a.example.com")));
+ manager->AddUserRestrictedSite(
+ url::Origin::Create(GURL("http://b.example.com")));
+ manager->AddUserRestrictedSite(url::Origin::Create(GURL("http://google.ca")));
+
+ scoped_refptr<ExtensionFunction> function = base::MakeRefCounted<
+ api::DeveloperPrivateGetUserAndExtensionSitesByEtldFunction>();
+ EXPECT_TRUE(RunFunction(function, base::ListValue())) << function->GetError();
+ const base::Value::List* results = function->GetResultList();
+ ASSERT_EQ(1u, results->size());
+
+ EXPECT_THAT((*results)[0], base::test::IsJson(R"([{
+ "etldPlusOne": "example.com",
+ "numExtensions": 0,
+ "sites": [{
+ "siteList": "PERMITTED",
+ "numExtensions": 0,
+ "site": "http://a.example.com",
+ }, {
+ "siteList": "RESTRICTED",
+ "numExtensions": 0,
+ "site": "http://b.example.com",
+ }]
+ }, {
+ "etldPlusOne": "google.ca",
+ "numExtensions": 0,
+ "sites": [{
+ "siteList": "RESTRICTED",
+ "numExtensions": 0,
+ "site": "http://google.ca",
+ }]
+ }])"));
+}
+
+TEST_F(DeveloperPrivateApiUnitTest,
+ DeveloperPrivateGetUserAndExtensionSitesByEtld_UserAndExtensionSites) {
+ PermissionsManager* manager = PermissionsManager::Get(browser_context());
+ manager->AddUserPermittedSite(
+ url::Origin::Create(GURL("http://images.google.com")));
+ manager->AddUserRestrictedSite(
+ url::Origin::Create(GURL("http://www.asdf.com")));
+
+ scoped_refptr<const Extension> extension_1 =
+ ExtensionBuilder("test")
+ .AddPermission("https://*.google.com/")
+ .AddPermission("http://www.google.com/")
+ .AddPermission("http://images.google.com/")
+ .AddPermission("https://example.com/")
+ .Build();
+
+ scoped_refptr<const Extension> extension_2 =
+ ExtensionBuilder("test_2")
+ .AddPermission("https://mail.google.com/")
+ .AddPermission("http://www.google.com/")
+ .AddPermission("http://www.asdf.com/")
+ .Build();
+ AddExtensionAndGrantPermissions(profile(), service(), *extension_1);
+ AddExtensionAndGrantPermissions(profile(), service(), *extension_2);
+
+ scoped_refptr<ExtensionFunction> function = base::MakeRefCounted<
+ api::DeveloperPrivateGetUserAndExtensionSitesByEtldFunction>();
+ EXPECT_TRUE(RunFunction(function, base::ListValue())) << function->GetError();
+ const base::Value::List* results = function->GetResultList();
+ ASSERT_EQ(1u, results->size());
+
+ // asdf.com and http://www.asdf.com should not have any extensions counted
+ // because they are associated with user specified sites.
+ EXPECT_THAT((*results)[0], base::test::IsJson(R"([{
+ "etldPlusOne": "asdf.com",
+ "numExtensions": 0,
+ "sites": [{
+ "siteList": "RESTRICTED",
+ "numExtensions": 0,
+ "site": "http://www.asdf.com",
+ }]
+ }, {
+ "etldPlusOne": "example.com",
+ "numExtensions": 1,
+ "sites": [{
+ "numExtensions": 1,
+ "site": "https://example.com/*",
+ }]
+ }, {
+ "etldPlusOne": "google.com",
+ "numExtensions": 2,
+ "sites": [{
+ "siteList": "PERMITTED",
+ "numExtensions": 0,
+ "site": "http://images.google.com",
+ }, {
+ "numExtensions": 2,
+ "site": "http://www.google.com/*",
+ }, {
+ "numExtensions": 1,
+ "site": "https://*.google.com/*",
+ }, {
+ "numExtensions": 1,
+ "site": "https://mail.google.com/*",
+ }]
+ }])"));
+}
+
+TEST_F(DeveloperPrivateApiUnitTest,
+ DeveloperPrivateGetUserAndExtensionSitesByEtld_EffectiveAllHosts) {
+ PermissionsManager* manager = PermissionsManager::Get(browser_context());
+ manager->AddUserPermittedSite(
+ url::Origin::Create(GURL("http://images.google.ca")));
+
+ scoped_refptr<const Extension> extension_1 =
+ ExtensionBuilder("specific_hosts")
+ .AddPermission("https://*.google.ca/")
+ .AddPermission("http://www.example.com/")
+ .Build();
+
+ scoped_refptr<const Extension> extension_2 =
+ ExtensionBuilder("all_.com").AddPermission("*://*.com/*").Build();
+
+ scoped_refptr<const Extension> extension_3 =
+ ExtensionBuilder("all_urls").AddPermission("<all_urls>").Build();
+ AddExtensionAndGrantPermissions(profile(), service(), *extension_1);
+ AddExtensionAndGrantPermissions(profile(), service(), *extension_2);
+ AddExtensionAndGrantPermissions(profile(), service(), *extension_3);
+
+ scoped_refptr<ExtensionFunction> function = base::MakeRefCounted<
+ api::DeveloperPrivateGetUserAndExtensionSitesByEtldFunction>();
+ EXPECT_TRUE(RunFunction(function, base::ListValue())) << function->GetError();
+ const base::Value::List* results = function->GetResultList();
+ ASSERT_EQ(1u, results->size());
+
+ // `extension_2` should not be counted for https://*.google.ca/* as it cannot
+ // run on .ca sites.
+ EXPECT_THAT((*results)[0], base::test::IsJson(R"([{
+ "etldPlusOne": "example.com",
+ "numExtensions": 3,
+ "sites": [{
+ "numExtensions": 3,
+ "site": "http://www.example.com/*",
+ }]
+ }, {
+ "etldPlusOne": "google.ca",
+ "numExtensions": 2,
+ "sites": [{
+ "numExtensions": 0,
+ "site": "http://images.google.ca",
+ "siteList": "PERMITTED",
+ }, {
+ "numExtensions": 2,
+ "site": "https://*.google.ca/*",
+ }]
+ }])"));
+}
+
+TEST_F(DeveloperPrivateApiUnitTest,
+ DeveloperPrivateGetUserAndExtensionSitesByEtld_RuntimeGrantedHosts) {
+ scoped_refptr<const Extension> extension_1 =
+ ExtensionBuilder("runtime_hosts").AddPermission("<all_urls>").Build();
+ AddExtensionAndGrantPermissions(profile(), service(), *extension_1);
+
+ auto get_user_and_extension_sites = [this](const std::string& expected_json) {
+ scoped_refptr<ExtensionFunction> function = base::MakeRefCounted<
+ api::DeveloperPrivateGetUserAndExtensionSitesByEtldFunction>();
+ EXPECT_TRUE(RunFunction(function, base::ListValue()))
+ << function->GetError();
+ const base::Value::List* results = function->GetResultList();
+ ASSERT_EQ(1u, results->size());
+ EXPECT_THAT((*results)[0], base::test::IsJson(expected_json));
+ };
+
+ get_user_and_extension_sites(R"([])");
+
+ ScriptingPermissionsModifier modifier(profile(), extension_1.get());
+ EXPECT_FALSE(modifier.HasWithheldHostPermissions());
+ modifier.SetWithholdHostPermissions(true);
+
+ get_user_and_extension_sites(R"([])");
+
+ const std::string kExampleCom = "https://example.com/*";
+ RunAddHostPermission(profile(), *extension_1, kExampleCom,
+ /*should_succeed=*/true, nullptr);
+
+ get_user_and_extension_sites(R"([{
+ "etldPlusOne": "example.com",
+ "numExtensions": 1,
+ "sites": [{
+ "numExtensions": 1,
+ "site": "https://example.com/*",
+ }]
+ }])");
+
+ scoped_refptr<const Extension> extension_2 =
+ ExtensionBuilder("test").AddPermission(kExampleCom).Build();
+ AddExtensionAndGrantPermissions(profile(), service(), *extension_2);
+
+ get_user_and_extension_sites(R"([{
+ "etldPlusOne": "example.com",
+ "numExtensions": 2,
+ "sites": [{
+ "numExtensions": 2,
+ "site": "https://example.com/*",
+ }]
+ }])");
+
+ RunUpdateHostAccess(*extension_1, "ON_ALL_SITES");
+ get_user_and_extension_sites(R"([{
+ "etldPlusOne": "example.com",
+ "numExtensions": 2,
+ "sites": [{
+ "numExtensions": 2,
+ "site": "https://example.com/*",
+ }]
+ }])");
+}
+
+TEST_F(DeveloperPrivateApiUnitTest,
+ DeveloperPrivateGetMatchingExtensionsForSite) {
+ namespace developer = api::developer_private;
+
+ scoped_refptr<const Extension> extension_1 =
+ ExtensionBuilder("test").AddPermission("*://mail.google.com/").Build();
+
+ scoped_refptr<const Extension> extension_2 =
+ ExtensionBuilder("test_2")
+ .AddPermission("*://images.google.com/")
+ .Build();
+ AddExtensionAndGrantPermissions(profile(), service(), *extension_1);
+ AddExtensionAndGrantPermissions(profile(), service(), *extension_2);
+
+ std::vector<developer::MatchingExtensionInfo> infos;
+ GetMatchingExtensionsForSite(profile(), "http://none.com/", &infos);
+ EXPECT_TRUE(infos.empty());
+
+ GetMatchingExtensionsForSite(profile(), "http://images.google.com/", &infos);
+
+ // "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)));
+
+ 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)));
+}
+
+// Test that the host access returned by GetMatchingExtensionsForSite reflects
+// whether the extension has access to the queried site, or has withheld sites
+// in general.
+TEST_F(DeveloperPrivateApiUnitTest,
+ DeveloperPrivateGetMatchingExtensionsForSite_RuntimeGrantedHostAccess) {
+ namespace developer = api::developer_private;
+
+ scoped_refptr<const Extension> extension =
+ ExtensionBuilder("test").AddPermission("<all_urls>").Build();
+ AddExtensionAndGrantPermissions(profile(), service(), *extension);
+
+ std::vector<developer::MatchingExtensionInfo> infos;
+ GetMatchingExtensionsForSite(profile(), "http://example.com/", &infos);
+
+ EXPECT_THAT(infos, testing::UnorderedElementsAre(MatchMatchingExtensionInfo(
+ extension->id(),
+ developer::HostAccess::HOST_ACCESS_ON_ALL_SITES)));
+
+ ScriptingPermissionsModifier modifier(profile(), extension.get());
+ EXPECT_FALSE(modifier.HasWithheldHostPermissions());
+ modifier.SetWithholdHostPermissions(true);
+
+ GetMatchingExtensionsForSite(profile(), "http://example.com/", &infos);
+ EXPECT_THAT(infos, testing::UnorderedElementsAre(MatchMatchingExtensionInfo(
+ extension->id(),
+ developer::HostAccess::HOST_ACCESS_ON_CLICK)));
+
+ 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)));
+}
+
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 c60fcbfdc18..f4143ef7372 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
@@ -4,6 +4,7 @@
#include "base/path_service.h"
#include "base/strings/stringprintf.h"
+#include "base/test/scoped_feature_list.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/devtools/devtools_window_testing.h"
#include "chrome/browser/extensions/api/developer_private/developer_private_api.h"
@@ -12,13 +13,20 @@
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/common/chrome_paths.h"
#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/service_worker_test_helpers.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/browsertest_util.h"
+#include "extensions/browser/extension_host_test_helper.h"
+#include "extensions/browser/offscreen_document_host.h"
+#include "extensions/browser/process_manager.h"
+#include "extensions/common/extension_features.h"
#include "extensions/common/manifest_handlers/background_info.h"
+#include "extensions/common/mojom/view_type.mojom.h"
#include "extensions/test/result_catcher.h"
+#include "extensions/test/test_extension_dir.h"
namespace extensions {
@@ -274,4 +282,103 @@ IN_PROC_BROWSER_TEST_F(DeveloperPrivateApiTest,
EXPECT_TRUE(DevToolsWindow::FindDevToolsWindow(service_worker_host.get()));
}
+class DeveloperPrivateOffscreenDocumentApiTest
+ : public DeveloperPrivateApiTest {
+ public:
+ DeveloperPrivateOffscreenDocumentApiTest() {
+ feature_list_.InitAndEnableFeature(
+ extensions_features::kExtensionsOffscreenDocuments);
+ }
+ ~DeveloperPrivateOffscreenDocumentApiTest() override = default;
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+// Test that offscreen documents show up in the list of inspectable views and
+// can be inspected.
+IN_PROC_BROWSER_TEST_F(DeveloperPrivateOffscreenDocumentApiTest,
+ InspectOffscreenDocument) {
+ static constexpr char kManifest[] =
+ R"({
+ "name": "Offscreen Document Test",
+ "manifest_version": 3,
+ "version": "0.1"
+ })";
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.html"),
+ "<html>offscreen</html>");
+
+ const Extension* extension = LoadExtension(test_dir.UnpackedPath());
+
+ // Create an offscreen document and wait for it to load.
+ std::unique_ptr<OffscreenDocumentHost> offscreen_document;
+ GURL offscreen_url = extension->GetResourceURL("offscreen.html");
+ {
+ ExtensionHostTestHelper offscreen_waiter(profile(), extension->id());
+ offscreen_waiter.RestrictToType(mojom::ViewType::kOffscreenDocument);
+ offscreen_document = std::make_unique<OffscreenDocumentHost>(
+ *extension,
+ ProcessManager::Get(profile())
+ ->GetSiteInstanceForURL(offscreen_url)
+ .get(),
+ offscreen_url);
+ offscreen_document->CreateRendererSoon();
+ offscreen_waiter.WaitForHostCompletedFirstLoad();
+ }
+
+ // Get the list of inspectable views for the extension.
+ auto get_info_function =
+ base::MakeRefCounted<api::DeveloperPrivateGetExtensionInfoFunction>();
+ std::unique_ptr<base::Value> result =
+ extension_function_test_utils::RunFunctionAndReturnSingleResult(
+ get_info_function.get(),
+ content::JsReplace(R"([$1])", extension->id()), browser());
+ ASSERT_TRUE(result);
+ std::unique_ptr<api::developer_private::ExtensionInfo> info =
+ api::developer_private::ExtensionInfo::FromValue(*result);
+ ASSERT_TRUE(info);
+
+ // The only inspectable view should be the offscreen document. Validate the
+ // metadata.
+ ASSERT_EQ(1u, info->views.size());
+ const api::developer_private::ExtensionView& view = info->views[0];
+ EXPECT_EQ(api::developer_private::VIEW_TYPE_OFFSCREEN_DOCUMENT, view.type);
+ content::WebContents* offscreen_contents =
+ offscreen_document->host_contents();
+ EXPECT_EQ(offscreen_url.spec(), view.url);
+ EXPECT_EQ(offscreen_document->render_process_host()->GetID(),
+ view.render_process_id);
+ EXPECT_EQ(offscreen_contents->GetPrimaryMainFrame()->GetRoutingID(),
+ view.render_view_id);
+ EXPECT_FALSE(view.incognito);
+ EXPECT_FALSE(view.is_iframe);
+
+ // The document shouldn't currently be under inspection.
+ EXPECT_FALSE(
+ DevToolsWindow::GetInstanceForInspectedWebContents(offscreen_contents));
+
+ // Call the API function to inspect the offscreen document.
+ auto dev_tools_function =
+ base::MakeRefCounted<api::DeveloperPrivateOpenDevToolsFunction>();
+ extension_function_test_utils::RunFunction(
+ dev_tools_function.get(),
+ content::JsReplace(
+ R"([{"renderViewId": $1,
+ "renderProcessId": $2,
+ "extensionId": $3
+ }])",
+ view.render_view_id, view.render_process_id, extension->id()),
+ browser(), api_test_utils::NONE);
+
+ // Validate that the devtools window is now shown.
+ DevToolsWindow* dev_tools_window =
+ DevToolsWindow::GetInstanceForInspectedWebContents(offscreen_contents);
+ ASSERT_TRUE(dev_tools_window);
+
+ // Tidy up.
+ DevToolsWindowTesting::CloseDevToolsWindowSync(dev_tools_window);
+}
+
} // namespace extensions
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 ec7ce69a263..ac0befd1ab5 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
@@ -360,45 +360,10 @@ void AddPermissionsInfo(content::BrowserContext* browser_context,
extension.GetType()));
permissions->simple_permissions = get_permission_messages(api_messages);
- auto runtime_host_permissions =
- std::make_unique<developer::RuntimeHostPermissions>();
-
- ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context);
- // "Effective" granted permissions are stored in different prefs, based on
- // whether host permissions are withheld.
- // TODO(devlin): Create a common helper method to retrieve granted prefs based
- // on whether host permissions are withheld?
- std::unique_ptr<const PermissionSet> granted_permissions;
- // Add the host access data, including the mode and any runtime-granted
- // hosts.
- if (!permissions_modifier.HasWithheldHostPermissions()) {
- granted_permissions =
- extension_prefs->GetGrantedPermissions(extension.id());
- runtime_host_permissions->host_access = developer::HOST_ACCESS_ON_ALL_SITES;
- } else {
- granted_permissions =
- extension_prefs->GetRuntimeGrantedPermissions(extension.id());
- if (granted_permissions->effective_hosts().is_empty()) {
- runtime_host_permissions->host_access = developer::HOST_ACCESS_ON_CLICK;
- } else if (granted_permissions->ShouldWarnAllHosts(false)) {
- runtime_host_permissions->host_access =
- developer::HOST_ACCESS_ON_ALL_SITES;
- } else {
- runtime_host_permissions->host_access =
- developer::HOST_ACCESS_ON_SPECIFIC_SITES;
- }
- }
-
- runtime_host_permissions->hosts = GetSpecificSiteControls(
- *granted_permissions,
- extension.permissions_data()->withheld_permissions());
- constexpr bool kIncludeApiPermissions = false;
- runtime_host_permissions->has_all_hosts =
- extension.permissions_data()->withheld_permissions().ShouldWarnAllHosts(
- kIncludeApiPermissions) ||
- granted_permissions->ShouldWarnAllHosts(kIncludeApiPermissions);
-
- permissions->runtime_host_permissions = std::move(runtime_host_permissions);
+ permissions->runtime_host_permissions =
+ std::make_unique<developer::RuntimeHostPermissions>(
+ ExtensionInfoGenerator::CreateRuntimeHostPermissionsInfo(
+ browser_context, extension));
}
} // namespace
@@ -489,6 +454,51 @@ void ExtensionInfoGenerator::CreateExtensionsInfo(
}
}
+developer::RuntimeHostPermissions
+ExtensionInfoGenerator::CreateRuntimeHostPermissionsInfo(
+ content::BrowserContext* browser_context,
+ const Extension& extension) {
+ ScriptingPermissionsModifier permissions_modifier(
+ browser_context, base::WrapRefCounted(&extension));
+ developer::RuntimeHostPermissions runtime_host_permissions;
+
+ ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context);
+ // "Effective" granted permissions are stored in different prefs, based on
+ // whether host permissions are withheld.
+ // TODO(devlin): Create a common helper method to retrieve granted prefs based
+ // on whether host permissions are withheld?
+ std::unique_ptr<const PermissionSet> granted_permissions;
+ // Add the host access data, including the mode and any runtime-granted
+ // hosts.
+ if (!permissions_modifier.HasWithheldHostPermissions()) {
+ granted_permissions =
+ extension_prefs->GetGrantedPermissions(extension.id());
+ runtime_host_permissions.host_access = developer::HOST_ACCESS_ON_ALL_SITES;
+ } else {
+ granted_permissions =
+ extension_prefs->GetRuntimeGrantedPermissions(extension.id());
+ if (granted_permissions->effective_hosts().is_empty()) {
+ runtime_host_permissions.host_access = developer::HOST_ACCESS_ON_CLICK;
+ } else if (granted_permissions->ShouldWarnAllHosts(false)) {
+ runtime_host_permissions.host_access =
+ developer::HOST_ACCESS_ON_ALL_SITES;
+ } else {
+ runtime_host_permissions.host_access =
+ developer::HOST_ACCESS_ON_SPECIFIC_SITES;
+ }
+ }
+
+ runtime_host_permissions.hosts = GetSpecificSiteControls(
+ *granted_permissions,
+ extension.permissions_data()->withheld_permissions());
+ constexpr bool kIncludeApiPermissions = false;
+ runtime_host_permissions.has_all_hosts =
+ extension.permissions_data()->withheld_permissions().ShouldWarnAllHosts(
+ kIncludeApiPermissions) ||
+ granted_permissions->ShouldWarnAllHosts(kIncludeApiPermissions);
+ return runtime_host_permissions;
+}
+
void ExtensionInfoGenerator::CreateExtensionInfoHelper(
const Extension& extension,
developer::ExtensionState state) {
@@ -642,13 +652,18 @@ void ExtensionInfoGenerator::CreateExtensionInfoHelper(
}
// Location.
+ bool updates_from_web_store =
+ extension_management->UpdatesFromWebstore(extension);
if (extension.location() == mojom::ManifestLocation::kInternal &&
- extension_management->UpdatesFromWebstore(extension)) {
+ updates_from_web_store) {
info->location = developer::LOCATION_FROM_STORE;
} else if (Manifest::IsUnpackedLocation(extension.location())) {
info->location = developer::LOCATION_UNPACKED;
+ } else if (extension.was_installed_by_default() &&
+ !extension.was_installed_by_oem() && updates_from_web_store) {
+ info->location = developer::LOCATION_INSTALLED_BY_DEFAULT;
} else if (Manifest::IsExternalLocation(extension.location()) &&
- extension_management->UpdatesFromWebstore(extension)) {
+ updates_from_web_store) {
info->location = developer::LOCATION_THIRD_PARTY;
} else {
info->location = developer::LOCATION_UNKNOWN;
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 fbe06dd5c14..a906c676e93 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
@@ -64,6 +64,12 @@ class ExtensionInfoGenerator {
bool include_terminated,
ExtensionInfosCallback callback);
+ // Creates and synchronously returns a RuntimeHostPermissions object with the
+ // given extension's host permissions.
+ static api::developer_private::RuntimeHostPermissions
+ CreateRuntimeHostPermissionsInfo(content::BrowserContext* browser_context,
+ const Extension& extension);
+
private:
// Creates an ExtensionInfo for the given |extension| and |state|, and
// asynchronously adds it to the |list|.
@@ -91,7 +97,7 @@ class ExtensionInfoGenerator {
raw_ptr<ErrorConsole> error_console_;
raw_ptr<ImageLoader> image_loader_;
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
- SupervisedUserService* supervised_user_service_;
+ raw_ptr<SupervisedUserService> supervised_user_service_;
#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
// The number of pending image loads.
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 44a8dd86ce0..68ed5f23ff4 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
@@ -270,7 +270,9 @@ TEST_F(ExtensionInfoGeneratorUnitTest, BasicInfoTest) {
.Build())
.Set("permissions", ListBuilder().Append("tabs").Build())
.Build();
- std::unique_ptr<base::DictionaryValue> manifest_copy(manifest->DeepCopy());
+ std::unique_ptr<base::DictionaryValue> manifest_copy =
+ base::DictionaryValue::From(
+ base::Value::ToUniquePtrValue(manifest->Clone()));
scoped_refptr<const Extension> extension =
ExtensionBuilder()
.SetManifest(std::move(manifest))
@@ -377,6 +379,63 @@ TEST_F(ExtensionInfoGeneratorUnitTest, BasicInfoTest) {
EXPECT_FALSE(info->path);
}
+// Tests that the correct location field is returned for an extension that's
+// installed by default.
+TEST_F(ExtensionInfoGeneratorUnitTest, ExtensionInfoInstalledByDefault) {
+ profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);
+
+ std::unique_ptr<base::DictionaryValue> manifest =
+ DictionaryBuilder()
+ .Set("name", "installed by default")
+ .Set("version", "1.2")
+ .Set("manifest_version", 3)
+ .Set("update_url", "https://clients2.google.com/service/update2/crx")
+ .Build();
+
+ scoped_refptr<const Extension> extension =
+ ExtensionBuilder()
+ .SetManifest(std::move(manifest))
+ .SetLocation(ManifestLocation::kExternalPref)
+ .SetPath(data_dir())
+ .SetID(crx_file::id_util::GenerateId("alpha"))
+ .AddFlags(Extension::WAS_INSTALLED_BY_DEFAULT)
+ .Build();
+ service()->AddExtension(extension.get());
+
+ std::unique_ptr<api::developer_private::ExtensionInfo> info =
+ GenerateExtensionInfo(extension->id());
+ EXPECT_EQ(info->location, developer::LOCATION_INSTALLED_BY_DEFAULT);
+}
+
+// Tests that the correct location field is returned for an extension that's
+// installed by the OEM.
+TEST_F(ExtensionInfoGeneratorUnitTest, ExtensionInfoInstalledByOem) {
+ profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);
+
+ std::unique_ptr<base::DictionaryValue> manifest =
+ DictionaryBuilder()
+ .Set("name", "installed by OEM")
+ .Set("version", "1.2")
+ .Set("manifest_version", 3)
+ .Set("update_url", "https://clients2.google.com/service/update2/crx")
+ .Build();
+
+ scoped_refptr<const Extension> extension =
+ ExtensionBuilder()
+ .SetManifest(std::move(manifest))
+ .SetLocation(ManifestLocation::kExternalPref)
+ .SetPath(data_dir())
+ .SetID(crx_file::id_util::GenerateId("alpha"))
+ .AddFlags(Extension::WAS_INSTALLED_BY_DEFAULT |
+ Extension::WAS_INSTALLED_BY_OEM)
+ .Build();
+ service()->AddExtension(extension.get());
+
+ std::unique_ptr<api::developer_private::ExtensionInfo> info =
+ GenerateExtensionInfo(extension->id());
+ EXPECT_EQ(info->location, developer::LOCATION_THIRD_PARTY);
+}
+
// Test three generated json outputs.
TEST_F(ExtensionInfoGeneratorUnitTest, GenerateExtensionsJSONData) {
// Test Extension1
diff --git a/chromium/chrome/browser/extensions/api/developer_private/inspectable_views_finder.cc b/chromium/chrome/browser/extensions/api/developer_private/inspectable_views_finder.cc
index 27fa396e606..87a5db2c54a 100644
--- a/chromium/chrome/browser/extensions/api/developer_private/inspectable_views_finder.cc
+++ b/chromium/chrome/browser/extensions/api/developer_private/inspectable_views_finder.cc
@@ -66,6 +66,10 @@ api::developer_private::ViewType ConvertViewType(const mojom::ViewType type) {
case mojom::ViewType::kTabContents:
developer_private_type = api::developer_private::VIEW_TYPE_TAB_CONTENTS;
break;
+ case mojom::ViewType::kOffscreenDocument:
+ developer_private_type =
+ api::developer_private::VIEW_TYPE_OFFSCREEN_DOCUMENT;
+ break;
default:
developer_private_type = api::developer_private::VIEW_TYPE_NONE;
NOTREACHED();
diff --git a/chromium/chrome/browser/extensions/api/device_permissions_manager_unittest.cc b/chromium/chrome/browser/extensions/api/device_permissions_manager_unittest.cc
index 21d8be994a4..7220ded81ab 100644
--- a/chromium/chrome/browser/extensions/api/device_permissions_manager_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/device_permissions_manager_unittest.cc
@@ -19,7 +19,7 @@
#include "extensions/browser/extension_prefs.h"
#include "extensions/common/extension.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/device/public/cpp/hid/fake_hid_manager.h"
+#include "services/device/public/cpp/test/fake_hid_manager.h"
#include "services/device/public/cpp/test/fake_usb_device_manager.h"
#include "services/device/public/mojom/hid.mojom.h"
#include "services/device/public/mojom/usb_device.mojom.h"
diff --git a/chromium/chrome/browser/extensions/api/document_scan/document_scan_api.h b/chromium/chrome/browser/extensions/api/document_scan/document_scan_api.h
index 8b45a9602fe..6bbb36508a5 100644
--- a/chromium/chrome/browser/extensions/api/document_scan/document_scan_api.h
+++ b/chromium/chrome/browser/extensions/api/document_scan/document_scan_api.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/memory/raw_ptr.h"
#include "chrome/common/extensions/api/document_scan.h"
#include "chromeos/crosapi/mojom/document_scan.mojom-forward.h"
#include "extensions/browser/extension_function.h"
@@ -49,7 +50,7 @@ class DocumentScanScanFunction : public ExtensionFunction {
// Null if the interface is unavailable.
// The pointer is constant - if Ash crashes and the mojo connection is lost,
// Lacros will automatically be restarted.
- crosapi::mojom::DocumentScan* document_scan_ = nullptr;
+ raw_ptr<crosapi::mojom::DocumentScan> document_scan_ = nullptr;
};
} // namespace api
diff --git a/chromium/chrome/browser/extensions/api/downloads/downloads_api.cc b/chromium/chrome/browser/extensions/api/downloads/downloads_api.cc
index 9b2e75bf4da..1d58b5ad000 100644
--- a/chromium/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chromium/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -33,6 +33,8 @@
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/bubble/download_bubble_controller.h"
+#include "chrome/browser/download/bubble/download_bubble_prefs.h"
#include "chrome/browser/download/download_core_service.h"
#include "chrome/browser/download/download_core_service_factory.h"
#include "chrome/browser/download/download_danger_prompt.h"
@@ -114,6 +116,10 @@ const char kTooManyListeners[] =
"Each extension may have at most one "
"onDeterminingFilename listener between all of its renderer execution "
"contexts.";
+const char kUiDisabled[] = "Another extension has disabled the download UI";
+const char kUiPermission[] =
+ "downloads.setUiOptions requires the "
+ "\"downloads.ui\" permission";
const char kUnexpectedDeterminer[] = "Unexpected determineFilename call";
const char kUserGesture[] = "User gesture required";
@@ -441,7 +447,7 @@ bool ShouldExport(const DownloadItem& download_item) {
// Set |manager| to the on-record DownloadManager, and |incognito_manager| to
// the off-record DownloadManager if one exists and is requested via
-// |include_incognito|. This should work regardless of whether |profile| is
+// |include_incognito|. This should work regardless of whether |context| is
// original or incognito.
void GetManagers(content::BrowserContext* context,
bool include_incognito,
@@ -459,6 +465,40 @@ void GetManagers(content::BrowserContext* context,
}
}
+// Set |service| to the on-record DownloadCoreService, |incognito_service| to
+// the off-record DownloadCoreService if one exists and is requested via
+// |include_incognito|. This should work regardless of whether |context| is
+// original or incognito.
+void GetDownloadCoreServices(content::BrowserContext* context,
+ bool include_incognito,
+ DownloadCoreService** service,
+ DownloadCoreService** incognito_service) {
+ DownloadManager* manager = nullptr;
+ DownloadManager* incognito_manager = nullptr;
+ GetManagers(context, include_incognito, &manager, &incognito_manager);
+ if (manager) {
+ *service = DownloadCoreServiceFactory::GetForBrowserContext(
+ manager->GetBrowserContext());
+ }
+ if (incognito_manager) {
+ *incognito_service = DownloadCoreServiceFactory::GetForBrowserContext(
+ incognito_manager->GetBrowserContext());
+ }
+}
+
+void MaybeSetUiEnabled(DownloadCoreService* service,
+ DownloadCoreService* incognito_service,
+ const Extension* extension,
+ bool enabled) {
+ if (service) {
+ service->GetExtensionEventRouter()->SetUiEnabled(extension, enabled);
+ }
+ if (incognito_service) {
+ incognito_service->GetExtensionEventRouter()->SetUiEnabled(extension,
+ enabled);
+ }
+}
+
DownloadItem* GetDownload(content::BrowserContext* context,
bool include_incognito,
int id) {
@@ -490,6 +530,7 @@ enum DownloadsFunctionName {
DOWNLOADS_FUNCTION_SHOW_DEFAULT_FOLDER = 13,
DOWNLOADS_FUNCTION_SET_SHELF_ENABLED = 14,
DOWNLOADS_FUNCTION_DETERMINE_FILENAME = 15,
+ DOWNLOADS_FUNCTION_SET_UI_OPTIONS = 16,
// Insert new values here, not at the beginning.
DOWNLOADS_FUNCTION_LAST
};
@@ -1462,48 +1503,105 @@ ExtensionFunction::ResponseAction DownloadsSetShelfEnabledFunction::Run() {
}
RecordApiFunctions(DOWNLOADS_FUNCTION_SET_SHELF_ENABLED);
- DownloadManager* manager = NULL;
- DownloadManager* incognito_manager = NULL;
- GetManagers(browser_context(), include_incognito_information(), &manager,
- &incognito_manager);
- DownloadCoreService* service = NULL;
- DownloadCoreService* incognito_service = NULL;
- if (manager) {
- service = DownloadCoreServiceFactory::GetForBrowserContext(
- manager->GetBrowserContext());
- service->GetExtensionEventRouter()->SetShelfEnabled(extension(),
- params->enabled);
- }
- if (incognito_manager) {
- incognito_service = DownloadCoreServiceFactory::GetForBrowserContext(
- incognito_manager->GetBrowserContext());
- incognito_service->GetExtensionEventRouter()->SetShelfEnabled(
- extension(), params->enabled);
- }
+ DownloadCoreService* service = nullptr;
+ DownloadCoreService* incognito_service = nullptr;
+ GetDownloadCoreServices(browser_context(), include_incognito_information(),
+ &service, &incognito_service);
+
+ MaybeSetUiEnabled(service, incognito_service, extension(), params->enabled);
+
+ bool is_bubble_enabled = download::IsDownloadBubbleEnabled(
+ Profile::FromBrowserContext(browser_context()));
BrowserList* browsers = BrowserList::GetInstance();
if (browsers) {
- for (auto iter = browsers->begin(); iter != browsers->end(); ++iter) {
- const Browser* browser = *iter;
+ for (auto* browser : *browsers) {
DownloadCoreService* current_service =
DownloadCoreServiceFactory::GetForBrowserContext(browser->profile());
- if (((current_service == service) ||
- (current_service == incognito_service)) &&
- browser->window()->IsDownloadShelfVisible() &&
- !current_service->IsShelfEnabled())
+ // The following code is to hide the download UI explicitly if the UI is
+ // set to disabled.
+ bool match_current_service = (current_service == service) ||
+ (current_service == incognito_service);
+ if (!match_current_service || current_service->IsDownloadUiEnabled()) {
+ continue;
+ }
+ // Calling this API affects the download bubble as well, so extensions
+ // using this API is still compatible with the new download bubble. This
+ // API will eventually be deprecated (replaced by the SetUiOptions API
+ // below).
+ if (is_bubble_enabled &&
+ browser->window()->GetDownloadBubbleUIController()) {
+ browser->window()->GetDownloadBubbleUIController()->HideDownloadUi();
+ } else if (browser->window()->IsDownloadShelfVisible()) {
browser->window()->GetDownloadShelf()->Close();
+ }
}
}
if (params->enabled &&
- ((manager && !service->IsShelfEnabled()) ||
- (incognito_manager && !incognito_service->IsShelfEnabled()))) {
+ ((service && !service->IsDownloadUiEnabled()) ||
+ (incognito_service && !incognito_service->IsDownloadUiEnabled()))) {
return RespondNow(Error(download_extension_errors::kShelfDisabled));
}
return RespondNow(NoArguments());
}
+DownloadsSetUiOptionsFunction::DownloadsSetUiOptionsFunction() = default;
+
+DownloadsSetUiOptionsFunction::~DownloadsSetUiOptionsFunction() = default;
+
+ExtensionFunction::ResponseAction DownloadsSetUiOptionsFunction::Run() {
+ std::unique_ptr<downloads::SetUiOptions::Params> params(
+ downloads::SetUiOptions::Params::Create(args()));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+ const downloads::UiOptions& options = params->options;
+ if (!extension()->permissions_data()->HasAPIPermission(
+ APIPermissionID::kDownloadsUi)) {
+ return RespondNow(Error(download_extension_errors::kUiPermission));
+ }
+
+ RecordApiFunctions(DOWNLOADS_FUNCTION_SET_UI_OPTIONS);
+ DownloadCoreService* service = nullptr;
+ DownloadCoreService* incognito_service = nullptr;
+ GetDownloadCoreServices(browser_context(), include_incognito_information(),
+ &service, &incognito_service);
+
+ MaybeSetUiEnabled(service, incognito_service, extension(), options.enabled);
+
+ bool is_bubble_enabled = download::IsDownloadBubbleEnabled(
+ Profile::FromBrowserContext(browser_context()));
+
+ BrowserList* browsers = BrowserList::GetInstance();
+ if (browsers) {
+ for (auto* browser : *browsers) {
+ DownloadCoreService* current_service =
+ DownloadCoreServiceFactory::GetForBrowserContext(browser->profile());
+ // The following code is to hide the download UI explicitly if the UI is
+ // set to disabled.
+ bool match_current_service = (current_service == service) ||
+ (current_service == incognito_service);
+ if (!match_current_service || current_service->IsDownloadUiEnabled()) {
+ continue;
+ }
+ if (is_bubble_enabled &&
+ browser->window()->GetDownloadBubbleUIController()) {
+ browser->window()->GetDownloadBubbleUIController()->HideDownloadUi();
+ } else if (browser->window()->IsDownloadShelfVisible()) {
+ browser->window()->GetDownloadShelf()->Close();
+ }
+ }
+ }
+
+ if (options.enabled &&
+ ((service && !service->IsDownloadUiEnabled()) ||
+ (incognito_service && !incognito_service->IsDownloadUiEnabled()))) {
+ return RespondNow(Error(download_extension_errors::kUiDisabled));
+ }
+
+ return RespondNow(NoArguments());
+}
+
DownloadsGetFileIconFunction::DownloadsGetFileIconFunction()
: icon_extractor_(new DownloadFileIconExtractorImpl()) {}
@@ -1583,19 +1681,24 @@ void ExtensionDownloadsEventRouter::
SetDetermineFilenameTimeoutSecondsForTesting(s);
}
-void ExtensionDownloadsEventRouter::SetShelfEnabled(const Extension* extension,
- bool enabled) {
- auto iter = shelf_disabling_extensions_.find(extension);
- if (iter == shelf_disabling_extensions_.end()) {
+void ExtensionDownloadsEventRouter::SetUiEnabled(const Extension* extension,
+ bool enabled) {
+ auto iter = ui_disabling_extensions_.find(extension);
+ if (iter == ui_disabling_extensions_.end()) {
if (!enabled)
- shelf_disabling_extensions_.insert(extension);
+ ui_disabling_extensions_.insert(extension);
} else if (enabled) {
- shelf_disabling_extensions_.erase(extension);
+ ui_disabling_extensions_.erase(extension);
}
}
-bool ExtensionDownloadsEventRouter::IsShelfEnabled() const {
- return shelf_disabling_extensions_.empty();
+bool ExtensionDownloadsEventRouter::IsUiEnabled() const {
+ return ui_disabling_extensions_.empty();
+}
+
+bool ExtensionDownloadsEventRouter::IsDownloadObservedByExtension() const {
+ EventRouter* router = EventRouter::Get(profile_);
+ return router && router->HasEventListener(downloads::OnChanged::kEventName);
}
// The method by which extensions hook into the filename determination process
@@ -1910,8 +2013,8 @@ void ExtensionDownloadsEventRouter::DispatchEvent(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!EventRouter::Get(profile_))
return;
- std::vector<base::Value> args;
- args.push_back(std::move(arg));
+ base::Value::List args;
+ args.Append(std::move(arg));
// The downloads system wants to share on-record events with off-record
// extension renderers even in incognito_split_mode because that's how
// chrome://downloads works. The "restrict_to_profile" mechanism does not
@@ -1936,9 +2039,9 @@ void ExtensionDownloadsEventRouter::OnExtensionUnloaded(
const Extension* extension,
UnloadedExtensionReason reason) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- auto iter = shelf_disabling_extensions_.find(extension);
- if (iter != shelf_disabling_extensions_.end())
- shelf_disabling_extensions_.erase(iter);
+ auto iter = ui_disabling_extensions_.find(extension);
+ if (iter != ui_disabling_extensions_.end())
+ ui_disabling_extensions_.erase(iter);
}
void ExtensionDownloadsEventRouter::CheckForHistoryFilesRemoval() {
diff --git a/chromium/chrome/browser/extensions/api/downloads/downloads_api.h b/chromium/chrome/browser/extensions/api/downloads/downloads_api.h
index 994116d8716..3aef44c043d 100644
--- a/chromium/chrome/browser/extensions/api/downloads/downloads_api.h
+++ b/chromium/chrome/browser/extensions/api/downloads/downloads_api.h
@@ -59,6 +59,8 @@ extern const char kOpenPermission[];
extern const char kShelfDisabled[];
extern const char kShelfPermission[];
extern const char kTooManyListeners[];
+extern const char kUiDisabled[];
+extern const char kUiPermission[];
extern const char kUnexpectedDeterminer[];
extern const char kUserGesture[];
@@ -299,6 +301,21 @@ class DownloadsSetShelfEnabledFunction : public ExtensionFunction {
~DownloadsSetShelfEnabledFunction() override;
};
+class DownloadsSetUiOptionsFunction : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("downloads.setUiOptions", DOWNLOADS_SETUIOPTIONS)
+ DownloadsSetUiOptionsFunction();
+
+ DownloadsSetUiOptionsFunction(const DownloadsSetUiOptionsFunction&) = delete;
+ DownloadsSetUiOptionsFunction& operator=(
+ const DownloadsSetUiOptionsFunction&) = delete;
+
+ ResponseAction Run() override;
+
+ protected:
+ ~DownloadsSetUiOptionsFunction() override;
+};
+
class DownloadsGetFileIconFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.getFileIcon", DOWNLOADS_GETFILEICON)
@@ -373,8 +390,10 @@ class ExtensionDownloadsEventRouter
~ExtensionDownloadsEventRouter() override;
- void SetShelfEnabled(const extensions::Extension* extension, bool enabled);
- bool IsShelfEnabled() const;
+ void SetUiEnabled(const extensions::Extension* extension, bool enabled);
+ bool IsUiEnabled() const;
+
+ bool IsDownloadObservedByExtension() const;
// Called by ChromeDownloadManagerDelegate during the filename determination
// process, allows extensions to change the item's target filename. If no
@@ -415,7 +434,7 @@ class ExtensionDownloadsEventRouter
raw_ptr<Profile> profile_;
download::AllDownloadItemNotifier notifier_;
- std::set<const extensions::Extension*> shelf_disabling_extensions_;
+ std::set<const extensions::Extension*> ui_disabling_extensions_;
base::Time last_checked_removal_;
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 65b3ff5b730..8c94fbb4dfd 100644
--- a/chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -28,6 +28,9 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "chrome/browser/download/bubble/download_bubble_controller.h"
+#include "chrome/browser/download/bubble/download_display.h"
+#include "chrome/browser/download/bubble/download_display_controller.h"
#include "chrome/browser/download/download_core_service.h"
#include "chrome/browser/download/download_core_service_factory.h"
#include "chrome/browser/download/download_file_icon_extractor.h"
@@ -41,6 +44,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/extensions/extension_action_test_helper.h"
#include "chrome/common/extensions/api/downloads.h"
#include "chrome/common/pref_names.h"
@@ -48,6 +52,8 @@
#include "chrome/test/base/ui_test_utils.h"
#include "components/download/public/common/download_item.h"
#include "components/prefs/pref_service.h"
+#include "components/safe_browsing/content/common/file_type_policies_test_util.h"
+#include "components/safe_browsing/core/common/features.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
@@ -208,7 +214,8 @@ class DownloadsEventsListener : public EventRouter::TestObserver {
Event* new_event = new Event(
Profile::FromBrowserContext(event.restrict_to_browser_context),
- event.event_name, *event.event_args.get(), base::Time::Now());
+ event.event_name, base::Value(event.event_args.Clone()),
+ base::Time::Now());
events_.push_back(base::WrapUnique(new_event));
if (waiting_ && waiting_for_.get() && new_event->Satisfies(*waiting_for_)) {
waiting_ = false;
@@ -332,30 +339,11 @@ class DownloadExtensionTest : public ExtensionApiTest {
};
void LoadExtension(const char* name, bool enable_file_access = false) {
- // Store the created Extension object so that we can attach it to
- // ExtensionFunctions. Also load the extension in incognito profiles for
- // testing incognito.
- extension_ = ExtensionBrowserTest::LoadExtension(
- test_data_dir_.AppendASCII(name),
- {.allow_in_incognito = true, .allow_file_access = enable_file_access});
- CHECK(extension_);
- content::WebContents* tab = chrome::AddSelectedTabWithURL(
- current_browser(),
- extension_->GetResourceURL("empty.html"),
- ui::PAGE_TRANSITION_LINK);
- EXPECT_TRUE(content::WaitForLoadStop(tab));
- EventRouter::Get(current_browser()->profile())
- ->AddEventListener(downloads::OnCreated::kEventName,
- tab->GetPrimaryMainFrame()->GetProcess(),
- GetExtensionId());
- EventRouter::Get(current_browser()->profile())
- ->AddEventListener(downloads::OnChanged::kEventName,
- tab->GetPrimaryMainFrame()->GetProcess(),
- GetExtensionId());
- EventRouter::Get(current_browser()->profile())
- ->AddEventListener(downloads::OnErased::kEventName,
- tab->GetPrimaryMainFrame()->GetProcess(),
- GetExtensionId());
+ extension_ = LoadExtensionInternal(name, enable_file_access);
+ }
+
+ void LoadSecondExtension(const char* name) {
+ second_extension_ = LoadExtensionInternal(name, false);
}
content::RenderProcessHost* AddFilenameDeterminer() {
@@ -468,6 +456,7 @@ class DownloadExtensionTest : public ExtensionApiTest {
std::string GetExtensionId() {
return extension_->id();
}
+ std::string GetSecondExtensionId() { return second_extension_->id(); }
std::string GetFilename(const char* path) {
std::string result = downloads_directory().AppendASCII(path).AsUTF8Unsafe();
@@ -626,14 +615,12 @@ class DownloadExtensionTest : public ExtensionApiTest {
}
bool RunFunction(ExtensionFunction* function, const std::string& args) {
- scoped_refptr<ExtensionFunction> delete_function(function);
- SetUpExtensionFunction(function);
- bool result = extension_function_test_utils::RunFunction(
- function, args, current_browser(), GetFlags());
- if (!result) {
- LOG(ERROR) << function->GetError();
- }
- return result;
+ return RunFunctionInternal(extension_, function, args);
+ }
+
+ bool RunFunctionInSecondExtension(ExtensionFunction* function,
+ const std::string& args) {
+ return RunFunctionInternal(second_extension_, function, args);
}
api_test_utils::RunFunctionFlags GetFlags() {
@@ -649,7 +636,7 @@ class DownloadExtensionTest : public ExtensionApiTest {
std::unique_ptr<base::Value> RunFunctionAndReturnResult(
scoped_refptr<ExtensionFunction> function,
const std::string& args) {
- SetUpExtensionFunction(function.get());
+ SetUpExtensionFunction(extension_, function.get());
return extension_function_test_utils::RunFunctionAndReturnSingleResult(
function.get(), args, current_browser(), GetFlags());
}
@@ -657,7 +644,15 @@ class DownloadExtensionTest : public ExtensionApiTest {
std::string RunFunctionAndReturnError(
scoped_refptr<ExtensionFunction> function,
const std::string& args) {
- SetUpExtensionFunction(function.get());
+ SetUpExtensionFunction(extension_, function.get());
+ return extension_function_test_utils::RunFunctionAndReturnError(
+ function.get(), args, current_browser(), GetFlags());
+ }
+
+ std::string RunFunctionAndReturnErrorInSecondExtension(
+ scoped_refptr<ExtensionFunction> function,
+ const std::string& args) {
+ SetUpExtensionFunction(second_extension_, function.get());
return extension_function_test_utils::RunFunctionAndReturnError(
function.get(), args, current_browser(), GetFlags());
}
@@ -665,7 +660,7 @@ class DownloadExtensionTest : public ExtensionApiTest {
bool RunFunctionAndReturnString(scoped_refptr<ExtensionFunction> function,
const std::string& args,
std::string* result_string) {
- SetUpExtensionFunction(function.get());
+ SetUpExtensionFunction(extension_, function.get());
std::unique_ptr<base::Value> result(
RunFunctionAndReturnResult(function, args));
EXPECT_TRUE(result.get());
@@ -689,12 +684,13 @@ class DownloadExtensionTest : public ExtensionApiTest {
const Extension* extension() { return extension_; }
private:
- void SetUpExtensionFunction(ExtensionFunction* function) {
- if (extension_) {
+ void SetUpExtensionFunction(const raw_ptr<const Extension>& extension,
+ ExtensionFunction* function) {
+ if (extension) {
const GURL url = current_browser_ == incognito_browser_ &&
- !IncognitoInfo::IsSplitMode(extension_)
+ !IncognitoInfo::IsSplitMode(extension)
? GURL(url::kAboutBlankURL)
- : extension_->GetResourceURL("empty.html");
+ : extension->GetResourceURL("empty.html");
// Watch and wait for the navigation to take place.
auto observer = std::make_unique<content::TestNavigationObserver>(url);
observer->WatchExistingWebContents();
@@ -703,14 +699,56 @@ class DownloadExtensionTest : public ExtensionApiTest {
content::WebContents* tab = chrome::AddSelectedTabWithURL(
current_browser(), url, ui::PAGE_TRANSITION_LINK);
observer->WaitForNavigationFinished();
- function->set_extension(extension_.get());
+ function->set_extension(extension.get());
function->SetRenderFrameHost(tab->GetPrimaryMainFrame());
function->set_source_process_id(
tab->GetPrimaryMainFrame()->GetProcess()->GetID());
}
}
+ bool RunFunctionInternal(const raw_ptr<const Extension>& extension,
+ ExtensionFunction* function,
+ const std::string& args) {
+ scoped_refptr<ExtensionFunction> delete_function(function);
+ SetUpExtensionFunction(extension, function);
+ bool result = extension_function_test_utils::RunFunction(
+ function, args, current_browser(), GetFlags());
+ if (!result) {
+ LOG(ERROR) << function->GetError();
+ }
+ return result;
+ }
+
+ raw_ptr<const Extension> LoadExtensionInternal(const char* name,
+ bool enable_file_access) {
+ // Store the created Extension object so that we can attach it to
+ // ExtensionFunctions. Also load the extension in incognito profiles for
+ // testing incognito.
+ raw_ptr<const Extension> extension = ExtensionBrowserTest::LoadExtension(
+ test_data_dir_.AppendASCII(name),
+ {.allow_in_incognito = true, .allow_file_access = enable_file_access});
+ CHECK(extension);
+ content::WebContents* tab = chrome::AddSelectedTabWithURL(
+ current_browser(), extension->GetResourceURL("empty.html"),
+ ui::PAGE_TRANSITION_LINK);
+ EXPECT_TRUE(content::WaitForLoadStop(tab));
+ EventRouter::Get(current_browser()->profile())
+ ->AddEventListener(downloads::OnCreated::kEventName,
+ tab->GetPrimaryMainFrame()->GetProcess(),
+ extension->id());
+ EventRouter::Get(current_browser()->profile())
+ ->AddEventListener(downloads::OnChanged::kEventName,
+ tab->GetPrimaryMainFrame()->GetProcess(),
+ extension->id());
+ EventRouter::Get(current_browser()->profile())
+ ->AddEventListener(downloads::OnErased::kEventName,
+ tab->GetPrimaryMainFrame()->GetProcess(),
+ extension->id());
+ return extension;
+ }
+
raw_ptr<const Extension> extension_;
+ raw_ptr<const Extension> second_extension_;
raw_ptr<Browser> incognito_browser_;
raw_ptr<Browser> current_browser_;
std::unique_ptr<DownloadsEventsListener> events_listener_;
@@ -1852,7 +1890,7 @@ class CustomResponse : public net::test_server::HttpResponse {
void SendResponse(
base::WeakPtr<net::test_server::HttpResponseDelegate> delegate) override {
base::StringPairs headers = {
- //"HTTP/1.1 200 OK\r\n"
+ // "HTTP/1.1 200 OK\r\n"
{"Content-type", "application/octet-stream"},
{"Cache-Control", "max-age=0"},
};
@@ -1967,6 +2005,7 @@ IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
"hOsT",
"kEEp-aLivE",
"rEfErEr",
+ "sEt-cOoKiE",
"tE",
"trAilER",
"trANsfer-eNcodiNg",
@@ -3194,6 +3233,9 @@ IN_PROC_BROWSER_TEST_F(
IN_PROC_BROWSER_TEST_F(
DownloadExtensionTest,
DownloadExtensionTest_OnDeterminingFilename_SafeOverride) {
+ safe_browsing::FileTypePoliciesTestOverlay scoped_dangerous =
+ safe_browsing::ScopedMarkAllFilesDangerousForTesting();
+
GoOnTheRecord();
LoadExtension("downloads_split");
AddFilenameDeterminer();
@@ -4574,17 +4616,13 @@ IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
EXPECT_TRUE(RunFunction(new DownloadsSetShelfEnabledFunction(), "[false]"));
EXPECT_FALSE(DownloadCoreServiceFactory::GetForBrowserContext(
current_browser()->profile())
- ->IsShelfEnabled());
+ ->IsDownloadUiEnabled());
EXPECT_TRUE(RunFunction(new DownloadsSetShelfEnabledFunction(), "[true]"));
EXPECT_TRUE(DownloadCoreServiceFactory::GetForBrowserContext(
current_browser()->profile())
- ->IsShelfEnabled());
- // TODO(benjhayden) Test that existing shelves are hidden.
- // TODO(benjhayden) Test multiple extensions.
- // TODO(benjhayden) Test disabling extensions.
+ ->IsDownloadUiEnabled());
// TODO(benjhayden) Test that browsers associated with other profiles are not
// affected.
- // TODO(benjhayden) Test incognito.
}
// TODO(benjhayden) Figure out why DisableExtension() does not fire
@@ -4593,6 +4631,21 @@ IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
// TODO(benjhayden) Test that the shelf is shown for download() both with and
// without a WebContents.
+IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
+ DownloadExtensionTest_SetUiOptions) {
+ LoadExtension("downloads_split");
+ EXPECT_TRUE(RunFunction(new DownloadsSetUiOptionsFunction(),
+ R"([{"enabled": false}])"));
+ EXPECT_FALSE(DownloadCoreServiceFactory::GetForBrowserContext(
+ current_browser()->profile())
+ ->IsDownloadUiEnabled());
+ EXPECT_TRUE(RunFunction(new DownloadsSetUiOptionsFunction(),
+ R"([{"enabled": true}])"));
+ EXPECT_TRUE(DownloadCoreServiceFactory::GetForBrowserContext(
+ current_browser()->profile())
+ ->IsDownloadUiEnabled());
+}
+
void OnDangerPromptCreated(DownloadDangerPrompt* prompt) {
prompt->InvokeActionForTesting(DownloadDangerPrompt::ACCEPT);
}
@@ -4608,6 +4661,9 @@ void OnDangerPromptCreated(DownloadDangerPrompt* prompt) {
#endif
IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
MAYBE_DownloadExtensionTest_AcceptDanger) {
+ safe_browsing::FileTypePoliciesTestOverlay scoped_dangerous =
+ safe_browsing::ScopedMarkAllFilesDangerousForTesting();
+
// Download a file that will be marked dangerous; click the browser action
// button; the browser action poup will call acceptDanger(); when the
// DownloadDangerPrompt is created, pretend that the user clicks the Accept
@@ -4697,6 +4753,141 @@ IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
result_id)));
}
+// The DownloadExtensionBubbleEnabledTest relies on the download surface, which
+// ChromeOS_ASH doesn't use (see crbug.com/1323505).
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+class DownloadExtensionBubbleEnabledTest : public DownloadExtensionTest {
+ public:
+ DownloadExtensionBubbleEnabledTest() {
+ feature_list_.InitAndEnableFeature(safe_browsing::kDownloadBubble);
+ }
+
+ DownloadDisplay* GetDownloadToolbarButton() {
+ return current_browser()
+ ->window()
+ ->GetDownloadBubbleUIController()
+ ->GetDownloadDisplayController()
+ ->download_display_for_testing();
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(DownloadExtensionBubbleEnabledTest,
+ DownloadExtensionBubbleEnabledTest_SetUiOptions) {
+ DownloadManager::DownloadVector items;
+ CreateTwoDownloads(&items);
+ ScopedItemVectorCanceller delete_items(&items);
+ LoadExtension("downloads_split");
+
+ EXPECT_TRUE(RunFunction(new DownloadsSetUiOptionsFunction(),
+ R"([{"enabled": true}])"));
+ EXPECT_TRUE(GetDownloadToolbarButton()->IsShowing());
+
+ EXPECT_TRUE(RunFunction(new DownloadsSetUiOptionsFunction(),
+ R"([{"enabled": false}])"));
+ EXPECT_FALSE(GetDownloadToolbarButton()->IsShowing());
+
+ items[0]->Cancel(true);
+ // Remain hidden on download updates.
+ EXPECT_FALSE(GetDownloadToolbarButton()->IsShowing());
+}
+
+IN_PROC_BROWSER_TEST_F(
+ DownloadExtensionBubbleEnabledTest,
+ DownloadExtensionBubbleEnabledTest_SetUiOptionsBeforeDownloadStart) {
+ LoadExtension("downloads_split");
+ EXPECT_TRUE(RunFunction(new DownloadsSetUiOptionsFunction(),
+ R"([{"enabled": false}])"));
+ DownloadManager::DownloadVector items;
+ CreateTwoDownloads(&items);
+ ScopedItemVectorCanceller delete_items(&items);
+ EXPECT_FALSE(GetDownloadToolbarButton()->IsShowing());
+}
+
+IN_PROC_BROWSER_TEST_F(
+ DownloadExtensionBubbleEnabledTest,
+ DownloadExtensionBubbleEnabledTest_SetUiOptionsShowDetails) {
+ LoadExtension("downloads_split");
+ DownloadManager::DownloadVector items;
+ CreateTwoDownloads(&items);
+ ScopedItemVectorCanceller delete_items(&items);
+
+ EXPECT_TRUE(GetDownloadToolbarButton()->IsShowing());
+ // Details are not shown because the download item is observed by an
+ // extension.
+ EXPECT_FALSE(GetDownloadToolbarButton()->IsShowingDetails());
+
+ items[0]->Cancel(true);
+ EXPECT_TRUE(GetDownloadToolbarButton()->IsShowing());
+ // Details are not shown because the download item is observed by an
+ // extension.
+ EXPECT_FALSE(GetDownloadToolbarButton()->IsShowingDetails());
+
+ DisableExtension(GetExtensionId());
+ items[1]->Cancel(true);
+ EXPECT_TRUE(GetDownloadToolbarButton()->IsShowing());
+ // Details are shown because the extension is disabled.
+ EXPECT_TRUE(GetDownloadToolbarButton()->IsShowingDetails());
+}
+
+IN_PROC_BROWSER_TEST_F(
+ DownloadExtensionBubbleEnabledTest,
+ DownloadExtensionBubbleEnabledTest_SetUiOptionsOffTheRecord) {
+ LoadExtension("downloads_split");
+ EXPECT_TRUE(RunFunction(new DownloadsSetUiOptionsFunction(),
+ R"([{"enabled": false}])"));
+ DownloadManager::DownloadVector items;
+ CreateTwoDownloads(&items);
+ ScopedItemVectorCanceller delete_items(&items);
+ EXPECT_FALSE(GetDownloadToolbarButton()->IsShowing());
+
+ GoOffTheRecord();
+ EXPECT_FALSE(GetDownloadToolbarButton()->IsShowing());
+
+ EXPECT_TRUE(RunFunction(new DownloadsSetUiOptionsFunction(),
+ R"([{"enabled": true}])"));
+ items[0]->Cancel(true);
+ EXPECT_TRUE(GetDownloadToolbarButton()->IsShowing());
+
+ GoOnTheRecord();
+ EXPECT_TRUE(GetDownloadToolbarButton()->IsShowing());
+}
+
+IN_PROC_BROWSER_TEST_F(
+ DownloadExtensionBubbleEnabledTest,
+ DownloadExtensionBubbleEnabledTest_SetUiOptionsMultipleExtensions) {
+ LoadExtension("downloads_split");
+ EXPECT_TRUE(RunFunction(new DownloadsSetUiOptionsFunction(),
+ R"([{"enabled": false}])"));
+ DownloadManager::DownloadVector items;
+ CreateTwoDownloads(&items);
+ ScopedItemVectorCanceller delete_items(&items);
+ EXPECT_FALSE(GetDownloadToolbarButton()->IsShowing());
+
+ LoadSecondExtension("downloads_spanning");
+ // Returns error because the first extension has disabled the UI.
+ EXPECT_STREQ(errors::kUiDisabled, RunFunctionAndReturnErrorInSecondExtension(
+ new DownloadsSetUiOptionsFunction(),
+ R"([{"enabled": true}])")
+ .c_str());
+ // Two extensions can set the UI to disabled at the same time. No error should
+ // be returned.
+ EXPECT_TRUE(RunFunctionInSecondExtension(new DownloadsSetUiOptionsFunction(),
+ R"([{"enabled": false}])"));
+
+ DisableExtension(GetExtensionId());
+ items[0]->Pause();
+ // The UI keeps disabled because the second extension has set it to disabled.
+ EXPECT_FALSE(GetDownloadToolbarButton()->IsShowing());
+
+ DisableExtension(GetSecondExtensionId());
+ items[0]->Cancel(true);
+ EXPECT_TRUE(GetDownloadToolbarButton()->IsShowing());
+}
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
+
class DownloadsApiTest : public ExtensionApiTest {
public:
DownloadsApiTest() {}
diff --git a/chromium/chrome/browser/extensions/api/enterprise_device_attributes/DIR_METADATA b/chromium/chrome/browser/extensions/api/enterprise_device_attributes/DIR_METADATA
index 07b250ad60f..fa5cbf478ce 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_device_attributes/DIR_METADATA
+++ b/chromium/chrome/browser/extensions/api/enterprise_device_attributes/DIR_METADATA
@@ -1,3 +1,3 @@
-monorail {
- component: "OS>Software>Enterprise"
+buganizer: {
+ component_id: 620570
}
diff --git a/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc b/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
index e74209d89f9..6d7f4bef40b 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
@@ -11,7 +11,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.h"
#include "chrome/browser/extensions/extension_apitest.h"
-#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
#include "chromeos/system/fake_statistics_provider.h"
#include "chromeos/system/statistics_provider.h"
#include "components/user_manager/user_manager.h"
@@ -83,9 +83,9 @@ class EnterpriseDeviceAttributesTest
proto->set_device_hostname_template(kHostname);
device_policy->Build();
- chromeos::FakeSessionManagerClient::Get()->set_device_policy(
+ ash::FakeSessionManagerClient::Get()->set_device_policy(
device_policy->GetBlob());
- chromeos::FakeSessionManagerClient::Get()->OnPropertyChangeComplete(true);
+ ash::FakeSessionManagerClient::Get()->OnPropertyChangeComplete(true);
}
private:
diff --git a/chromium/chrome/browser/extensions/api/enterprise_networking_attributes/enterprise_networking_attributes_ash_apitest.cc b/chromium/chrome/browser/extensions/api/enterprise_networking_attributes/enterprise_networking_attributes_ash_apitest.cc
index e10c67337c9..dc9aa25776c 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_networking_attributes/enterprise_networking_attributes_ash_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_networking_attributes/enterprise_networking_attributes_ash_apitest.cc
@@ -10,10 +10,10 @@
#include "chrome/browser/ash/policy/affiliation/affiliation_test_helper.h"
#include "chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.h"
#include "chrome/browser/extensions/extension_apitest.h"
-#include "chromeos/dbus/shill/shill_device_client.h"
-#include "chromeos/dbus/shill/shill_ipconfig_client.h"
-#include "chromeos/dbus/shill/shill_profile_client.h"
-#include "chromeos/dbus/shill/shill_service_client.h"
+#include "chromeos/ash/components/dbus/shill/shill_device_client.h"
+#include "chromeos/ash/components/dbus/shill/shill_ipconfig_client.h"
+#include "chromeos/ash/components/dbus/shill/shill_profile_client.h"
+#include "chromeos/ash/components/dbus/shill/shill_service_client.h"
#include "content/public/test/browser_test.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
#include "url/gurl.h"
@@ -77,14 +77,14 @@ class EnterpriseNetworkingAttributesTest
std::get<1>(GetParam())) {}
void SetupDisconnectedNetwork() {
- chromeos::ShillDeviceClient::TestInterface* shill_device_client =
- chromeos::ShillDeviceClient::Get()->GetTestInterface();
- chromeos::ShillIPConfigClient::TestInterface* shill_ipconfig_client =
- chromeos::ShillIPConfigClient::Get()->GetTestInterface();
- chromeos::ShillServiceClient::TestInterface* shill_service_client =
- chromeos::ShillServiceClient::Get()->GetTestInterface();
- chromeos::ShillProfileClient::TestInterface* shill_profile_client =
- chromeos::ShillProfileClient::Get()->GetTestInterface();
+ ash::ShillDeviceClient::TestInterface* shill_device_client =
+ ash::ShillDeviceClient::Get()->GetTestInterface();
+ ash::ShillIPConfigClient::TestInterface* shill_ipconfig_client =
+ ash::ShillIPConfigClient::Get()->GetTestInterface();
+ ash::ShillServiceClient::TestInterface* shill_service_client =
+ ash::ShillServiceClient::Get()->GetTestInterface();
+ ash::ShillProfileClient::TestInterface* shill_profile_client =
+ ash::ShillProfileClient::Get()->GetTestInterface();
shill_service_client->ClearServices();
shill_device_client->ClearDevices();
@@ -125,14 +125,14 @@ class EnterpriseNetworkingAttributesTest
kWifiServicePath, shill::kConnectableProperty, base::Value(true));
shill_profile_client->AddService(
- chromeos::ShillProfileClient::GetSharedProfilePath(), kWifiServicePath);
+ ash::ShillProfileClient::GetSharedProfilePath(), kWifiServicePath);
base::RunLoop().RunUntilIdle();
}
void ConnectNetwork() {
- chromeos::ShillServiceClient::TestInterface* shill_service_client =
- chromeos::ShillServiceClient::Get()->GetTestInterface();
+ ash::ShillServiceClient::TestInterface* shill_service_client =
+ ash::ShillServiceClient::Get()->GetTestInterface();
shill_service_client->SetServiceProperty(kWifiServicePath,
shill::kStateProperty,
base::Value(shill::kStateOnline));
diff --git a/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc b/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
index 4b40d6e437e..b922e5144f0 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
@@ -132,13 +132,10 @@ bool IsExtensionAllowed(Profile* profile, const Extension* extension) {
// allowed in chrome/common/extensions/api/_permission_features.json
return true;
}
- const base::Value* list =
- profile->GetPrefs()->GetList(prefs::kAttestationExtensionAllowlist);
- DCHECK_NE(list, nullptr);
+ const base::Value::List& list =
+ profile->GetPrefs()->GetValueList(prefs::kAttestationExtensionAllowlist);
base::Value value(extension->id());
- return std::find(list->GetListDeprecated().begin(),
- list->GetListDeprecated().end(),
- value) != list->GetListDeprecated().end();
+ return base::Contains(list, value);
}
} // namespace platform_keys
@@ -250,8 +247,8 @@ void EnterprisePlatformKeysGetCertificatesFunction::OnGetCertificates(
client_certs.Append(base::Value(std::move(cert)));
}
- std::vector<base::Value> results;
- results.emplace_back(std::move(client_certs));
+ base::Value::List results;
+ results.Append(std::move(client_certs));
Respond(ArgumentList(std::move(results)));
}
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 c22d9b597ce..f8f6bdaae70 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
@@ -39,14 +39,13 @@ namespace {
const char kUserEmail[] = "test@google.com";
-void FakeRunCheckNotRegister(
- chromeos::attestation::AttestationKeyType key_type,
- Profile* profile,
- ash::attestation::TpmChallengeKeyCallback callback,
- const std::string& challenge,
- bool register_key,
- const std::string& key_name_for_spkac,
- const absl::optional<::attestation::DeviceTrustSignals>& signals) {
+void FakeRunCheckNotRegister(chromeos::attestation::AttestationKeyType key_type,
+ Profile* profile,
+ ash::attestation::TpmChallengeKeyCallback callback,
+ const std::string& challenge,
+ bool register_key,
+ const std::string& key_name_for_spkac,
+ const absl::optional<std::string>& signals) {
EXPECT_FALSE(register_key);
std::move(callback).Run(
ash::attestation::TpmChallengeKeyResult::MakeChallengeResponse(
diff --git a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/DEPS b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/DEPS
new file mode 100644
index 00000000000..3023fa83c91
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/device_signals/core",
+]
diff --git a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.cc b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.cc
new file mode 100644
index 00000000000..25798a6b8e3
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.cc
@@ -0,0 +1,218 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.h"
+
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
+#include <memory>
+#include <utility>
+
+#include "base/base64url.h"
+#include "base/files/file_path.h"
+#include "components/device_signals/core/browser/signals_types.h"
+#include "components/device_signals/core/common/common_types.h"
+#include "extensions/browser/extension_function.h"
+
+#if BUILDFLAG(IS_WIN)
+#include "base/strings/sys_string_conversions.h"
+#include "components/device_signals/core/common/win/win_types.h"
+#endif // BUILDFLAG(IS_WIN)
+
+using SignalCollectionError = device_signals::SignalCollectionError;
+using PresenceValue = device_signals::PresenceValue;
+
+namespace extensions {
+
+namespace {
+
+absl::optional<ParsedSignalsError> TryParseError(
+ const device_signals::SignalsAggregationResponse& response,
+ const absl::optional<device_signals::BaseSignalResponse>& bundle) {
+ absl::optional<std::string> error_string;
+ if (response.top_level_error) {
+ return ParsedSignalsError{response.top_level_error.value(),
+ /*is_top_level_error=*/true};
+ }
+
+ if (!bundle) {
+ return ParsedSignalsError{SignalCollectionError::kMissingBundle,
+ /*is_top_level_error=*/false};
+ }
+
+ if (bundle->collection_error) {
+ return ParsedSignalsError{bundle->collection_error.value(),
+ /*is_top_level_error=*/false};
+ }
+
+ return absl::nullopt;
+}
+
+api::enterprise_reporting_private::PresenceValue ConvertPresenceValue(
+ PresenceValue presence) {
+ switch (presence) {
+ case PresenceValue::kUnspecified:
+ return api::enterprise_reporting_private::PRESENCE_VALUE_UNSPECIFIED;
+ case PresenceValue::kAccessDenied:
+ return api::enterprise_reporting_private::PRESENCE_VALUE_ACCESS_DENIED;
+ case PresenceValue::kNotFound:
+ return api::enterprise_reporting_private::PRESENCE_VALUE_NOT_FOUND;
+ case PresenceValue::kFound:
+ return api::enterprise_reporting_private::PRESENCE_VALUE_FOUND;
+ }
+}
+
+std::string EncodeHash(const std::string& byte_string) {
+ std::string encoded_string;
+ base::Base64UrlEncode(byte_string, base::Base64UrlEncodePolicy::OMIT_PADDING,
+ &encoded_string);
+ return encoded_string;
+}
+
+} // namespace
+
+std::vector<device_signals::GetFileSystemInfoOptions>
+ConvertFileSystemInfoOptions(
+ const std::vector<
+ api::enterprise_reporting_private::GetFileSystemInfoOptions>&
+ api_options) {
+ std::vector<device_signals::GetFileSystemInfoOptions> converted_options;
+ for (const auto& api_options_param : api_options) {
+ device_signals::GetFileSystemInfoOptions converted_param;
+ converted_param.file_path =
+ base::FilePath::FromUTF8Unsafe(api_options_param.path);
+ converted_param.compute_sha256 = api_options_param.compute_sha256;
+ converted_param.compute_executable_metadata =
+ api_options_param.compute_executable_metadata;
+ converted_options.push_back(std::move(converted_param));
+ }
+ return converted_options;
+}
+
+absl::optional<ParsedSignalsError> ConvertFileSystemInfoResponse(
+ const device_signals::SignalsAggregationResponse& response,
+ std::vector<api::enterprise_reporting_private::GetFileSystemInfoResponse>*
+ arg_list) {
+ auto error = TryParseError(response, response.file_system_info_response);
+ if (error) {
+ return error.value();
+ }
+
+ std::vector<api::enterprise_reporting_private::GetFileSystemInfoResponse>
+ api_responses;
+ const auto& file_system_signal_values =
+ response.file_system_info_response.value();
+ for (const auto& file_system_item :
+ file_system_signal_values.file_system_items) {
+ api::enterprise_reporting_private::GetFileSystemInfoResponse response;
+ response.path = file_system_item.file_path.AsUTF8Unsafe();
+ response.presence = ConvertPresenceValue(file_system_item.presence);
+
+ if (file_system_item.sha256_hash) {
+ response.sha256_hash = std::make_unique<std::string>(
+ EncodeHash(file_system_item.sha256_hash.value()));
+ }
+
+ if (file_system_item.executable_metadata) {
+ const auto& executable_metadata =
+ file_system_item.executable_metadata.value();
+
+ response.is_running =
+ std::make_unique<bool>(executable_metadata.is_running);
+
+ if (executable_metadata.public_key_sha256) {
+ response.public_key_sha256 = std::make_unique<std::string>(
+ EncodeHash(executable_metadata.public_key_sha256.value()));
+ }
+
+ if (executable_metadata.product_name) {
+ response.product_name = std::make_unique<std::string>(
+ executable_metadata.product_name.value());
+ }
+
+ if (executable_metadata.version) {
+ response.version =
+ std::make_unique<std::string>(executable_metadata.version.value());
+ }
+ }
+
+ api_responses.push_back(std::move(response));
+ }
+
+ *arg_list = std::move(api_responses);
+ return absl::nullopt;
+}
+
+#if BUILDFLAG(IS_WIN)
+
+absl::optional<ParsedSignalsError> ConvertAvProductsResponse(
+ const device_signals::SignalsAggregationResponse& response,
+ std::vector<api::enterprise_reporting_private::AntiVirusSignal>* arg_list) {
+ auto error = TryParseError(response, response.av_signal_response);
+ if (error) {
+ return error.value();
+ }
+
+ std::vector<api::enterprise_reporting_private::AntiVirusSignal>
+ api_av_signals;
+ const auto& av_response = response.av_signal_response.value();
+ for (const auto& av_product : av_response.av_products) {
+ api::enterprise_reporting_private::AntiVirusSignal api_av_signal;
+ api_av_signal.display_name = av_product.display_name;
+ api_av_signal.product_id = av_product.product_id;
+
+ switch (av_product.state) {
+ case device_signals::AvProductState::kOn:
+ api_av_signal.state = api::enterprise_reporting_private::
+ AntiVirusProductState::ANTI_VIRUS_PRODUCT_STATE_ON;
+ break;
+ case device_signals::AvProductState::kOff:
+ api_av_signal.state = api::enterprise_reporting_private::
+ AntiVirusProductState::ANTI_VIRUS_PRODUCT_STATE_OFF;
+ break;
+ case device_signals::AvProductState::kSnoozed:
+ api_av_signal.state = api::enterprise_reporting_private::
+ AntiVirusProductState::ANTI_VIRUS_PRODUCT_STATE_SNOOZED;
+ break;
+ case device_signals::AvProductState::kExpired:
+ api_av_signal.state = api::enterprise_reporting_private::
+ AntiVirusProductState::ANTI_VIRUS_PRODUCT_STATE_EXPIRED;
+ break;
+ }
+
+ api_av_signals.push_back(std::move(api_av_signal));
+ }
+
+ *arg_list = std::move(api_av_signals);
+ return absl::nullopt;
+}
+
+absl::optional<ParsedSignalsError> ConvertHotfixesResponse(
+ const device_signals::SignalsAggregationResponse& response,
+ std::vector<api::enterprise_reporting_private::HotfixSignal>* arg_list) {
+ auto error = TryParseError(response, response.hotfix_signal_response);
+ if (error) {
+ return error.value();
+ }
+
+ std::vector<api::enterprise_reporting_private::HotfixSignal>
+ api_hotfix_signals;
+ const auto& hotfix_response = response.hotfix_signal_response.value();
+ for (const auto& hotfix : hotfix_response.hotfixes) {
+ api::enterprise_reporting_private::HotfixSignal api_hotfix;
+ api_hotfix.hotfix_id = hotfix.hotfix_id;
+ api_hotfix_signals.push_back(std::move(api_hotfix));
+ }
+
+ *arg_list = std::move(api_hotfix_signals);
+ return absl::nullopt;
+}
+
+#endif // BUILDFLAG(IS_WIN)
+
+} // namespace extensions
+
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
diff --git a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.h b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.h
new file mode 100644
index 00000000000..764aa73af9a
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.h
@@ -0,0 +1,68 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_REPORTING_PRIVATE_CONVERSION_UTILS_H_
+#define CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_REPORTING_PRIVATE_CONVERSION_UTILS_H_
+
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
+#include <vector>
+
+#include "chrome/common/extensions/api/enterprise_reporting_private.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace device_signals {
+struct GetFileSystemInfoOptions;
+struct SignalsAggregationResponse;
+enum class SignalCollectionError;
+} // namespace device_signals
+
+namespace extensions {
+
+struct ParsedSignalsError {
+ device_signals::SignalCollectionError error;
+ bool is_top_level_error;
+};
+
+// Converts GetFileSystemInfoOptions from the Extension API struct definition,
+// `api_options`, to the device_signals component definition.
+std::vector<device_signals::GetFileSystemInfoOptions>
+ConvertFileSystemInfoOptions(
+ const std::vector<
+ api::enterprise_reporting_private::GetFileSystemInfoOptions>&
+ api_options);
+
+// Parses and converts the File System info signal values from `response` into
+// `arg_list`. If any error occurred during signal collection, it will be
+// returned and `arg_list` will remain unchanged.
+absl::optional<ParsedSignalsError> ConvertFileSystemInfoResponse(
+ const device_signals::SignalsAggregationResponse& response,
+ std::vector<api::enterprise_reporting_private::GetFileSystemInfoResponse>*
+ arg_list);
+
+#if BUILDFLAG(IS_WIN)
+
+// Parses and converts the Antivirus signal values from `response` into
+// `arg_list`. If any error occurred during signal collection, it will be
+// returned and `arg_list` will remain unchanged.
+absl::optional<ParsedSignalsError> ConvertAvProductsResponse(
+ const device_signals::SignalsAggregationResponse& response,
+ std::vector<api::enterprise_reporting_private::AntiVirusSignal>* arg_list);
+
+// Parses and converts the Hotfix signal values from `response` into
+// `arg_list`. If any error occurred during signal collection, it will be
+// returned and `arg_list` will remain unchanged.
+absl::optional<ParsedSignalsError> ConvertHotfixesResponse(
+ const device_signals::SignalsAggregationResponse& response,
+ std::vector<api::enterprise_reporting_private::HotfixSignal>* arg_list);
+
+#endif // BUILDFLAG(IS_WIN)
+
+} // namespace extensions
+
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_REPORTING_PRIVATE_CONVERSION_UTILS_H_
diff --git a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc
index 7caa584b10d..ae82bcb654d 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback.h"
#include "base/strings/stringprintf.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -30,6 +31,18 @@
#include "components/reporting/util/statusor.h"
#endif
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+#include "base/strings/string_util.h"
+#include "chrome/browser/enterprise/signals/signals_aggregator_factory.h"
+#include "chrome/browser/extensions/api/enterprise_reporting_private/conversion_utils.h"
+#include "components/device_signals/core/browser/metrics_utils.h"
+#include "components/device_signals/core/browser/signals_aggregator.h"
+#include "components/device_signals/core/browser/signals_types.h"
+#include "components/device_signals/core/browser/user_context.h"
+#include "components/device_signals/core/common/signals_features.h" // nogncheck
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
#include "components/content_settings/core/common/pref_names.h"
#include "components/enterprise/browser/controller/browser_dm_token_storage.h"
#include "net/cert/x509_util.h"
@@ -142,6 +155,40 @@ api::enterprise_reporting_private::ContextInfo ToContextInfo(
return info;
}
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
+device_signals::SignalsAggregationRequest CreateAggregationRequest(
+ const std::string& user_id,
+ device_signals::SignalName signal_name) {
+ device_signals::UserContext user_context;
+ user_context.user_id = user_id;
+
+ device_signals::SignalsAggregationRequest request;
+ request.user_context = std::move(user_context);
+ request.signal_names.emplace(signal_name);
+ return request;
+}
+
+void StartSignalCollection(
+ device_signals::SignalsAggregationRequest request,
+ content::BrowserContext* browser_context,
+ base::OnceCallback<void(device_signals::SignalsAggregationResponse)>
+ callback) {
+ DCHECK(browser_context);
+ auto* profile = Profile::FromBrowserContext(browser_context);
+ DCHECK(profile);
+ auto* signals_aggregator =
+ enterprise_signals::SignalsAggregatorFactory::GetForProfile(profile);
+ DCHECK(signals_aggregator);
+ signals_aggregator->GetSignals(std::move(request), std::move(callback));
+}
+
+bool CanReturnResponse(content::BrowserContext* browser_context) {
+ return browser_context && !browser_context->ShutdownStarted();
+}
+
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
} // namespace
#if !BUILDFLAG(IS_CHROMEOS)
@@ -608,4 +655,185 @@ void EnterpriseReportingPrivateEnqueueRecordFunction::
}
#endif
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
+// getFileSystemInfo
+
+EnterpriseReportingPrivateGetFileSystemInfoFunction::
+ EnterpriseReportingPrivateGetFileSystemInfoFunction() = default;
+EnterpriseReportingPrivateGetFileSystemInfoFunction::
+ ~EnterpriseReportingPrivateGetFileSystemInfoFunction() = default;
+
+ExtensionFunction::ResponseAction
+EnterpriseReportingPrivateGetFileSystemInfoFunction::Run() {
+ if (!IsNewFunctionEnabled(
+ enterprise_signals::features::NewEvFunction::kFileSystemInfo)) {
+ return RespondNow(Error(device_signals::ErrorToString(
+ device_signals::SignalCollectionError::kUnsupported)));
+ }
+
+ std::unique_ptr<api::enterprise_reporting_private::GetFileSystemInfo::Params>
+ params(
+ api::enterprise_reporting_private::GetFileSystemInfo::Params::Create(
+ args()));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ // Verify that all file paths are UTF8.
+ bool paths_are_all_utf8 = true;
+ for (const auto& api_options_param : params->request.options) {
+ if (!base::IsStringUTF8(api_options_param.path)) {
+ paths_are_all_utf8 = false;
+ break;
+ }
+ }
+ EXTENSION_FUNCTION_VALIDATE(paths_are_all_utf8);
+
+ auto aggregation_request = CreateAggregationRequest(
+ params->request.user_context.user_id, signal_name());
+ aggregation_request.file_system_signal_parameters =
+ ConvertFileSystemInfoOptions(params->request.options);
+
+ StartSignalCollection(
+ aggregation_request, browser_context(),
+ base::BindOnce(&EnterpriseReportingPrivateGetFileSystemInfoFunction::
+ OnSignalRetrieved,
+ this));
+
+ return RespondLater();
+}
+
+void EnterpriseReportingPrivateGetFileSystemInfoFunction::OnSignalRetrieved(
+ device_signals::SignalsAggregationResponse response) {
+ if (!CanReturnResponse(browser_context())) {
+ // The browser is no longer accepting responses, so just bail.
+ return;
+ }
+
+ std::vector<api::enterprise_reporting_private::GetFileSystemInfoResponse>
+ arg_list;
+ auto parsed_error = ConvertFileSystemInfoResponse(response, &arg_list);
+
+ if (parsed_error) {
+ LogSignalCollectionFailed(signal_name(), parsed_error->error,
+ parsed_error->is_top_level_error);
+ Respond(Error(device_signals::ErrorToString(parsed_error->error)));
+ return;
+ }
+
+ LogSignalCollectionSucceeded(signal_name(), arg_list.size());
+ Respond(ArgumentList(
+ api::enterprise_reporting_private::GetFileSystemInfo::Results::Create(
+ arg_list)));
+}
+
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
+#if BUILDFLAG(IS_WIN)
+
+// getAvInfo
+
+EnterpriseReportingPrivateGetAvInfoFunction::
+ EnterpriseReportingPrivateGetAvInfoFunction() = default;
+EnterpriseReportingPrivateGetAvInfoFunction::
+ ~EnterpriseReportingPrivateGetAvInfoFunction() = default;
+
+ExtensionFunction::ResponseAction
+EnterpriseReportingPrivateGetAvInfoFunction::Run() {
+ if (!IsNewFunctionEnabled(
+ enterprise_signals::features::NewEvFunction::kAntiVirus)) {
+ return RespondNow(Error(device_signals::ErrorToString(
+ device_signals::SignalCollectionError::kUnsupported)));
+ }
+
+ std::unique_ptr<api::enterprise_reporting_private::GetAvInfo::Params> params(
+ api::enterprise_reporting_private::GetAvInfo::Params::Create(args()));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ StartSignalCollection(
+ CreateAggregationRequest(params->user_context.user_id, signal_name()),
+ browser_context(),
+ base::BindOnce(
+ &EnterpriseReportingPrivateGetAvInfoFunction::OnSignalRetrieved,
+ this));
+
+ return RespondLater();
+}
+
+void EnterpriseReportingPrivateGetAvInfoFunction::OnSignalRetrieved(
+ device_signals::SignalsAggregationResponse response) {
+ if (!CanReturnResponse(browser_context())) {
+ // The browser is no longer accepting responses, so just bail.
+ return;
+ }
+
+ std::vector<api::enterprise_reporting_private::AntiVirusSignal> arg_list;
+ auto parsed_error = ConvertAvProductsResponse(response, &arg_list);
+
+ if (parsed_error) {
+ LogSignalCollectionFailed(signal_name(), parsed_error->error,
+ parsed_error->is_top_level_error);
+ Respond(Error(device_signals::ErrorToString(parsed_error->error)));
+ return;
+ }
+
+ LogSignalCollectionSucceeded(signal_name(), arg_list.size());
+ Respond(ArgumentList(
+ api::enterprise_reporting_private::GetAvInfo::Results::Create(arg_list)));
+}
+
+// getHotfixes
+
+EnterpriseReportingPrivateGetHotfixesFunction::
+ EnterpriseReportingPrivateGetHotfixesFunction() = default;
+EnterpriseReportingPrivateGetHotfixesFunction::
+ ~EnterpriseReportingPrivateGetHotfixesFunction() = default;
+
+ExtensionFunction::ResponseAction
+EnterpriseReportingPrivateGetHotfixesFunction::Run() {
+ if (!IsNewFunctionEnabled(
+ enterprise_signals::features::NewEvFunction::kHotfix)) {
+ return RespondNow(Error(device_signals::ErrorToString(
+ device_signals::SignalCollectionError::kUnsupported)));
+ }
+
+ std::unique_ptr<api::enterprise_reporting_private::GetHotfixes::Params>
+ params(api::enterprise_reporting_private::GetHotfixes::Params::Create(
+ args()));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ StartSignalCollection(
+ CreateAggregationRequest(params->user_context.user_id, signal_name()),
+ browser_context(),
+ base::BindOnce(
+ &EnterpriseReportingPrivateGetHotfixesFunction::OnSignalRetrieved,
+ this));
+
+ return RespondLater();
+}
+
+void EnterpriseReportingPrivateGetHotfixesFunction::OnSignalRetrieved(
+ device_signals::SignalsAggregationResponse response) {
+ if (!CanReturnResponse(browser_context())) {
+ // The browser is no longer accepting responses, so just bail.
+ return;
+ }
+
+ std::vector<api::enterprise_reporting_private::HotfixSignal> arg_list;
+ auto parsed_error = ConvertHotfixesResponse(response, &arg_list);
+
+ if (parsed_error) {
+ LogSignalCollectionFailed(signal_name(), parsed_error->error,
+ parsed_error->is_top_level_error);
+ Respond(Error(device_signals::ErrorToString(parsed_error->error)));
+ return;
+ }
+
+ LogSignalCollectionSucceeded(signal_name(), arg_list.size());
+ Respond(ArgumentList(
+ api::enterprise_reporting_private::GetHotfixes::Results::Create(
+ arg_list)));
+}
+
+#endif // BUILDFLAG(IS_WIN)
+
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h
index bc0a5a7eafd..8afa2b5c177 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h
+++ b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h
@@ -19,7 +19,9 @@
#include "components/reporting/proto/synced/record.pb.h"
#include "components/reporting/proto/synced/record_constants.pb.h"
#include "components/reporting/util/statusor.h"
-#endif
+#elif BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+#include "components/device_signals/core/browser/signals_types.h"
+#endif // BUILDFLAG(IS_CHROMEOS)
#include "extensions/browser/extension_function.h"
@@ -262,6 +264,87 @@ class EnterpriseReportingPrivateEnqueueRecordFunction
#endif
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
+class EnterpriseReportingPrivateGetFileSystemInfoFunction
+ : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("enterprise.reportingPrivate.getFileSystemInfo",
+ ENTERPRISEREPORTINGPRIVATE_GETFILESYSTEMINFO)
+
+ EnterpriseReportingPrivateGetFileSystemInfoFunction();
+ EnterpriseReportingPrivateGetFileSystemInfoFunction(
+ const EnterpriseReportingPrivateGetFileSystemInfoFunction&) = delete;
+ EnterpriseReportingPrivateGetFileSystemInfoFunction& operator=(
+ const EnterpriseReportingPrivateGetFileSystemInfoFunction&) = delete;
+
+ private:
+ ~EnterpriseReportingPrivateGetFileSystemInfoFunction() override;
+
+ // ExtensionFunction
+ ExtensionFunction::ResponseAction Run() override;
+
+ void OnSignalRetrieved(device_signals::SignalsAggregationResponse response);
+
+ device_signals::SignalName signal_name() {
+ return device_signals::SignalName::kFileSystemInfo;
+ }
+};
+
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
+#if BUILDFLAG(IS_WIN)
+
+class EnterpriseReportingPrivateGetAvInfoFunction : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("enterprise.reportingPrivate.getAvInfo",
+ ENTERPRISEREPORTINGPRIVATE_GETAVINFO)
+
+ EnterpriseReportingPrivateGetAvInfoFunction();
+ EnterpriseReportingPrivateGetAvInfoFunction(
+ const EnterpriseReportingPrivateGetAvInfoFunction&) = delete;
+ EnterpriseReportingPrivateGetAvInfoFunction& operator=(
+ const EnterpriseReportingPrivateGetAvInfoFunction&) = delete;
+
+ private:
+ ~EnterpriseReportingPrivateGetAvInfoFunction() override;
+
+ // ExtensionFunction
+ ExtensionFunction::ResponseAction Run() override;
+
+ void OnSignalRetrieved(device_signals::SignalsAggregationResponse response);
+
+ device_signals::SignalName signal_name() {
+ return device_signals::SignalName::kAntiVirus;
+ }
+};
+
+class EnterpriseReportingPrivateGetHotfixesFunction : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("enterprise.reportingPrivate.getHotfixes",
+ ENTERPRISEREPORTINGPRIVATE_GETHOTFIXES)
+
+ EnterpriseReportingPrivateGetHotfixesFunction();
+ EnterpriseReportingPrivateGetHotfixesFunction(
+ const EnterpriseReportingPrivateGetHotfixesFunction&) = delete;
+ EnterpriseReportingPrivateGetHotfixesFunction& operator=(
+ const EnterpriseReportingPrivateGetHotfixesFunction&) = delete;
+
+ private:
+ ~EnterpriseReportingPrivateGetHotfixesFunction() override;
+
+ // ExtensionFunction
+ ExtensionFunction::ResponseAction Run() override;
+
+ void OnSignalRetrieved(device_signals::SignalsAggregationResponse response);
+
+ device_signals::SignalName signal_name() {
+ return device_signals::SignalName::kHotfixes;
+ }
+};
+
+#endif // BUILDFLAG(IS_WIN)
+
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_REPORTING_PRIVATE_ENTERPRISE_REPORTING_PRIVATE_API_H_
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 8fc6fa0f42c..aa71b2e544d 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
@@ -2,26 +2,56 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/test/scoped_feature_list.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
+#include "chrome/browser/enterprise/browser_management/management_service_factory.h"
+#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/policy/profile_policy_connector.h"
+#include "chrome/browser/signin/chrome_signin_client_factory.h"
+#include "chrome/browser/signin/chrome_signin_client_test_util.h"
+#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/test/base/in_process_browser_test.h"
+#include "components/policy/core/common/management/management_service.h"
+#include "components/signin/public/identity_manager/account_info.h"
+#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/version_info/version_info.h"
#include "content/public/test/browser_test.h"
#include "extensions/common/extension.h"
#include "extensions/test/result_catcher.h"
#include "extensions/test/test_extension_dir.h"
+#include "services/network/test/test_url_loader_factory.h"
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+#include "base/files/file_path.h"
+#include "base/process/process.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/policy/chrome_browser_policy_connector.h"
+#include "components/device_signals/core/common/signals_features.h"
+#include "components/device_signals/core/system_signals/platform_utils.h" // nogncheck
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h"
#include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h"
-#endif
+#include "components/policy/core/common/cloud/cloud_policy_core.h"
+#include "components/policy/core/common/cloud/cloud_policy_store.h"
+#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h"
+#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
+#include "components/policy/proto/device_management_backend.pb.h"
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS)
#include "base/strings/strcat.h"
#include "chrome/browser/enterprise/util/affiliation.h"
#include "chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_api.h"
-#include "chrome/browser/extensions/chrome_test_extension_loader.h"
#include "chrome/browser/profiles/profile_manager.h"
#endif
@@ -42,6 +72,10 @@
namespace extensions {
namespace {
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+constexpr char kAffiliationId[] = "affiliation-id";
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
+
// Manifest key for the Endpoint Verification extension found at
// chrome.google.com/webstore/detail/callobklhcbilhphinckomhgkigmfocg
// This extension is authorized to use the enterprise.reportingPrivate API.
@@ -83,13 +117,48 @@ constexpr char kManifestTemplate[] = R"(
class EnterpriseReportingPrivateApiTest : public extensions::ExtensionApiTest {
public:
EnterpriseReportingPrivateApiTest() {
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+ scoped_features_.InitAndEnableFeature(
+ enterprise_signals::features::kNewEvSignalsEnabled);
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
#if !BUILDFLAG(IS_CHROMEOS_ASH)
browser_dm_token_storage_.SetClientId("client_id");
-#endif
+ browser_dm_token_storage_.SetEnrollmentToken("enrollment_token");
+ browser_dm_token_storage_.SetDMToken("dm_token");
+ policy::BrowserDMTokenStorage::SetForTesting(&browser_dm_token_storage_);
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
}
~EnterpriseReportingPrivateApiTest() override = default;
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+ // Signs in and returns the account ID of the primary account.
+ AccountInfo SignIn(const std::string& email, bool as_managed = true) {
+ auto account_info = identity_test_env()->MakePrimaryAccountAvailable(
+ email, signin::ConsentLevel::kSignin);
+ EXPECT_TRUE(identity_test_env()->identity_manager()->HasPrimaryAccount(
+ signin::ConsentLevel::kSignin));
+
+ if (as_managed) {
+ account_info.hosted_domain = "example.com";
+ identity_test_env()->UpdateAccountInfoForAccount(account_info);
+
+ safe_browsing::SetProfileDMToken(profile(), "fake_user_dmtoken");
+ auto profile_policy_data =
+ std::make_unique<enterprise_management::PolicyData>();
+ profile_policy_data->add_user_affiliation_ids(kAffiliationId);
+ profile()
+ ->GetUserCloudPolicyManager()
+ ->core()
+ ->store()
+ ->set_policy_data_for_testing(std::move(profile_policy_data));
+ }
+
+ return account_info;
+ }
+#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
+
void RunTest(const std::string& background_js,
bool authorized_manifest_key = true) {
ResultCatcher result_catcher;
@@ -116,6 +185,69 @@ class EnterpriseReportingPrivateApiTest : public extensions::ExtensionApiTest {
}
protected:
+ void SetUpInProcessBrowserTestFixture() override {
+ extensions::ExtensionApiTest::SetUpInProcessBrowserTestFixture();
+
+ create_services_subscription_ =
+ BrowserContextDependencyManager::GetInstance()
+ ->RegisterCreateServicesCallbackForTesting(
+ base::BindRepeating(&EnterpriseReportingPrivateApiTest::
+ OnWillCreateBrowserContextServices,
+ base::Unretained(this)));
+ }
+
+ void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
+ IdentityTestEnvironmentProfileAdaptor::
+ SetIdentityTestEnvironmentFactoriesOnBrowserContext(context);
+
+ ChromeSigninClientFactory::GetInstance()->SetTestingFactory(
+ context, base::BindRepeating(&BuildChromeSigninClientWithURLLoader,
+ &test_url_loader_factory_));
+ }
+
+ void SetUpOnMainThread() override {
+ extensions::ExtensionApiTest::SetUpOnMainThread();
+ identity_test_env_profile_adaptor_ =
+ std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
+
+ identity_test_env()->SetTestURLLoaderFactory(&test_url_loader_factory_);
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+ // Set device org's affiliated IDs.
+ auto* browser_policy_manager =
+ g_browser_process->browser_policy_connector()
+ ->machine_level_user_cloud_policy_manager();
+ auto browser_policy_data =
+ std::make_unique<enterprise_management::PolicyData>();
+ browser_policy_data->add_device_affiliation_ids(kAffiliationId);
+ browser_policy_manager->core()->store()->set_policy_data_for_testing(
+ std::move(browser_policy_data));
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+ }
+
+ void TearDownOnMainThread() override {
+ extensions::ExtensionApiTest::TearDownOnMainThread();
+ // Must be destroyed before the Profile.
+ identity_test_env_profile_adaptor_.reset();
+ }
+
+ policy::ProfilePolicyConnector* profile_policy_connector() {
+ return profile()->GetProfilePolicyConnector();
+ }
+
+ signin::IdentityTestEnvironment* identity_test_env() {
+ return identity_test_env_profile_adaptor_->identity_test_env();
+ }
+
+ std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
+ identity_test_env_profile_adaptor_;
+
+ network::TestURLLoaderFactory test_url_loader_factory_;
+
+ base::CallbackListSubscription create_services_subscription_;
+
+ base::test::ScopedFeatureList scoped_features_;
+
#if !BUILDFLAG(IS_CHROMEOS_ASH)
policy::FakeBrowserDMTokenStorage browser_dm_token_storage_;
#endif
@@ -382,6 +514,101 @@ IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetCertificate) {
});)");
}
+#if BUILDFLAG(IS_WIN)
+
+IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetAvInfo_Success) {
+ constexpr char kTest[] = R"(
+ chrome.test.assertEq(
+ 'function',
+ typeof chrome.enterprise.reportingPrivate.getAvInfo);
+ const userContext = {userId: '%s'};
+
+ chrome.enterprise.reportingPrivate.getAvInfo(userContext, (avProducts) => {
+ chrome.test.assertNoLastError();
+ chrome.test.assertTrue(avProducts instanceof Array);
+ chrome.test.notifyPass();
+ });
+ )";
+
+ AccountInfo account_info = SignIn("some-email@example.com");
+ RunTest(base::StringPrintf(kTest, account_info.gaia.c_str()));
+}
+
+IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest, GetHotfixes_Success) {
+ constexpr char kTest[] = R"(
+ chrome.test.assertEq(
+ 'function',
+ typeof chrome.enterprise.reportingPrivate.getHotfixes);
+ const userContext = {userId: '%s'};
+
+ chrome.enterprise.reportingPrivate.getHotfixes(userContext, (hotfixes) => {
+ chrome.test.assertNoLastError();
+ chrome.test.assertTrue(hotfixes instanceof Array);
+ chrome.test.notifyPass();
+ });
+ )";
+
+ AccountInfo account_info = SignIn("some-email@example.com");
+ RunTest(base::StringPrintf(kTest, account_info.gaia.c_str()));
+}
+
+#endif // BUILDFLAG(IS_WIN)
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
+IN_PROC_BROWSER_TEST_F(EnterpriseReportingPrivateApiTest,
+ GetFileSystemInfo_Success) {
+ // Use the test runner process and binary as test parameters, as it will always
+ // be running.
+ auto test_runner_file_path =
+ device_signals::GetProcessExePath(base::Process::Current().Pid());
+
+ ASSERT_TRUE(test_runner_file_path.has_value());
+ ASSERT_FALSE(test_runner_file_path->empty());
+
+ constexpr char kTest[] = R"(
+ chrome.test.assertEq(
+ 'function',
+ typeof chrome.enterprise.reportingPrivate.getFileSystemInfo);
+ const userContext = {userId: '%s'};
+
+ const executablePath = '%s';
+ const fileItem = {
+ path: executablePath,
+ computeSha256: true,
+ computeExecutableMetadata: true
+ };
+
+ const request = { userContext, options: [fileItem] };
+
+ chrome.enterprise.reportingPrivate.getFileSystemInfo(
+ request,
+ (fileItems) => {
+ chrome.test.assertNoLastError();
+ chrome.test.assertTrue(fileItems instanceof Array);
+ chrome.test.assertEq(1, fileItems.length);
+
+ const fileItemResponse = fileItems[0];
+ chrome.test.assertEq(executablePath, fileItemResponse.path);
+ chrome.test.assertEq('FOUND', fileItemResponse.presence);
+ chrome.test.assertTrue(!!fileItemResponse.sha256Hash);
+ chrome.test.assertTrue(fileItemResponse.isRunning);
+
+ chrome.test.notifyPass();
+ });
+ )";
+
+ // Escape all backslashes.
+ std::string escaped_file_path = test_runner_file_path->AsUTF8Unsafe();
+ base::ReplaceSubstringsAfterOffset(&escaped_file_path, 0U, "\\", "\\\\");
+
+ AccountInfo account_info = SignIn("some-email@example.com");
+ RunTest(base::StringPrintf(kTest, account_info.gaia.c_str(),
+ escaped_file_path.c_str()));
+}
+
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+
#if BUILDFLAG(IS_CHROMEOS)
static void RunTestUsingProfile(const std::string& background_js,
Profile* profile) {
@@ -522,7 +749,6 @@ using EnterpriseReportingPrivateEnqueueRecordApiTest = ExtensionApiTest;
static void SetupAffiliationLacros() {
constexpr char kDomain[] = "fake-domain";
- constexpr char kAffiliationId[] = "affiliation-id";
constexpr char kFakeProfileClientId[] = "fake-profile-client-id";
constexpr char kFakeDMToken[] = "fake-dm-token";
enterprise_management::PolicyData profile_policy_data;
diff --git a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc
index 5a073322133..10534443294 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/enterprise_reporting_private_unittest.cc
@@ -12,6 +12,7 @@
#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/json/json_writer.h"
#include "build/build_config.h"
#include "chrome/browser/enterprise/signals/signals_common.h"
#include "chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.h"
@@ -33,6 +34,7 @@
#include "components/reporting/proto/synced/record.pb.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/version_info/version_info.h"
+#include "extensions/browser/api_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -50,7 +52,19 @@
#include <wrl/client.h>
#include "base/test/test_reg_util_win.h"
-#endif
+#endif // BUILDFLAG(IS_WIN)
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/enterprise/signals/signals_aggregator_factory.h"
+#include "components/device_signals/core/browser/mock_signals_aggregator.h" // nogncheck
+#include "components/device_signals/core/browser/signals_aggregator.h" // nogncheck
+#include "components/device_signals/core/browser/signals_types.h" // nogncheck
+#include "components/device_signals/core/common/common_types.h" // nogncheck
+#include "components/device_signals/core/common/signals_constants.h" // nogncheck
+#include "components/device_signals/core/common/signals_features.h" // nogncheck
+#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "base/nix/xdg_util.h"
@@ -63,16 +77,24 @@ using SettingValue = enterprise_signals::SettingValue;
using ::testing::_;
using ::testing::Eq;
using ::testing::Invoke;
+using ::testing::IsEmpty;
+using ::testing::SizeIs;
using ::testing::StrEq;
using ::testing::WithArgs;
namespace extensions {
+#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
+
+constexpr char kNoError[] = "";
+
+#endif // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
+
#if !BUILDFLAG(IS_CHROMEOS)
namespace {
-const char kFakeClientId[] = "fake-client-id";
+constexpr char kFakeClientId[] = "fake-client-id";
} // namespace
@@ -1035,38 +1057,18 @@ TEST_P(EnterpriseReportingPrivateGetContextInfoRealTimeURLCheckTest, Test) {
}
#if BUILDFLAG(IS_CHROMEOS)
-class MockMissiveClient : public ::chromeos::FakeMissiveClient {
- public:
- MockMissiveClient() = default;
- ~MockMissiveClient() override = default;
-
- MockMissiveClient(const MockMissiveClient& other) = delete;
- MockMissiveClient& operator=(const MockMissiveClient& other) = delete;
-
- void Init() override {}
-
- MissiveClient::TestInterface* GetTestInterface() override { return this; }
-
- MOCK_METHOD(void,
- EnqueueRecord,
- (const ::reporting::Priority,
- ::reporting::Record,
- base::OnceCallback<void(::reporting::Status)>),
- (override));
-};
// Test for API enterprise.reportingPrivate.enqueueRecord
class EnterpriseReportingPrivateEnqueueRecordFunctionTest
: public ExtensionApiUnittest {
protected:
- static constexpr char kNoError[] = "";
static constexpr char kTestDMTokenValue[] = "test_dm_token_value";
EnterpriseReportingPrivateEnqueueRecordFunctionTest() = default;
void SetUp() override {
ExtensionApiUnittest::SetUp();
- ::chromeos::MissiveClient::InitializeFake<MockMissiveClient>();
+ ::chromeos::MissiveClient::InitializeFake();
function_ =
base::MakeRefCounted<EnterpriseReportingPrivateEnqueueRecordFunction>();
const auto record = GetTestRecord();
@@ -1096,6 +1098,18 @@ class EnterpriseReportingPrivateEnqueueRecordFunctionTest
return record;
}
+ void VerifyNoRecordsEnqueued(::reporting::Priority priority =
+ ::reporting::Priority::BACKGROUND_BATCH) {
+ ::chromeos::MissiveClient::TestInterface* const missive_test_interface =
+ ::chromeos::MissiveClient::Get()->GetTestInterface();
+ ASSERT_TRUE(missive_test_interface);
+
+ const std::vector<::reporting::Record>& records =
+ missive_test_interface->GetEnqueuedRecords(priority);
+
+ ASSERT_THAT(records, IsEmpty());
+ }
+
std::vector<uint8_t> serialized_record_data_;
scoped_refptr<extensions::EnterpriseReportingPrivateEnqueueRecordFunction>
function_;
@@ -1121,25 +1135,25 @@ TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
policy::DMToken::CreateValidTokenForTesting(kTestDMTokenValue);
policy::SetDMTokenForTesting(dm_token);
- auto* const reporting_client =
- static_cast<MockMissiveClient*>(::chromeos::MissiveClient::Get());
- EXPECT_CALL(*reporting_client, EnqueueRecord(_, _, _))
- .WillOnce(WithArgs<1, 2>(
- Invoke([&](::reporting::Record record,
- base::OnceCallback<void(::reporting::Status)>
- completion_callback) {
- EXPECT_THAT(record.destination(),
- Eq(::reporting::Destination::TELEMETRY_METRIC));
- EXPECT_THAT(record.dm_token(), StrEq(dm_token.value()));
- EXPECT_THAT(record.data(), StrEq(GetTestRecord().data()));
-
- std::move(completion_callback).Run(::reporting::Status::StatusOK());
- })));
-
extension_function_test_utils::RunFunction(function_.get(), std::move(params),
browser(),
extensions::api_test_utils::NONE);
EXPECT_EQ(function_->GetError(), kNoError);
+
+ ::chromeos::MissiveClient::TestInterface* const missive_test_interface =
+ ::chromeos::MissiveClient::Get()->GetTestInterface();
+ ASSERT_TRUE(missive_test_interface);
+
+ const std::vector<::reporting::Record>& background_batch_records =
+ missive_test_interface->GetEnqueuedRecords(
+ ::reporting::Priority::BACKGROUND_BATCH);
+
+ ASSERT_THAT(background_batch_records, SizeIs(1));
+ EXPECT_THAT(background_batch_records[0].destination(),
+ Eq(::reporting::Destination::TELEMETRY_METRIC));
+ EXPECT_THAT(background_batch_records[0].dm_token(), StrEq(dm_token.value()));
+ EXPECT_THAT(background_batch_records[0].data(),
+ StrEq(GetTestRecord().data()));
}
TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
@@ -1163,10 +1177,6 @@ TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
policy::SetDMTokenForTesting(
policy::DMToken::CreateValidTokenForTesting(kTestDMTokenValue));
- auto* const reporting_client =
- static_cast<MockMissiveClient*>(::chromeos::MissiveClient::Get());
- EXPECT_CALL(*reporting_client, EnqueueRecord(_, _, _)).Times(0);
-
extension_function_test_utils::RunFunction(function_.get(), std::move(params),
browser(),
extensions::api_test_utils::NONE);
@@ -1174,6 +1184,8 @@ TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
EXPECT_EQ(function_->GetError(),
EnterpriseReportingPrivateEnqueueRecordFunction::
kErrorInvalidEnqueueRecordRequest);
+
+ VerifyNoRecordsEnqueued();
}
TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
@@ -1196,10 +1208,6 @@ TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
policy::SetDMTokenForTesting(
policy::DMToken::CreateValidTokenForTesting(kTestDMTokenValue));
- auto* const reporting_client =
- static_cast<MockMissiveClient*>(::chromeos::MissiveClient::Get());
- EXPECT_CALL(*reporting_client, EnqueueRecord(_, _, _)).Times(0);
-
extension_function_test_utils::RunFunction(function_.get(), std::move(params),
browser(),
extensions::api_test_utils::NONE);
@@ -1207,6 +1215,8 @@ TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
EXPECT_EQ(function_->GetError(),
EnterpriseReportingPrivateEnqueueRecordFunction::
kErrorProfileNotAffiliated);
+
+ VerifyNoRecordsEnqueued();
}
TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
@@ -1226,10 +1236,6 @@ TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
// Set up invalid DM token
policy::SetDMTokenForTesting(policy::DMToken::CreateInvalidTokenForTesting());
- auto* const reporting_client =
- static_cast<MockMissiveClient*>(::chromeos::MissiveClient::Get());
- EXPECT_CALL(*reporting_client, EnqueueRecord(_, _, _)).Times(0);
-
extension_function_test_utils::RunFunction(function_.get(), std::move(params),
browser(),
extensions::api_test_utils::NONE);
@@ -1237,6 +1243,8 @@ TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
EXPECT_EQ(function_->GetError(),
EnterpriseReportingPrivateEnqueueRecordFunction::
kErrorCannotAssociateRecordWithUser);
+
+ VerifyNoRecordsEnqueued();
}
TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
@@ -1265,10 +1273,6 @@ TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
policy::SetDMTokenForTesting(
policy::DMToken::CreateValidTokenForTesting(kTestDMTokenValue));
- auto* const reporting_client =
- static_cast<MockMissiveClient*>(::chromeos::MissiveClient::Get());
- EXPECT_CALL(*reporting_client, EnqueueRecord(_, _, _)).Times(0);
-
extension_function_test_utils::RunFunction(function_.get(), std::move(params),
browser(),
extensions::api_test_utils::NONE);
@@ -1276,7 +1280,482 @@ TEST_F(EnterpriseReportingPrivateEnqueueRecordFunctionTest,
EXPECT_EQ(function_->GetError(),
EnterpriseReportingPrivateEnqueueRecordFunction::
kErrorInvalidEnqueueRecordRequest);
+
+ VerifyNoRecordsEnqueued();
}
#endif // BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_WIN)
+
+namespace {
+
+constexpr char kFakeUserId[] = "fake user id";
+
+enterprise_reporting_private::UserContext GetFakeUserContext() {
+ enterprise_reporting_private::UserContext user_context;
+ user_context.user_id = kFakeUserId;
+ return user_context;
+}
+
+std::string GetFakeUserContextJsonParams() {
+ auto user_context = GetFakeUserContext();
+ base::ListValue params;
+ params.Append(base::Value::FromUniquePtrValue(user_context.ToValue()));
+ std::string json_value;
+ base::JSONWriter::Write(params, &json_value);
+ return json_value;
+}
+
+std::unique_ptr<KeyedService> BuildMockAggregator(
+ content::BrowserContext* context) {
+ return std::make_unique<
+ testing::StrictMock<device_signals::MockSignalsAggregator>>();
+}
+
+} // namespace
+
+// Base test class for APIs that require a UserContext parameter and which will
+// make use of the SignalsAggregator to retrieve device signals.
+class UserContextGatedTest : public ExtensionApiUnittest {
+ protected:
+ void SetUp() override {
+ ExtensionApiUnittest::SetUp();
+
+ auto* factory = enterprise_signals::SignalsAggregatorFactory::GetInstance();
+ mock_aggregator_ = static_cast<device_signals::MockSignalsAggregator*>(
+ factory->SetTestingFactoryAndUse(
+ browser()->profile(), base::BindRepeating(&BuildMockAggregator)));
+ }
+
+ void SetFakeResponse(
+ const device_signals::SignalsAggregationResponse& response) {
+ EXPECT_CALL(*mock_aggregator_, GetSignals(_, _))
+ .WillOnce(
+ Invoke([&](const device_signals::SignalsAggregationRequest& request,
+ device_signals::SignalsAggregator::GetSignalsCallback
+ callback) {
+ EXPECT_EQ(request.user_context.user_id, kFakeUserId);
+ EXPECT_EQ(request.signal_names.size(), 1U);
+ std::move(callback).Run(response);
+ }));
+ }
+
+ virtual void SetFeatureFlag() {
+ scoped_features_.InitAndEnableFeature(
+ enterprise_signals::features::kNewEvSignalsEnabled);
+ }
+
+ device_signals::MockSignalsAggregator* mock_aggregator_;
+ base::test::ScopedFeatureList scoped_features_;
+ base::HistogramTester histogram_tester_;
+};
+
+// Tests for API enterprise.reportingPrivate.getFileSystemInfo
+class EnterpriseReportingPrivateGetFileSystemInfoTest
+ : public UserContextGatedTest {
+ protected:
+ void SetUp() override {
+ UserContextGatedTest::SetUp();
+
+ SetFeatureFlag();
+
+ function_ = base::MakeRefCounted<
+ EnterpriseReportingPrivateGetFileSystemInfoFunction>();
+ }
+
+ device_signals::SignalName signal_name() {
+ return device_signals::SignalName::kFileSystemInfo;
+ }
+
+ enterprise_reporting_private::GetFileSystemInfoOptions
+ GetFakeFileSystemOptionsParam() const {
+ enterprise_reporting_private::GetFileSystemInfoOptions api_param;
+ api_param.path = "some file path";
+ api_param.compute_sha256 = true;
+ return api_param;
+ }
+
+ std::string GetFakeRequest() const {
+ enterprise_reporting_private::GetFileSystemInfoRequest request;
+ request.user_context = GetFakeUserContext();
+ request.options.push_back(GetFakeFileSystemOptionsParam());
+ base::ListValue params;
+ params.Append(base::Value::FromUniquePtrValue(request.ToValue()));
+ std::string json_value;
+ base::JSONWriter::Write(params, &json_value);
+ return json_value;
+ }
+
+ scoped_refptr<extensions::EnterpriseReportingPrivateGetFileSystemInfoFunction>
+ function_;
+};
+
+TEST_F(EnterpriseReportingPrivateGetFileSystemInfoTest, Success) {
+ device_signals::FileSystemItem fake_file_item;
+ fake_file_item.file_path = base::FilePath();
+ fake_file_item.presence = device_signals::PresenceValue::kFound;
+ fake_file_item.sha256_hash = "some hashed value";
+
+ device_signals::FileSystemInfoResponse signal_response;
+ signal_response.file_system_items.push_back(fake_file_item);
+
+ device_signals::SignalsAggregationResponse expected_response;
+ expected_response.file_system_info_response = signal_response;
+
+ SetFakeResponse(expected_response);
+
+ auto response = api_test_utils::RunFunctionAndReturnSingleResult(
+ function_.get(), GetFakeRequest(), profile());
+
+ EXPECT_EQ(function_->GetError(), kNoError);
+
+ ASSERT_TRUE(response);
+ ASSERT_TRUE(response->is_list());
+ const base::Value::List& list_value = response->GetList();
+ ASSERT_EQ(list_value.size(), signal_response.file_system_items.size());
+
+ const base::Value& file_system_value = list_value.front();
+ auto parsed_file_system_signal =
+ enterprise_reporting_private::GetFileSystemInfoResponse::FromValue(
+ file_system_value);
+ ASSERT_TRUE(parsed_file_system_signal);
+ EXPECT_EQ(parsed_file_system_signal->path,
+ fake_file_item.file_path.AsUTF8Unsafe());
+ EXPECT_EQ(parsed_file_system_signal->presence,
+ enterprise_reporting_private::PRESENCE_VALUE_FOUND);
+ EXPECT_EQ(*parsed_file_system_signal->sha256_hash.get(),
+ "c29tZSBoYXNoZWQgdmFsdWU");
+
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Success", signal_name(), 1);
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Success.FileSystemInfo.Items",
+ /*number_of_items=*/1,
+ /*number_of_occurrences=*/1);
+}
+
+TEST_F(EnterpriseReportingPrivateGetFileSystemInfoTest, TopLevelError) {
+ device_signals::SignalCollectionError expected_error =
+ device_signals::SignalCollectionError::kConsentRequired;
+
+ device_signals::SignalsAggregationResponse expected_response;
+ expected_response.top_level_error = expected_error;
+ SetFakeResponse(expected_response);
+
+ auto error = api_test_utils::RunFunctionAndReturnError(
+ function_.get(), GetFakeRequest(), profile());
+
+ EXPECT_EQ(error, function_->GetError());
+ EXPECT_EQ(error, device_signals::ErrorToString(expected_error));
+
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure", signal_name(), 1);
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure.FileSystemInfo."
+ "TopLevelError",
+ /*error=*/expected_error,
+ /*number_of_occurrences=*/1);
+}
+
+TEST_F(EnterpriseReportingPrivateGetFileSystemInfoTest, CollectionError) {
+ device_signals::SignalCollectionError expected_error =
+ device_signals::SignalCollectionError::kMissingSystemService;
+
+ device_signals::FileSystemInfoResponse signal_response;
+ signal_response.collection_error = expected_error;
+
+ device_signals::SignalsAggregationResponse expected_response;
+ expected_response.file_system_info_response = signal_response;
+ SetFakeResponse(expected_response);
+
+ auto error = api_test_utils::RunFunctionAndReturnError(
+ function_.get(), GetFakeRequest(), profile());
+
+ EXPECT_EQ(error, function_->GetError());
+ EXPECT_EQ(error, device_signals::ErrorToString(expected_error));
+
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure", signal_name(), 1);
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure.FileSystemInfo."
+ "CollectionLevelError",
+ /*error=*/expected_error,
+ /*number_of_occurrences=*/1);
+}
+
+class EnterpriseReportingPrivateGetFileSystemInfoDisabledTest
+ : public EnterpriseReportingPrivateGetFileSystemInfoTest {
+ protected:
+ // Overwrite this function to disable the feature flag for tests using this
+ // specific fixture.
+ void SetFeatureFlag() override {
+ scoped_features_.InitAndEnableFeatureWithParameters(
+ enterprise_signals::features::kNewEvSignalsEnabled,
+ {{"DisableFileSystemInfo", "true"}});
+ }
+};
+
+TEST_F(EnterpriseReportingPrivateGetFileSystemInfoDisabledTest,
+ FlagDisabled_Test) {
+ auto error = api_test_utils::RunFunctionAndReturnError(
+ function_.get(), GetFakeRequest(), profile());
+ EXPECT_EQ(error, function_->GetError());
+ EXPECT_EQ(error, device_signals::ErrorToString(
+ device_signals::SignalCollectionError::kUnsupported));
+}
+
+// Tests for API enterprise.reportingPrivate.getAvInfo
+class EnterpriseReportingPrivateGetAvInfoTest : public UserContextGatedTest {
+ protected:
+ void SetUp() override {
+ UserContextGatedTest::SetUp();
+
+ SetFeatureFlag();
+
+ function_ =
+ base::MakeRefCounted<EnterpriseReportingPrivateGetAvInfoFunction>();
+ }
+
+ device_signals::SignalName signal_name() {
+ return device_signals::SignalName::kAntiVirus;
+ }
+
+ scoped_refptr<extensions::EnterpriseReportingPrivateGetAvInfoFunction>
+ function_;
+};
+
+TEST_F(EnterpriseReportingPrivateGetAvInfoTest, Success) {
+ device_signals::AvProduct fake_av_product;
+ fake_av_product.display_name = "Fake display name";
+ fake_av_product.state = device_signals::AvProductState::kOff;
+ fake_av_product.product_id = "fake product id";
+
+ device_signals::AntiVirusSignalResponse av_response;
+ av_response.av_products.push_back(fake_av_product);
+
+ device_signals::SignalsAggregationResponse expected_response;
+ expected_response.av_signal_response = av_response;
+
+ SetFakeResponse(expected_response);
+
+ auto response = api_test_utils::RunFunctionAndReturnSingleResult(
+ function_.get(), GetFakeUserContextJsonParams(), profile());
+
+ EXPECT_EQ(function_->GetError(), kNoError);
+
+ ASSERT_TRUE(response);
+ ASSERT_TRUE(response->is_list());
+ const base::Value::List& list_value = response->GetList();
+ ASSERT_EQ(list_value.size(), av_response.av_products.size());
+
+ const base::Value& av_value = list_value.front();
+ auto parsed_av_signal =
+ enterprise_reporting_private::AntiVirusSignal::FromValue(av_value);
+ ASSERT_TRUE(parsed_av_signal);
+ EXPECT_EQ(parsed_av_signal->display_name, fake_av_product.display_name);
+ EXPECT_EQ(parsed_av_signal->state,
+ enterprise_reporting_private::ANTI_VIRUS_PRODUCT_STATE_OFF);
+ EXPECT_EQ(parsed_av_signal->product_id, fake_av_product.product_id);
+
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Success", signal_name(), 1);
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Success.AntiVirus.Items",
+ /*number_of_items=*/1,
+ /*number_of_occurrences=*/1);
+}
+
+TEST_F(EnterpriseReportingPrivateGetAvInfoTest, TopLevelError) {
+ device_signals::SignalCollectionError expected_error =
+ device_signals::SignalCollectionError::kConsentRequired;
+
+ device_signals::SignalsAggregationResponse expected_response;
+ expected_response.top_level_error = expected_error;
+ SetFakeResponse(expected_response);
+
+ auto error = api_test_utils::RunFunctionAndReturnError(
+ function_.get(), GetFakeUserContextJsonParams(), profile());
+
+ EXPECT_EQ(error, function_->GetError());
+ EXPECT_EQ(error, device_signals::ErrorToString(expected_error));
+
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure", signal_name(), 1);
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure.AntiVirus.TopLevelError",
+ /*error=*/expected_error,
+ /*number_of_occurrences=*/1);
+}
+
+TEST_F(EnterpriseReportingPrivateGetAvInfoTest, CollectionError) {
+ device_signals::SignalCollectionError expected_error =
+ device_signals::SignalCollectionError::kMissingSystemService;
+
+ device_signals::AntiVirusSignalResponse av_response;
+ av_response.collection_error = expected_error;
+
+ device_signals::SignalsAggregationResponse expected_response;
+ expected_response.av_signal_response = av_response;
+ SetFakeResponse(expected_response);
+
+ auto error = api_test_utils::RunFunctionAndReturnError(
+ function_.get(), GetFakeUserContextJsonParams(), profile());
+
+ EXPECT_EQ(error, function_->GetError());
+ EXPECT_EQ(error, device_signals::ErrorToString(expected_error));
+
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure", signal_name(), 1);
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure.AntiVirus."
+ "CollectionLevelError",
+ /*error=*/expected_error,
+ /*number_of_occurrences=*/1);
+}
+
+class EnterpriseReportingPrivateGetAvInfoDisabledTest
+ : public EnterpriseReportingPrivateGetAvInfoTest {
+ protected:
+ // Overwrite this function to disable the feature flag for tests using this
+ // specific fixture.
+ void SetFeatureFlag() override {
+ scoped_features_.InitAndEnableFeatureWithParameters(
+ enterprise_signals::features::kNewEvSignalsEnabled,
+ {{"DisableAntiVirus", "true"}});
+ }
+};
+
+TEST_F(EnterpriseReportingPrivateGetAvInfoDisabledTest, FlagDisabled_Test) {
+ auto error = api_test_utils::RunFunctionAndReturnError(
+ function_.get(), GetFakeUserContextJsonParams(), profile());
+ EXPECT_EQ(error, function_->GetError());
+ EXPECT_EQ(error, device_signals::ErrorToString(
+ device_signals::SignalCollectionError::kUnsupported));
+}
+
+// Tests for API enterprise.reportingPrivate.getHotfixes
+class EnterpriseReportingPrivateGetHotfixesTest : public UserContextGatedTest {
+ protected:
+ void SetUp() override {
+ UserContextGatedTest::SetUp();
+
+ SetFeatureFlag();
+
+ function_ =
+ base::MakeRefCounted<EnterpriseReportingPrivateGetHotfixesFunction>();
+ }
+
+ device_signals::SignalName signal_name() {
+ return device_signals::SignalName::kHotfixes;
+ }
+
+ scoped_refptr<extensions::EnterpriseReportingPrivateGetHotfixesFunction>
+ function_;
+};
+
+TEST_F(EnterpriseReportingPrivateGetHotfixesTest, Success) {
+ static constexpr char kFakeHotfixId[] = "hotfix id";
+ device_signals::HotfixSignalResponse hotfix_response;
+ hotfix_response.hotfixes.push_back({kFakeHotfixId});
+
+ device_signals::SignalsAggregationResponse expected_response;
+ expected_response.hotfix_signal_response = hotfix_response;
+
+ SetFakeResponse(expected_response);
+
+ auto response = api_test_utils::RunFunctionAndReturnSingleResult(
+ function_.get(), GetFakeUserContextJsonParams(), profile());
+
+ EXPECT_EQ(function_->GetError(), kNoError);
+
+ ASSERT_TRUE(response);
+ ASSERT_TRUE(response->is_list());
+ const base::Value::List& list_value = response->GetList();
+ ASSERT_EQ(list_value.size(), hotfix_response.hotfixes.size());
+
+ const base::Value& hotfix_value = list_value.front();
+ auto parsed_hotfix =
+ enterprise_reporting_private::HotfixSignal::FromValue(hotfix_value);
+ ASSERT_TRUE(parsed_hotfix);
+ EXPECT_EQ(parsed_hotfix->hotfix_id, kFakeHotfixId);
+
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Success", signal_name(), 1);
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Success.Hotfixes.Items",
+ /*number_of_items=*/1,
+ /*number_of_occurrences=*/1);
+}
+
+TEST_F(EnterpriseReportingPrivateGetHotfixesTest, TopLevelError) {
+ device_signals::SignalCollectionError expected_error =
+ device_signals::SignalCollectionError::kConsentRequired;
+
+ device_signals::SignalsAggregationResponse expected_response;
+ expected_response.top_level_error = expected_error;
+ SetFakeResponse(expected_response);
+
+ auto error = api_test_utils::RunFunctionAndReturnError(
+ function_.get(), GetFakeUserContextJsonParams(), profile());
+
+ EXPECT_EQ(error, function_->GetError());
+ EXPECT_EQ(error, device_signals::ErrorToString(expected_error));
+
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure", signal_name(), 1);
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure.Hotfixes.TopLevelError",
+ /*error=*/expected_error,
+ /*number_of_occurrences=*/1);
+}
+
+TEST_F(EnterpriseReportingPrivateGetHotfixesTest, CollectionError) {
+ device_signals::SignalCollectionError expected_error =
+ device_signals::SignalCollectionError::kMissingSystemService;
+
+ device_signals::HotfixSignalResponse hotfix_response;
+ hotfix_response.collection_error = expected_error;
+
+ device_signals::SignalsAggregationResponse expected_response;
+ expected_response.hotfix_signal_response = hotfix_response;
+ SetFakeResponse(expected_response);
+
+ auto error = api_test_utils::RunFunctionAndReturnError(
+ function_.get(), GetFakeUserContextJsonParams(), profile());
+
+ EXPECT_EQ(error, function_->GetError());
+ EXPECT_EQ(error, device_signals::ErrorToString(expected_error));
+
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure", signal_name(), 1);
+ histogram_tester_.ExpectUniqueSample(
+ "Enterprise.DeviceSignals.Collection.Failure.Hotfixes."
+ "CollectionLevelError",
+ /*error=*/expected_error,
+ /*number_of_occurrences=*/1);
+}
+
+class EnterpriseReportingPrivateGetHotfixesInfoDisabledTest
+ : public EnterpriseReportingPrivateGetHotfixesTest {
+ protected:
+ // Overwrite this function to disable the feature flag for tests using this
+ // specific fixture.
+ void SetFeatureFlag() override {
+ scoped_features_.InitAndEnableFeatureWithParameters(
+ enterprise_signals::features::kNewEvSignalsEnabled,
+ {{"DisableHotfix", "true"}});
+ }
+};
+
+TEST_F(EnterpriseReportingPrivateGetHotfixesInfoDisabledTest,
+ FlagDisabled_Test) {
+ auto error = api_test_utils::RunFunctionAndReturnError(
+ function_.get(), GetFakeUserContextJsonParams(), profile());
+ EXPECT_EQ(error, function_->GetError());
+ EXPECT_EQ(error, device_signals::ErrorToString(
+ device_signals::SignalCollectionError::kUnsupported));
+}
+
+#endif // BUILDFLAG(IS_WIN)
+
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.mm b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.mm
index ca810f8158a..05e95beacb9 100644
--- a/chromium/chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.mm
+++ b/chromium/chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.mm
@@ -15,6 +15,12 @@
namespace extensions {
namespace {
+// Much of the Keychain API was marked deprecated as of the macOS 13 SDK.
+// Removal of its use is tracked in https://crbug.com/1348251 but deprecation
+// warnings are disabled in the meanwhile.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
// Creates an access for a generic password item to share it with other Google
// applications with teamid:EQHXZ8M8AV (taken from the signing certificate).
OSStatus CreateTargetAccess(NSString* service_name, SecAccessRef* access_ref) {
@@ -116,4 +122,6 @@ OSStatus VerifyDefaultKeychainUnlocked(bool* unlocked) {
return VerifyKeychainUnlocked(keychain, unlocked);
}
+#pragma clang diagnostic pop
+
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
index 0b7ae5b359e..38901384b55 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -548,7 +548,8 @@ IN_PROC_BROWSER_TEST_P(BrowserActionApiTestWithContextType,
// Go back to first tab, changed title should reappear.
browser()->tab_strip_model()->ActivateTabAt(
- 0, {TabStripModel::GestureType::kOther});
+ 0, TabStripUserGestureDetails(
+ TabStripUserGestureDetails::GestureType::kOther));
EXPECT_EQ("Showing icon 2",
GetBrowserActionsBar()->GetTooltip(extension->id()));
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 4f2a14feff9..f4ba6142b99 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
@@ -34,6 +34,8 @@
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/download_test_observer.h"
+#include "content/public/test/fenced_frame_test_util.h"
+#include "content/public/test/test_navigation_observer.h"
#include "extensions/browser/extension_action.h"
#include "extensions/browser/extension_action_manager.h"
#include "extensions/browser/extension_host.h"
@@ -72,7 +74,7 @@ namespace {
bool IsDownloadSurfaceVisible(BrowserWindow* window) {
return base::FeatureList::IsEnabled(safe_browsing::kDownloadBubble)
? window->GetDownloadBubbleUIController()
- ->display_controller_for_testing()
+ ->GetDownloadDisplayController()
->download_display_for_testing()
->IsShowingDetails()
: window->IsDownloadShelfVisible();
@@ -432,7 +434,8 @@ IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TabSwitchClosesPopup) {
ExtensionHostTestHelper host_helper(profile());
// Change active tabs, the extension popup should close.
browser()->tab_strip_model()->ActivateTabAt(
- 0, {TabStripModel::GestureType::kOther});
+ 0, TabStripUserGestureDetails(
+ TabStripUserGestureDetails::GestureType::kOther));
host_helper.WaitForHostDestroyed();
EXPECT_FALSE(ExtensionActionTestHelper::Create(browser())->HasPopup());
@@ -613,8 +616,9 @@ class MainFrameSizeWaiter : public content::WebContentsObserver {
// TODO(crbug.com/1249851): Test crashes on Windows
#if BUILDFLAG(IS_WIN)
#define MAYBE_BrowserActionPopup DISABLED_BrowserActionPopup
-#elif BUILDFLAG(IS_LINUX) && defined(THREAD_SANITIZER)
-// TODO(crbug.com/1269076): Test is flaky for linux tsan builds
+#elif BUILDFLAG(IS_LINUX) && \
+ (defined(THREAD_SANITIZER) || defined(ADDRESS_SANITIZER))
+// TODO(crbug.com/1269076): Test is flaky for linux tsan and asan builds
#define MAYBE_BrowserActionPopup DISABLED_BrowserActionPopup
#elif BUILDFLAG(IS_MAC)
// TODO(crbug.com/1269076): Test is flaky on Mac as well.
@@ -786,7 +790,6 @@ class RenderFrameChangedWatcher : public content::WebContentsObserver {
IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
BrowserActionPopupWithIframe) {
ASSERT_TRUE(embedded_test_server()->Start());
-
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("browser_action/popup_with_iframe")));
const Extension* extension = GetSingleLoadedExtension();
@@ -832,6 +835,71 @@ IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
EXPECT_TRUE(ClosePopup());
}
+class BrowserActionInteractiveFencedFrameTest
+ : public BrowserActionInteractiveTest {
+ public:
+ ~BrowserActionInteractiveFencedFrameTest() override = default;
+
+ content::test::FencedFrameTestHelper& fenced_frame_test_helper() {
+ return fenced_frame_test_helper_;
+ }
+
+ private:
+ content::test::FencedFrameTestHelper fenced_frame_test_helper_;
+};
+
+IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveFencedFrameTest,
+ BrowserActionPopupWithFencedFrame) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
+ https_server.ServeFilesFromSourceDirectory("chrome/test/data");
+ ASSERT_TRUE(https_server.Start());
+
+ ASSERT_TRUE(LoadExtension(
+ test_data_dir_.AppendASCII("browser_action/popup_with_fencedframe")));
+ const Extension* extension = GetSingleLoadedExtension();
+ ASSERT_TRUE(extension) << message_;
+
+ // Simulate a click on the browser action to open the popup.
+ ASSERT_TRUE(OpenPopupViaToolbar(extension->id()));
+
+ // Find a primary main frame associated in the popup.
+ extensions::ProcessManager* manager =
+ extensions::ProcessManager::Get(browser()->profile());
+ std::set<content::RenderFrameHost*> hosts =
+ manager->GetRenderFrameHostsForExtension(extension->id());
+ const auto& it =
+ base::ranges::find_if(hosts, [](content::RenderFrameHost* host) {
+ return host->IsInPrimaryMainFrame();
+ });
+ content::RenderFrameHost* primary_rfh = (it != hosts.end()) ? *it : nullptr;
+ ASSERT_TRUE(primary_rfh);
+
+ // 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
+ // the page has loaded.
+ GURL foo_url(https_server.GetURL("a.test", "/popup_fencedframe.html"));
+
+ content::TestNavigationObserver observer(
+ content::WebContents::FromRenderFrameHost(primary_rfh));
+ std::string script =
+ "document.querySelector('fencedframe').src = '" + foo_url.spec() + "'";
+ EXPECT_TRUE(ExecuteScript(primary_rfh, script));
+ observer.WaitForNavigationFinished();
+
+ content::RenderFrameHost* fenced_frame_rfh =
+ fenced_frame_test_helper().GetMostRecentlyAddedFencedFrame(primary_rfh);
+ ASSERT_TRUE(fenced_frame_rfh);
+
+ // Confirm that the new page (popup_fencedframe.html) is actually loaded.
+ content::DOMMessageQueue dom_message_queue(fenced_frame_rfh);
+ std::string json;
+ EXPECT_TRUE(dom_message_queue.WaitForMessage(&json));
+ EXPECT_EQ("\"DONE\"", json);
+
+ EXPECT_TRUE(ClosePopup());
+}
+
class NavigatingExtensionPopupInteractiveTest
: public BrowserActionInteractiveTest {
public:
diff --git a/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index 7cd02548061..a105cbb6757 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -280,8 +280,7 @@ void ExtensionActionAPI::DispatchEventToExtension(
return;
auto event = std::make_unique<Event>(
- histogram_value, event_name, std::move(*event_args).TakeListDeprecated(),
- context);
+ histogram_value, event_name, std::move(event_args->GetList()), context);
event->user_gesture = EventRouter::USER_GESTURE_ENABLED;
EventRouter::Get(context)
->DispatchEventToExtension(extension_id, std::move(event));
@@ -486,9 +485,9 @@ ExtensionActionSetIconFunction::RunExtensionAction() {
ExtensionFunction::ResponseAction
ExtensionActionSetTitleFunction::RunExtensionAction() {
EXTENSION_FUNCTION_VALIDATE(details_);
- std::string title;
- EXTENSION_FUNCTION_VALIDATE(details_->GetString("title", &title));
- extension_action_->SetTitle(tab_id_, title);
+ const std::string* title = details_->GetDict().FindString("title");
+ EXTENSION_FUNCTION_VALIDATE(title);
+ extension_action_->SetTitle(tab_id_, *title);
NotifyChange();
return RespondNow(NoArguments());
}
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 67f4ee4607b..0373a5692d7 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
@@ -18,6 +18,7 @@
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/extensions/extension_action_test_helper.h"
+#include "chrome/browser/ui/tabs/tab_enums.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
#include "chrome/test/base/ui_test_utils.h"
@@ -388,7 +389,7 @@ IN_PROC_BROWSER_TEST_P(MultiActionAPITest,
{
content::WebContentsDestroyedWatcher destroyed_watcher(web_contents);
tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(),
- TabStripModel::CLOSE_NONE);
+ TabCloseTypes::CLOSE_NONE);
destroyed_watcher.Wait();
}
// The title should have been cleared on tab removal as well.
@@ -738,7 +739,8 @@ IN_PROC_BROWSER_TEST_P(ActionAndBrowserActionAPITest, ValuesArePersisted) {
}
// Tests setting the icon dynamically from the background page.
-IN_PROC_BROWSER_TEST_P(MultiActionAPICanvasTest, DynamicSetIcon) {
+// TODO(crbug.com/1340330): flaky.
+IN_PROC_BROWSER_TEST_P(MultiActionAPICanvasTest, DISABLED_DynamicSetIcon) {
constexpr char kManifestTemplate[] =
R"({
"name": "Test Clicking",
diff --git a/chromium/chrome/browser/extensions/api/extension_action/page_action_apitest.cc b/chromium/chrome/browser/extensions/api/extension_action/page_action_apitest.cc
index 7c8ef6f371e..c223d12d335 100644
--- a/chromium/chrome/browser/extensions/api/extension_action/page_action_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/extension_action/page_action_apitest.cc
@@ -222,7 +222,8 @@ IN_PROC_BROWSER_TEST_P(PageActionApiTest, TestTriggerPageAction) {
browser(), embedded_test_server()->GetURL("/simple.html")));
chrome::NewTab(browser());
browser()->tab_strip_model()->ActivateTabAt(
- 0, {TabStripModel::GestureType::kOther});
+ 0, TabStripUserGestureDetails(
+ TabStripUserGestureDetails::GestureType::kOther));
// Give the extension time to show the page action on the tab.
WaitForPageActionVisibilityChangeTo(1);
diff --git a/chromium/chrome/browser/extensions/api/favicon/favicon_util_unittest.cc b/chromium/chrome/browser/extensions/api/favicon/favicon_util_unittest.cc
index 5c192857434..f92639f8a73 100644
--- a/chromium/chrome/browser/extensions/api/favicon/favicon_util_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/favicon/favicon_util_unittest.cc
@@ -22,12 +22,12 @@ TEST(FaviconUtilUnittest, Parse) {
{false, "chrome-extension://id/_favicon"},
{false, "chrome-extension://id/_favicon/"},
{false, "chrome-extension://id/_favicon/?"},
- {true, "chrome-extension://id/_favicon?page_url=https://ok.com"},
- {true, "chrome-extension://id/_favicon/?page_url=https://ok.com"},
- {true, "chrome-extension://id/_favicon/?page_url=https://ok.com&size=16"},
+ {true, "chrome-extension://id/_favicon?pageUrl=https://ok.com"},
+ {true, "chrome-extension://id/_favicon/?pageUrl=https://ok.com"},
+ {true, "chrome-extension://id/_favicon/?pageUrl=https://ok.com&size=16"},
{true,
- "chrome-extension://id/_favicon/?page_url=https://"
- "ok.com&size=16&scale_factor=1.0x&server_fallback=1"}};
+ "chrome-extension://id/_favicon/?pageUrl=https://"
+ "ok.com&size=16&scaleFactor=1.0x&server_fallback=1"}};
for (const auto& test_case : test_cases) {
GURL url(test_case.url);
chrome::ParsedFaviconPath parsed;
diff --git a/chromium/chrome/browser/extensions/api/file_browser_handler/file_browser_handler_flow_lacros.cc b/chromium/chrome/browser/extensions/api/file_browser_handler/file_browser_handler_flow_lacros.cc
index 7963fefbc17..dde4f12df87 100644
--- a/chromium/chrome/browser/extensions/api/file_browser_handler/file_browser_handler_flow_lacros.cc
+++ b/chromium/chrome/browser/extensions/api/file_browser_handler/file_browser_handler_flow_lacros.cc
@@ -12,6 +12,7 @@
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/memory/raw_ptr.h"
#include "base/values.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h"
@@ -76,7 +77,7 @@ class FileBrowserHandlerExecutorFlow {
FileBrowserHandlerFlowFinishedCallback done_;
- Profile* profile_;
+ raw_ptr<Profile> profile_;
scoped_refptr<const Extension> extension_;
// Inputs owned by the class.
@@ -243,8 +244,7 @@ void FileBrowserHandlerExecutorFlow::GrantAccessToFilesAndLaunch(
auto event = std::make_unique<extensions::Event>(
extensions::events::FILE_BROWSER_HANDLER_ON_EXECUTE,
- "fileBrowserHandler.onExecute",
- base::Value(std::move(event_args)).TakeListDeprecated(), profile_);
+ "fileBrowserHandler.onExecute", std::move(event_args), profile_);
router->DispatchEventToExtension(extension_->id(), std::move(event));
Finish(true); // Success.
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 29346dc0038..e9747993b4c 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
@@ -6,74 +6,48 @@
#include <string>
#include <utility>
-#include <vector>
#include "apps/saved_files_service.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/check.h"
-#include "base/files/file_path.h"
+#include "base/notreached.h"
#include "base/path_service.h"
-#include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
#include "chrome/browser/download/chrome_download_manager_delegate.h"
#include "chrome/browser/download/download_core_service.h"
#include "chrome/browser/download/download_core_service_factory.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/extensions/api/file_system/file_entry_picker.h"
-#include "chrome/browser/extensions/chrome_extension_function_details.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/apps/directory_access_confirmation_dialog.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/grit/generated_resources.h"
#include "content/public/browser/browser_context.h"
-#include "content/public/browser/child_process_security_policy.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
-#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
#include "extensions/browser/api/file_system/saved_files_service_interface.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
-#include "extensions/browser/extension_function.h"
-#include "extensions/browser/extension_prefs.h"
-#include "extensions/browser/extension_system.h"
-#include "extensions/browser/extension_util.h"
-#include "extensions/common/api/file_system.h"
#include "extensions/common/extension.h"
-#include "storage/browser/file_system/external_mount_points.h"
-#include "storage/browser/file_system/isolated_context.h"
-#include "storage/common/file_system/file_system_types.h"
#include "storage/common/file_system/file_system_util.h"
-#include "third_party/blink/public/common/storage_key/storage_key.h"
-#include "ui/shell_dialogs/select_file_dialog.h"
#if BUILDFLAG(IS_MAC)
#include <CoreFoundation/CoreFoundation.h>
#include "base/mac/foundation_util.h"
#endif
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chrome/browser/ash/file_manager/volume_manager.h"
-#include "chrome/browser/extensions/api/file_system/consent_provider.h"
+#if BUILDFLAG(IS_CHROMEOS)
#include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/common/constants.h"
-#include "url/gurl.h"
-#include "url/origin.h"
-#include "url/url_constants.h"
-#endif
+#endif // BUILDFLAG(IS_CHROMEOS)
namespace extensions {
namespace file_system = api::file_system;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
using file_system_api::ConsentProvider;
using file_system_api::ConsentProviderDelegate;
-namespace {
+namespace file_system_api {
const char kConsentImpossible[] =
"Impossible to ask for user consent as there is no app window visible.";
@@ -84,173 +58,27 @@ const char kRequiresFileSystemWriteError[] =
const char kSecurityError[] = "Security error.";
const char kVolumeNotFoundError[] = "Volume not found.";
-// Fills a list of volumes mounted in the system.
-bool GetVolumeListForExtension(
- const std::vector<base::WeakPtr<file_manager::Volume>>& available_volumes,
- ConsentProvider* consent_provider,
- const Extension& extension,
- std::vector<file_system::Volume>* result_volumes) {
- if (!consent_provider)
- return false;
-
- const FileSystemDelegate::GrantVolumesMode mode =
- consent_provider->GetGrantVolumesMode(extension);
- if (mode == FileSystemDelegate::kGrantNone)
- return false;
-
- // Convert available_volumes to result_volume_list.
- for (const auto& volume : available_volumes) {
- if (mode == FileSystemDelegate::kGrantAll ||
- (mode == FileSystemDelegate::kGrantPerVolume &&
- consent_provider->IsGrantableForVolume(extension, volume))) {
- file_system::Volume result_volume;
- result_volume.volume_id = volume->volume_id();
- result_volume.writable = !volume->is_read_only();
- result_volumes->push_back(std::move(result_volume));
- }
- }
- return true;
-}
-
-// Callback called when consent is granted or denied.
-void OnConsentReceived(content::BrowserContext* browser_context,
- scoped_refptr<ExtensionFunction> requester,
- FileSystemDelegate::FileSystemCallback success_callback,
- FileSystemDelegate::ErrorCallback error_callback,
- const url::Origin& origin,
- const base::WeakPtr<file_manager::Volume>& volume,
- bool writable,
- ConsentProvider::Consent result) {
- using file_manager::VolumeManager;
- using file_manager::Volume;
-
- // Render frame host can be gone before this callback method is executed.
- if (!requester->render_frame_host()) {
- std::move(error_callback).Run(std::string());
- return;
- }
-
+// Returns error message, or null if none.
+const char* ConsentResultToError(ConsentProvider::Consent result) {
switch (result) {
case ConsentProvider::CONSENT_REJECTED:
- std::move(error_callback).Run(kSecurityError);
- return;
-
+ return kSecurityError;
case ConsentProvider::CONSENT_IMPOSSIBLE:
- std::move(error_callback).Run(kConsentImpossible);
- return;
-
+ return kConsentImpossible;
case ConsentProvider::CONSENT_GRANTED:
- break;
- }
-
- if (!volume.get()) {
- std::move(error_callback).Run(kVolumeNotFoundError);
- return;
- }
-
- DCHECK_EQ(origin.scheme(), kExtensionScheme);
- scoped_refptr<storage::FileSystemContext> file_system_context =
- util::GetStoragePartitionForExtensionId(origin.host(), browser_context)
- ->GetFileSystemContext();
- storage::ExternalFileSystemBackend* const backend =
- file_system_context->external_backend();
- DCHECK(backend);
-
- base::FilePath virtual_path;
- if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) {
- std::move(error_callback).Run(kSecurityError);
- return;
- }
-
- storage::IsolatedContext* const isolated_context =
- storage::IsolatedContext::GetInstance();
- DCHECK(isolated_context);
-
- const storage::FileSystemURL original_url =
- file_system_context->CreateCrackedFileSystemURL(
- blink::StorageKey(origin), storage::kFileSystemTypeExternal,
- virtual_path);
-
- // Set a fixed register name, as the automatic one would leak the mount point
- // directory.
- std::string register_name = "fs";
- const storage::IsolatedContext::ScopedFSHandle file_system =
- isolated_context->RegisterFileSystemForPath(
- storage::kFileSystemTypeLocalForPlatformApp,
- std::string() /* file_system_id */, original_url.path(),
- &register_name);
- if (!file_system.is_valid()) {
- std::move(error_callback).Run(kSecurityError);
- return;
- }
-
- backend->GrantFileAccessToOrigin(origin, virtual_path);
-
- // Grant file permissions to the renderer hosting component.
- content::ChildProcessSecurityPolicy* policy =
- content::ChildProcessSecurityPolicy::GetInstance();
- DCHECK(policy);
-
- const auto process_id = requester->source_process_id();
- // Read-only permisisons.
- policy->GrantReadFile(process_id, volume->mount_path());
- policy->GrantReadFileSystem(process_id, file_system.id());
-
- // Additional write permissions.
- if (writable) {
- policy->GrantCreateReadWriteFile(process_id, volume->mount_path());
- policy->GrantCopyInto(process_id, volume->mount_path());
- policy->GrantWriteFileSystem(process_id, file_system.id());
- policy->GrantDeleteFromFileSystem(process_id, file_system.id());
- policy->GrantCreateFileForFileSystem(process_id, file_system.id());
- }
-
- std::move(success_callback).Run(file_system.id(), register_name);
-}
-
-} // namespace
-
-namespace file_system_api {
-
-void DispatchVolumeListChangeEvent(content::BrowserContext* browser_context) {
- DCHECK(browser_context);
- EventRouter* const event_router = EventRouter::Get(browser_context);
- if (!event_router) // Possible on shutdown.
- return;
-
- ExtensionRegistry* const registry = ExtensionRegistry::Get(browser_context);
- if (!registry) // Possible on shutdown.
- return;
-
- ConsentProviderDelegate consent_provider_delegate(
- Profile::FromBrowserContext(browser_context));
- ConsentProvider consent_provider(&consent_provider_delegate);
-
- const std::vector<base::WeakPtr<file_manager::Volume>> volume_list =
- file_manager::VolumeManager::Get(browser_context)->GetVolumeList();
-
- for (const auto& extension : registry->enabled_extensions()) {
- file_system::VolumeListChangedEvent event_args;
- if (!GetVolumeListForExtension(volume_list, &consent_provider,
- *extension.get(), &event_args.volumes)) {
- continue;
- }
-
- event_router->DispatchEventToExtension(
- extension->id(),
- std::make_unique<Event>(
- events::FILE_SYSTEM_ON_VOLUME_LIST_CHANGED,
- file_system::OnVolumeListChanged::kEventName,
- file_system::OnVolumeListChanged::Create(event_args)));
+ return nullptr;
}
+ NOTREACHED();
}
} // namespace file_system_api
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS)
-ChromeFileSystemDelegate::ChromeFileSystemDelegate() {}
+/******** ChromeFileSystemDelegate ********/
-ChromeFileSystemDelegate::~ChromeFileSystemDelegate() {}
+ChromeFileSystemDelegate::ChromeFileSystemDelegate() = default;
+
+ChromeFileSystemDelegate::~ChromeFileSystemDelegate() = default;
base::FilePath ChromeFileSystemDelegate::GetDefaultDirectory() {
base::FilePath documents_dir;
@@ -337,18 +165,15 @@ int ChromeFileSystemDelegate::GetDescriptionIdForAcceptType(
return 0;
}
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-FileSystemDelegate::GrantVolumesMode
-ChromeFileSystemDelegate::GetGrantVolumesMode(
+#if BUILDFLAG(IS_CHROMEOS)
+bool ChromeFileSystemDelegate::IsGrantable(
content::BrowserContext* browser_context,
- content::RenderFrameHost* render_frame_host,
const Extension& extension) {
// Only kiosk apps in kiosk sessions can use this API.
// Additionally it is enabled for allowlisted component extensions and apps.
ConsentProviderDelegate consent_provider_delegate(
Profile::FromBrowserContext(browser_context));
- return ConsentProvider(&consent_provider_delegate)
- .GetGrantVolumesMode(extension);
+ return ConsentProvider(&consent_provider_delegate).IsGrantable(extension);
}
void ChromeFileSystemDelegate::RequestFileSystem(
@@ -358,82 +183,13 @@ void ChromeFileSystemDelegate::RequestFileSystem(
std::string volume_id,
bool writable,
FileSystemCallback success_callback,
- ErrorCallback error_callback) {
- ConsentProviderDelegate consent_provider_delegate(
- Profile::FromBrowserContext(browser_context));
- ConsentProvider consent_provider(&consent_provider_delegate);
-
- using file_manager::VolumeManager;
- using file_manager::Volume;
- VolumeManager* const volume_manager = VolumeManager::Get(browser_context);
- DCHECK(volume_manager);
-
- if (writable &&
- !app_file_handler_util::HasFileSystemWritePermission(&extension)) {
- std::move(error_callback).Run(kRequiresFileSystemWriteError);
- return;
- }
-
- if (consent_provider.GetGrantVolumesMode(extension) ==
- FileSystemDelegate::kGrantNone) {
- std::move(error_callback).Run(kNotSupportedOnNonKioskSessionError);
- return;
- }
-
- base::WeakPtr<file_manager::Volume> volume =
- volume_manager->FindVolumeById(volume_id);
- if (!volume.get() ||
- !consent_provider.IsGrantableForVolume(extension, volume)) {
- std::move(error_callback).Run(kVolumeNotFoundError);
- return;
- }
-
- scoped_refptr<storage::FileSystemContext> file_system_context =
- util::GetStoragePartitionForExtensionId(extension.id(), browser_context)
- ->GetFileSystemContext();
- storage::ExternalFileSystemBackend* const backend =
- file_system_context->external_backend();
- DCHECK(backend);
-
- base::FilePath virtual_path;
- if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) {
- std::move(error_callback).Run(kSecurityError);
- return;
- }
-
- if (writable && (volume->is_read_only())) {
- std::move(error_callback).Run(kSecurityError);
- return;
- }
-
- ConsentProvider::ConsentCallback callback =
- base::BindOnce(&OnConsentReceived, browser_context, requester,
- std::move(success_callback), std::move(error_callback),
- extension.origin(), volume, writable);
-
- consent_provider.RequestConsent(extension, requester->render_frame_host(),
- volume, writable, std::move(callback));
-}
+ ErrorCallback error_callback) {}
void ChromeFileSystemDelegate::GetVolumeList(
content::BrowserContext* browser_context,
- const Extension& extension,
VolumeListCallback success_callback,
- ErrorCallback error_callback) {
- ConsentProviderDelegate consent_provider_delegate(
- Profile::FromBrowserContext(browser_context));
- ConsentProvider consent_provider(&consent_provider_delegate);
-
- const std::vector<base::WeakPtr<file_manager::Volume>> volume_list =
- file_manager::VolumeManager::Get(browser_context)->GetVolumeList();
- std::vector<file_system::Volume> result_volume_list;
-
- GetVolumeListForExtension(volume_list, &consent_provider, extension,
- &result_volume_list);
- std::move(success_callback).Run(result_volume_list);
-}
-
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+ ErrorCallback error_callback) {}
+#endif // BUILDFLAG(IS_CHROMEOS)
SavedFilesServiceInterface* ChromeFileSystemDelegate::GetSavedFilesService(
content::BrowserContext* browser_context) {
diff --git a/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h
index 9be9c0da9a4..cde2f6905b1 100644
--- a/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h
+++ b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h
@@ -8,21 +8,38 @@
#include "extensions/browser/api/file_system/file_system_delegate.h"
#include <memory>
+#include <vector>
+#include "base/files/file_path.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
+#include "extensions/browser/extension_function.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+
+#if BUILDFLAG(IS_CHROMEOS)
+#include "chrome/browser/extensions/api/file_system/consent_provider.h"
+#endif // BUILDFLAG(IS_CHROMEOS)
+
+namespace content {
+class BrowserContext;
+} // namespace content
namespace extensions {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
namespace file_system_api {
-// Dispatches an event about a mounted or unmounted volume in the system to
-// each extension which can request it.
-void DispatchVolumeListChangeEvent(content::BrowserContext* browser_context);
+extern const char kConsentImpossible[];
+extern const char kNotSupportedOnNonKioskSessionError[];
+extern const char kRequiresFileSystemWriteError[];
+extern const char kSecurityError[];
+extern const char kVolumeNotFoundError[];
+
+// Returns error message, or null if none.
+const char* ConsentResultToError(ConsentProvider::Consent result);
} // namespace file_system_api
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS)
class ChromeFileSystemDelegate : public FileSystemDelegate {
public:
@@ -51,11 +68,9 @@ class ChromeFileSystemDelegate : public FileSystemDelegate {
base::OnceClosure on_accept,
base::OnceClosure on_cancel) override;
int GetDescriptionIdForAcceptType(const std::string& accept_type) override;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- FileSystemDelegate::GrantVolumesMode GetGrantVolumesMode(
- content::BrowserContext* browser_context,
- content::RenderFrameHost* render_frame_host,
- const Extension& extension) override;
+#if BUILDFLAG(IS_CHROMEOS)
+ bool IsGrantable(content::BrowserContext* browser_context,
+ const Extension& extension) override;
void RequestFileSystem(content::BrowserContext* browser_context,
scoped_refptr<ExtensionFunction> requester,
const Extension& extension,
@@ -64,10 +79,9 @@ class ChromeFileSystemDelegate : public FileSystemDelegate {
FileSystemCallback success_callback,
ErrorCallback error_callback) override;
void GetVolumeList(content::BrowserContext* browser_context,
- const Extension& extension,
VolumeListCallback success_callback,
ErrorCallback error_callback) override;
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS)
SavedFilesServiceInterface* GetSavedFilesService(
content::BrowserContext* browser_context) override;
};
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
new file mode 100644
index 00000000000..0c594e1c123
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.cc
@@ -0,0 +1,269 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/check.h"
+#include "base/path_service.h"
+#include "chrome/browser/ash/file_manager/volume_manager.h"
+#include "chrome/browser/extensions/api/file_system/consent_provider.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/storage_partition.h"
+#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_registry.h"
+#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"
+#include "storage/common/file_system/file_system_types.h"
+#include "third_party/blink/public/common/storage_key/storage_key.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+#include "url/url_constants.h"
+
+namespace extensions {
+
+namespace file_system = api::file_system;
+
+using file_system_api::ConsentProvider;
+using file_system_api::ConsentProviderDelegate;
+
+namespace {
+
+// Fills a list of volumes mounted in the system.
+void FillVolumeList(content::BrowserContext* browser_context,
+ std::vector<file_system::Volume>* result) {
+ file_manager::VolumeManager* const volume_manager =
+ file_manager::VolumeManager::Get(browser_context);
+ DCHECK(volume_manager);
+
+ const auto& volume_list = volume_manager->GetVolumeList();
+ // Convert volume_list to result_volume_list.
+ for (const auto& volume : volume_list) {
+ file_system::Volume result_volume;
+ result_volume.volume_id = volume->volume_id();
+ result_volume.writable = !volume->is_read_only();
+ result->push_back(std::move(result_volume));
+ }
+}
+
+// Callback called when consent is granted or denied.
+void OnConsentReceived(content::BrowserContext* browser_context,
+ scoped_refptr<ExtensionFunction> requester,
+ FileSystemDelegate::FileSystemCallback success_callback,
+ FileSystemDelegate::ErrorCallback error_callback,
+ const url::Origin& origin,
+ const base::WeakPtr<file_manager::Volume>& volume,
+ bool writable,
+ ConsentProvider::Consent result) {
+ using file_manager::Volume;
+ using file_manager::VolumeManager;
+
+ // Render frame host can be gone before this callback method is executed.
+ if (!requester->render_frame_host()) {
+ std::move(error_callback).Run(std::string());
+ return;
+ }
+
+ const char* consent_err_msg = file_system_api::ConsentResultToError(result);
+ if (consent_err_msg) {
+ std::move(error_callback).Run(consent_err_msg);
+ return;
+ }
+
+ if (!volume.get()) {
+ std::move(error_callback).Run(file_system_api::kVolumeNotFoundError);
+ return;
+ }
+
+ DCHECK_EQ(origin.scheme(), kExtensionScheme);
+ scoped_refptr<storage::FileSystemContext> file_system_context =
+ util::GetStoragePartitionForExtensionId(origin.host(), browser_context)
+ ->GetFileSystemContext();
+ storage::ExternalFileSystemBackend* const backend =
+ file_system_context->external_backend();
+ DCHECK(backend);
+
+ base::FilePath virtual_path;
+ if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) {
+ std::move(error_callback).Run(file_system_api::kSecurityError);
+ return;
+ }
+
+ storage::IsolatedContext* const isolated_context =
+ storage::IsolatedContext::GetInstance();
+ DCHECK(isolated_context);
+
+ const storage::FileSystemURL original_url =
+ file_system_context->CreateCrackedFileSystemURL(
+ blink::StorageKey(origin), storage::kFileSystemTypeExternal,
+ virtual_path);
+
+ // Set a fixed register name, as the automatic one would leak the mount point
+ // directory.
+ std::string register_name = "fs";
+ const storage::IsolatedContext::ScopedFSHandle file_system =
+ isolated_context->RegisterFileSystemForPath(
+ storage::kFileSystemTypeLocalForPlatformApp,
+ std::string() /* file_system_id */, original_url.path(),
+ &register_name);
+ if (!file_system.is_valid()) {
+ std::move(error_callback).Run(file_system_api::kSecurityError);
+ return;
+ }
+
+ backend->GrantFileAccessToOrigin(origin, virtual_path);
+
+ // Grant file permissions to the renderer hosting component.
+ content::ChildProcessSecurityPolicy* policy =
+ content::ChildProcessSecurityPolicy::GetInstance();
+ DCHECK(policy);
+
+ const auto process_id = requester->source_process_id();
+ // Read-only permisisons.
+ policy->GrantReadFile(process_id, volume->mount_path());
+ policy->GrantReadFileSystem(process_id, file_system.id());
+
+ // Additional write permissions.
+ if (writable) {
+ policy->GrantCreateReadWriteFile(process_id, volume->mount_path());
+ policy->GrantCopyInto(process_id, volume->mount_path());
+ policy->GrantWriteFileSystem(process_id, file_system.id());
+ policy->GrantDeleteFromFileSystem(process_id, file_system.id());
+ policy->GrantCreateFileForFileSystem(process_id, file_system.id());
+ }
+
+ std::move(success_callback).Run(file_system.id(), register_name);
+}
+
+} // namespace
+
+namespace file_system_api {
+
+void DispatchVolumeListChangeEventAsh(
+ content::BrowserContext* browser_context) {
+ DCHECK(browser_context);
+ EventRouter* const event_router = EventRouter::Get(browser_context);
+ if (!event_router) // Possible on shutdown.
+ return;
+
+ ExtensionRegistry* const registry = ExtensionRegistry::Get(browser_context);
+ if (!registry) // Possible on shutdown.
+ return;
+
+ ConsentProviderDelegate consent_provider_delegate(
+ Profile::FromBrowserContext(browser_context));
+ ConsentProvider consent_provider(&consent_provider_delegate);
+
+ file_system::VolumeListChangedEvent event_args;
+ FillVolumeList(browser_context, &event_args.volumes);
+ for (const auto& extension : registry->enabled_extensions()) {
+ if (!consent_provider.IsGrantable(*extension.get()))
+ continue;
+
+ event_router->DispatchEventToExtension(
+ extension->id(),
+ std::make_unique<Event>(
+ events::FILE_SYSTEM_ON_VOLUME_LIST_CHANGED,
+ file_system::OnVolumeListChanged::kEventName,
+ file_system::OnVolumeListChanged::Create(event_args)));
+ }
+}
+
+} // namespace file_system_api
+
+/******** ChromeFileSystemDelegateAsh ********/
+
+ChromeFileSystemDelegateAsh::ChromeFileSystemDelegateAsh() = default;
+
+ChromeFileSystemDelegateAsh::~ChromeFileSystemDelegateAsh() = default;
+
+void ChromeFileSystemDelegateAsh::RequestFileSystem(
+ content::BrowserContext* browser_context,
+ scoped_refptr<ExtensionFunction> requester,
+ const Extension& extension,
+ std::string volume_id,
+ bool writable,
+ FileSystemCallback success_callback,
+ ErrorCallback error_callback) {
+ ConsentProviderDelegate consent_provider_delegate(
+ Profile::FromBrowserContext(browser_context));
+ ConsentProvider consent_provider(&consent_provider_delegate);
+
+ using file_manager::Volume;
+ using file_manager::VolumeManager;
+ VolumeManager* const volume_manager = VolumeManager::Get(browser_context);
+ DCHECK(volume_manager);
+
+ if (writable &&
+ !app_file_handler_util::HasFileSystemWritePermission(&extension)) {
+ std::move(error_callback)
+ .Run(file_system_api::kRequiresFileSystemWriteError);
+ return;
+ }
+
+ if (!consent_provider.IsGrantable(extension)) {
+ std::move(error_callback)
+ .Run(file_system_api::kNotSupportedOnNonKioskSessionError);
+ return;
+ }
+
+ base::WeakPtr<file_manager::Volume> volume =
+ volume_manager->FindVolumeById(volume_id);
+ if (!volume.get()) {
+ std::move(error_callback).Run(file_system_api::kVolumeNotFoundError);
+ return;
+ }
+
+ scoped_refptr<storage::FileSystemContext> file_system_context =
+ util::GetStoragePartitionForExtensionId(extension.id(), browser_context)
+ ->GetFileSystemContext();
+ storage::ExternalFileSystemBackend* const backend =
+ file_system_context->external_backend();
+ DCHECK(backend);
+
+ base::FilePath virtual_path;
+ if (!backend->GetVirtualPath(volume->mount_path(), &virtual_path)) {
+ std::move(error_callback).Run(file_system_api::kSecurityError);
+ return;
+ }
+
+ if (writable && (volume->is_read_only())) {
+ std::move(error_callback).Run(file_system_api::kSecurityError);
+ return;
+ }
+
+ ConsentProvider::ConsentCallback callback =
+ base::BindOnce(&OnConsentReceived, browser_context, requester,
+ std::move(success_callback), std::move(error_callback),
+ extension.origin(), volume, writable);
+
+ consent_provider.RequestConsent(requester->render_frame_host(), extension,
+ volume->volume_id(), volume->volume_label(),
+ writable, std::move(callback));
+}
+
+void ChromeFileSystemDelegateAsh::GetVolumeList(
+ content::BrowserContext* browser_context,
+ VolumeListCallback success_callback,
+ ErrorCallback /*error_callback*/) {
+ std::vector<file_system::Volume> result_volume_list;
+ FillVolumeList(browser_context, &result_volume_list);
+
+ std::move(success_callback).Run(result_volume_list);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.h b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.h
new file mode 100644
index 00000000000..93d514bcfc7
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_ash.h
@@ -0,0 +1,56 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_ASH_H_
+#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_ASH_H_
+
+#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h"
+
+#include <string>
+
+#include "base/memory/scoped_refptr.h"
+#include "extensions/browser/extension_function.h"
+
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace extensions {
+
+class Extension;
+
+namespace file_system_api {
+
+// Dispatches an event about a mounted or unmounted volume in the system to
+// each extension which can request it.
+void DispatchVolumeListChangeEventAsh(content::BrowserContext* browser_context);
+
+} // namespace file_system_api
+
+class ChromeFileSystemDelegateAsh : public ChromeFileSystemDelegate {
+ public:
+ ChromeFileSystemDelegateAsh();
+
+ ChromeFileSystemDelegateAsh(const ChromeFileSystemDelegateAsh&) = delete;
+ ChromeFileSystemDelegateAsh& operator=(const ChromeFileSystemDelegateAsh&) =
+ delete;
+
+ ~ChromeFileSystemDelegateAsh() override;
+
+ // ChromeFileSystemDelegate:
+ void RequestFileSystem(content::BrowserContext* browser_context,
+ scoped_refptr<ExtensionFunction> requester,
+ const Extension& extension,
+ std::string volume_id,
+ bool writable,
+ FileSystemCallback success_callback,
+ ErrorCallback error_callback) override;
+ void GetVolumeList(content::BrowserContext* browser_context,
+ VolumeListCallback success_callback,
+ ErrorCallback error_callback) override;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_ASH_H_
diff --git a/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.cc b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.cc
new file mode 100644
index 00000000000..8b4f913f884
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.cc
@@ -0,0 +1,342 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/check.h"
+#include "base/memory/raw_ptr.h"
+#include "base/path_service.h"
+#include "base/scoped_observation.h"
+#include "chrome/browser/extensions/api/file_system/consent_provider.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_observer.h"
+#include "chromeos/lacros/lacros_service.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/granted_file_entry.h"
+#include "extensions/common/extension.h"
+
+namespace extensions {
+
+namespace file_system = api::file_system;
+
+using extensions::app_file_handler_util::CreateFileEntryWithPermissions;
+using file_system_api::ConsentProvider;
+using file_system_api::ConsentProviderDelegate;
+
+namespace {
+
+const char kApiUnavailableError[] = "API unavailable.";
+const char kProfileGoneError[] = "Profile gone.";
+const char kRenderFrameHostGoneError[] = "Render frame host gone.";
+
+// Volume list converter that excludes volumes unsupported by lacros-chrome.
+void ConvertAndFilterMojomToVolumeList(
+ const std::vector<crosapi::mojom::VolumePtr>& src_volume_list,
+ std::vector<file_system::Volume>* dst_volume_list) {
+ DCHECK(dst_volume_list->empty());
+ for (auto& src_volume : src_volume_list) {
+ if (src_volume->is_available_to_lacros) {
+ file_system::Volume dst_volume;
+ dst_volume.volume_id = src_volume->volume_id;
+ dst_volume.writable = src_volume->writable;
+ dst_volume_list->emplace_back(std::move(dst_volume));
+ }
+ }
+}
+
+} // namespace
+
+namespace file_system_api {
+
+void DispatchVolumeListChangeEventLacros(
+ content::BrowserContext* browser_context,
+ const std::vector<crosapi::mojom::VolumePtr>& volume_list) {
+ DCHECK(browser_context);
+ EventRouter* const event_router = EventRouter::Get(browser_context);
+ if (!event_router) // Possible on shutdown.
+ return;
+
+ ExtensionRegistry* const registry = ExtensionRegistry::Get(browser_context);
+ if (!registry) // Possible on shutdown.
+ return;
+
+ // TODO(crbug.com/1351493): Simplify usage for IsGrantable().
+ ConsentProviderDelegate consent_provider_delegate(
+ Profile::FromBrowserContext(browser_context));
+ ConsentProvider consent_provider(&consent_provider_delegate);
+
+ file_system::VolumeListChangedEvent event_args;
+ // Note: Events are still fired even if:
+ // * The *filtered* volume list does not change.
+ // * The filtered volume list is empty.
+ // This is done for simplicy: Detecting change in filtered volume list will
+ // requires caching volume list on Lacros side; preventing empty filtered
+ // volume list from triggering an event will lead to inconsistencies compared
+ // to polling via getVolumeList().
+ ConvertAndFilterMojomToVolumeList(volume_list, &event_args.volumes);
+ for (const auto& extension : registry->enabled_extensions()) {
+ if (!consent_provider.IsGrantable(*extension))
+ continue;
+
+ event_router->DispatchEventToExtension(
+ extension->id(),
+ std::make_unique<Event>(
+ events::FILE_SYSTEM_ON_VOLUME_LIST_CHANGED,
+ file_system::OnVolumeListChanged::kEventName,
+ file_system::OnVolumeListChanged::Create(event_args)));
+ }
+}
+
+} // namespace file_system_api
+
+namespace {
+
+/******** RequestFileSystemExecutor ********/
+
+// Executor for chrome.requestFileSystem(), with async steps:
+// 1. Crosapi call to get volume info.
+// 2. (Potentially) request consent via dialog.
+// Sources of complexity:
+// * Lifetime: Instances are ref counted, and are kept alive via callback
+// binding.
+// * Profile: (2) requires |profile_|, which may disappear while awaiting (1)!
+// This is handled by observing |profile_|: If it is destroyed then abort
+// before (2); else proceeds with (2) and unobserve ASAP.
+// * Fulfillment: To ensure the request is fulfilled, one of |success_callback|
+// or |error_callback| gets called eventually (via FinishWith*()).
+class RequestFileSystemExecutor
+ : public base::RefCountedThreadSafe<RequestFileSystemExecutor>,
+ public ProfileObserver {
+ public:
+ RequestFileSystemExecutor(
+ Profile* profile,
+ scoped_refptr<ExtensionFunction> requester,
+ const std::string& volume_id,
+ bool writable,
+ ChromeFileSystemDelegate::FileSystemCallback success_callback,
+ ChromeFileSystemDelegate::ErrorCallback error_callback);
+ RequestFileSystemExecutor(const RequestFileSystemExecutor&) = delete;
+ RequestFileSystemExecutor& operator=(const RequestFileSystemExecutor&) =
+ delete;
+
+ // Entry point for executor flow.
+ void Run(chromeos::LacrosService* lacros_service);
+
+ private:
+ friend class base::RefCountedThreadSafe<RequestFileSystemExecutor>;
+ ~RequestFileSystemExecutor() override;
+
+ // ProfileObserver:
+ void OnProfileWillBeDestroyed(Profile* profile) override;
+
+ // Callback for (1), on receiving volume info from crosapi.
+ void OnCrosapiGetVolumeMountInfo(crosapi::mojom::VolumePtr crosapi_volume);
+
+ // Callback for (2), on consent granting or denial.
+ void OnConsentReceived(base::FilePath mount_path,
+ ConsentProvider::Consent result);
+
+ // Consumes |error_callback_| to pass |error| on error.
+ void FinishWithError(const std::string& error);
+
+ // Consumes |success_callback_| to pass results on success.
+ void FinishWithResponse(const std::string& filesystem_id,
+ const std::string& registered_name);
+
+ // |profile_| can be a raw pointer since its destruction is observed.
+ base::raw_ptr<Profile> profile_;
+ base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this};
+ scoped_refptr<ExtensionFunction> requester_;
+ const std::string volume_id_;
+ const bool want_writable_;
+ ChromeFileSystemDelegate::FileSystemCallback success_callback_;
+ ChromeFileSystemDelegate::ErrorCallback error_callback_;
+};
+
+RequestFileSystemExecutor::RequestFileSystemExecutor(
+ Profile* profile,
+ scoped_refptr<ExtensionFunction> requester,
+ const std::string& volume_id,
+ bool want_writable,
+ ChromeFileSystemDelegate::FileSystemCallback success_callback,
+ ChromeFileSystemDelegate::ErrorCallback error_callback)
+ : profile_(profile),
+ requester_(requester),
+ volume_id_(volume_id),
+ want_writable_(want_writable),
+ success_callback_(std::move(success_callback)),
+ error_callback_(std::move(error_callback)) {
+ profile_observation_.Observe(profile_);
+}
+
+void RequestFileSystemExecutor::Run(chromeos::LacrosService* lacros_service) {
+ // All code path from here must lead to either |success_callback_| or
+ // |error_callback_| getting called.
+ lacros_service->GetRemote<crosapi::mojom::VolumeManager>()
+ ->GetVolumeMountInfo(
+ volume_id_,
+ base::BindOnce(
+ &RequestFileSystemExecutor::OnCrosapiGetVolumeMountInfo, this));
+}
+
+RequestFileSystemExecutor::~RequestFileSystemExecutor() = default;
+
+void RequestFileSystemExecutor::OnProfileWillBeDestroyed(Profile* profile) {
+ DCHECK_EQ(profile_, profile);
+ profile_observation_.Reset();
+ profile_ = nullptr;
+}
+
+void RequestFileSystemExecutor::OnCrosapiGetVolumeMountInfo(
+ crosapi::mojom::VolumePtr crosapi_volume) {
+ // Profile can be gone before this callback executes, while awaiting crosapi.
+ if (!profile_) {
+ FinishWithError(kProfileGoneError);
+ return;
+ }
+ if (!crosapi_volume || !crosapi_volume->is_available_to_lacros) {
+ FinishWithError(file_system_api::kVolumeNotFoundError);
+ return;
+ }
+ if (want_writable_ && !crosapi_volume->writable) {
+ FinishWithError(file_system_api::kSecurityError);
+ return;
+ }
+
+ // TODO(crbug.com/1351493): Simplify usage for RequestConsent().
+ ConsentProviderDelegate consent_provider_delegate(profile_);
+ ConsentProvider consent_provider(&consent_provider_delegate);
+
+ ConsentProvider::ConsentCallback callback =
+ base::BindOnce(&RequestFileSystemExecutor::OnConsentReceived, this,
+ crosapi_volume->mount_path);
+
+ consent_provider.RequestConsent(
+ requester_->render_frame_host(), *requester_->extension(),
+ crosapi_volume->volume_id, crosapi_volume->volume_label, want_writable_,
+ std::move(callback));
+
+ // Done with |profile_|, so stop observing.
+ profile_observation_.Reset();
+ profile_ = nullptr;
+}
+
+void RequestFileSystemExecutor::OnConsentReceived(
+ base::FilePath mount_path,
+ ConsentProvider::Consent result) {
+ // Render frame host can be gone before this callback executes.
+ if (!requester_->render_frame_host()) {
+ FinishWithError(kRenderFrameHostGoneError);
+ return;
+ }
+
+ const char* consent_err_msg = file_system_api::ConsentResultToError(result);
+ if (consent_err_msg) {
+ FinishWithError(consent_err_msg);
+ return;
+ }
+
+ const auto process_id = requester_->source_process_id();
+ extensions::GrantedFileEntry granted_file_entry =
+ CreateFileEntryWithPermissions(process_id, mount_path,
+ /*can_write=*/want_writable_,
+ /*can_create=*/want_writable_,
+ /*can_delete=*/want_writable_);
+ FinishWithResponse(granted_file_entry.filesystem_id,
+ granted_file_entry.registered_name);
+}
+
+void RequestFileSystemExecutor::FinishWithError(const std::string& error) {
+ std::move(error_callback_).Run(error);
+}
+
+void RequestFileSystemExecutor::FinishWithResponse(
+ const std::string& filesystem_id,
+ const std::string& registered_name) {
+ std::move(success_callback_).Run(filesystem_id, registered_name);
+}
+
+} // namespace
+
+/******** ChromeFileSystemDelegateLacros ********/
+
+ChromeFileSystemDelegateLacros::ChromeFileSystemDelegateLacros() = default;
+
+ChromeFileSystemDelegateLacros::~ChromeFileSystemDelegateLacros() = default;
+
+void ChromeFileSystemDelegateLacros::RequestFileSystem(
+ content::BrowserContext* browser_context,
+ scoped_refptr<ExtensionFunction> requester,
+ const Extension& extension,
+ std::string volume_id,
+ bool writable,
+ FileSystemCallback success_callback,
+ ErrorCallback error_callback) {
+ Profile* profile = Profile::FromBrowserContext(browser_context);
+ // TODO(crbug.com/1351493): Simplify usage for IsGrantable().
+ ConsentProviderDelegate consent_provider_delegate(profile);
+ ConsentProvider consent_provider(&consent_provider_delegate);
+
+ if (writable &&
+ !app_file_handler_util::HasFileSystemWritePermission(&extension)) {
+ std::move(error_callback)
+ .Run(file_system_api::kRequiresFileSystemWriteError);
+ return;
+ }
+
+ if (!consent_provider.IsGrantable(extension)) {
+ std::move(error_callback)
+ .Run(file_system_api::kNotSupportedOnNonKioskSessionError);
+ return;
+ }
+
+ auto* lacros_service = chromeos::LacrosService::Get();
+ DCHECK(lacros_service);
+ if (!lacros_service->IsAvailable<crosapi::mojom::VolumeManager>()) {
+ std::move(error_callback).Run(kApiUnavailableError);
+ return;
+ }
+
+ // The executor object is kept alive by its presence in callbacks, and
+ // deleted when callbacks are invoked or cleared.
+ scoped_refptr<RequestFileSystemExecutor> executor =
+ new RequestFileSystemExecutor(profile, requester, volume_id, writable,
+ std::move(success_callback),
+ std::move(error_callback));
+ executor->Run(lacros_service);
+}
+
+void ChromeFileSystemDelegateLacros::GetVolumeList(
+ content::BrowserContext* /*browser_context*/,
+ VolumeListCallback success_callback,
+ ErrorCallback error_callback) {
+ auto* lacros_service = chromeos::LacrosService::Get();
+ DCHECK(lacros_service);
+ if (!lacros_service->IsAvailable<crosapi::mojom::VolumeManager>()) {
+ std::move(error_callback).Run(kApiUnavailableError);
+ return;
+ }
+
+ lacros_service->GetRemote<crosapi::mojom::VolumeManager>()->GetFullVolumeList(
+ base::BindOnce(
+ [](VolumeListCallback success_callback,
+ std::vector<crosapi::mojom::VolumePtr> src_volume_list) {
+ std::vector<file_system::Volume> filtered_volume_list;
+ ConvertAndFilterMojomToVolumeList(src_volume_list,
+ &filtered_volume_list);
+ std::move(success_callback).Run(filtered_volume_list);
+ },
+ std::move(success_callback)));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h
new file mode 100644
index 00000000000..8fb3fbe65c4
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h
@@ -0,0 +1,61 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_LACROS_H_
+#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_LACROS_H_
+
+#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h"
+
+#include <string>
+#include <vector>
+
+#include "base/memory/scoped_refptr.h"
+#include "chromeos/crosapi/mojom/volume_manager.mojom.h"
+#include "extensions/browser/extension_function.h"
+
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace extensions {
+
+class Extension;
+
+namespace file_system_api {
+
+// Dispatches an event about a mounted or unmounted volume in the system to
+// each extension which can request it.
+void DispatchVolumeListChangeEventLacros(
+ content::BrowserContext* browser_context,
+ const std::vector<crosapi::mojom::VolumePtr>& volume_list);
+
+} // namespace file_system_api
+
+class ChromeFileSystemDelegateLacros : public ChromeFileSystemDelegate {
+ public:
+ ChromeFileSystemDelegateLacros();
+
+ ChromeFileSystemDelegateLacros(const ChromeFileSystemDelegateLacros&) =
+ delete;
+ ChromeFileSystemDelegateLacros& operator=(
+ const ChromeFileSystemDelegateLacros&) = delete;
+
+ ~ChromeFileSystemDelegateLacros() override;
+
+ // ChromeFileSystemDelegate:
+ void RequestFileSystem(content::BrowserContext* browser_context,
+ scoped_refptr<ExtensionFunction> requester,
+ const Extension& extension,
+ std::string volume_id,
+ bool writable,
+ FileSystemCallback success_callback,
+ ErrorCallback error_callback) override;
+ void GetVolumeList(content::BrowserContext* browser_context,
+ VolumeListCallback success_callback,
+ ErrorCallback error_callback) override;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CHROME_FILE_SYSTEM_DELEGATE_LACROS_H_
diff --git a/chromium/chrome/browser/extensions/api/file_system/consent_provider.cc b/chromium/chrome/browser/extensions/api/file_system/consent_provider.cc
index 70ad9360ab5..4e7c22a8c3a 100644
--- a/chromium/chrome/browser/extensions/api/file_system/consent_provider.cc
+++ b/chromium/chrome/browser/extensions/api/file_system/consent_provider.cc
@@ -5,25 +5,29 @@
#include "chrome/browser/extensions/api/file_system/consent_provider.h"
#include <memory>
-#include <string>
#include "base/bind.h"
#include "base/logging.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
-#include "chrome/browser/ash/file_manager/app_id.h"
-#include "chrome/browser/ash/file_manager/volume_manager.h"
+#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "chrome/browser/extensions/api/file_system/request_file_system_notification.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/ui/views/extensions/request_file_system_dialog_view.h"
-#include "components/user_manager/user_manager.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
+#include "extensions/browser/extensions_browser_client.h"
+#include "extensions/browser/kiosk/kiosk_delegate.h"
#include "extensions/common/api/file_system.h"
+#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/kiosk_mode_info.h"
-#include "extensions/common/permissions/permissions_data.h"
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/file_manager/app_id.h"
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace extensions {
@@ -32,8 +36,9 @@ namespace {
// List of allowlisted component apps and extensions by their ids for
// chrome.fileSystem.requestFileSystem.
const char* const kRequestFileSystemComponentAllowlist[] = {
- file_manager::kFileManagerAppId, file_manager::kAudioPlayerAppId,
- file_manager::kImageLoaderExtensionId,
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ file_manager::kFileManagerAppId, file_manager::kImageLoaderExtensionId,
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// TODO(henryhsu,b/110126438): Remove this extension id, and add it only
// for tests.
"pkplfbidichfdicaijlchgnapepdginl" // Testing extensions.
@@ -65,6 +70,7 @@ void DialogResultToConsent(
std::move(callback).Run(
file_system_api::ConsentProvider::CONSENT_GRANTED);
break;
+ // The following is wired to both Cancel and Close callbacks.
case ui::DIALOG_BUTTON_CANCEL:
std::move(callback).Run(
file_system_api::ConsentProvider::CONSENT_REJECTED);
@@ -76,23 +82,24 @@ void DialogResultToConsent(
namespace file_system_api {
+/******** ConsentProvider ********/
+
ConsentProvider::ConsentProvider(DelegateInterface* delegate)
: delegate_(delegate) {
DCHECK(delegate_);
}
-ConsentProvider::~ConsentProvider() {
-}
+ConsentProvider::~ConsentProvider() = default;
-void ConsentProvider::RequestConsent(
- const Extension& extension,
- content::RenderFrameHost* host,
- const base::WeakPtr<file_manager::Volume>& volume,
- bool writable,
- ConsentCallback callback) {
- DCHECK(IsGrantableForVolume(extension, volume));
+void ConsentProvider::RequestConsent(content::RenderFrameHost* host,
+ const Extension& extension,
+ const std::string& volume_id,
+ const std::string& volume_label,
+ bool writable,
+ ConsentCallback callback) {
+ DCHECK(IsGrantable(extension));
- // If a allowlisted component, then no need to ask or inform the user.
+ // If an allowlisted component, then no need to ask or inform the user.
if (extension.location() == mojom::ManifestLocation::kComponent &&
delegate_->IsAllowlistedComponent(extension)) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -100,77 +107,48 @@ void ConsentProvider::RequestConsent(
return;
}
- // If a allowlisted app or extensions to access Downloads folder, then no
- // need to ask or inform the user.
- if (volume.get() &&
- volume->type() == file_manager::VOLUME_TYPE_DOWNLOADS_DIRECTORY &&
- delegate_->HasRequestDownloadsPermission(extension)) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), CONSENT_GRANTED));
- return;
- }
-
// If auto-launched kiosk app, then no need to ask user either, but show the
// notification.
if (delegate_->IsAutoLaunched(extension)) {
- delegate_->ShowNotification(extension, volume, writable);
+ delegate_->ShowNotification(extension.id(), extension.name(), volume_id,
+ volume_label, writable);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), CONSENT_GRANTED));
return;
}
- // If it's a kiosk app running in manual-launch kiosk session, then show
- // the confirmation dialog.
+ // If it's a kiosk app running in manual-launch kiosk session, then show the
+ // confirmation dialog.
if (KioskModeInfo::IsKioskOnly(&extension) &&
- user_manager::UserManager::Get()->IsLoggedInAsKioskApp()) {
+ profiles::IsChromeAppKioskSession()) {
delegate_->ShowDialog(
- extension, host, volume, writable,
- base::BindOnce(&DialogResultToConsent, std::move(callback)));
+ host, extension.id(), extension.name(), volume_id, volume_label,
+ writable, base::BindOnce(&DialogResultToConsent, std::move(callback)));
return;
}
NOTREACHED() << "Cannot request consent for non-grantable extensions.";
}
-FileSystemDelegate::GrantVolumesMode ConsentProvider::GetGrantVolumesMode(
- const Extension& extension) {
+bool ConsentProvider::IsGrantable(const Extension& extension) {
const bool is_allowlisted_component =
delegate_->IsAllowlistedComponent(extension);
const bool is_running_in_kiosk_session =
KioskModeInfo::IsKioskOnly(&extension) &&
- user_manager::UserManager::Get()->IsLoggedInAsKioskApp();
+ profiles::IsChromeAppKioskSession();
- if (is_allowlisted_component || is_running_in_kiosk_session) {
- return FileSystemDelegate::kGrantAll;
- }
-
- const bool is_allowlisted_non_component =
- delegate_->HasRequestDownloadsPermission(extension);
-
- return is_allowlisted_non_component ? FileSystemDelegate::kGrantPerVolume
- : FileSystemDelegate::kGrantNone;
+ return is_allowlisted_component || is_running_in_kiosk_session;
}
-bool ConsentProvider::IsGrantableForVolume(
- const Extension& extension,
- const base::WeakPtr<file_manager::Volume>& volume) {
- if (volume.get() &&
- volume->type() == file_manager::VOLUME_TYPE_DOWNLOADS_DIRECTORY &&
- delegate_->HasRequestDownloadsPermission(extension)) {
- return true;
- }
-
- return GetGrantVolumesMode(extension) == FileSystemDelegate::kGrantAll;
-}
+/******** ConsentProviderDelegate ********/
ConsentProviderDelegate::ConsentProviderDelegate(Profile* profile)
: profile_(profile) {
DCHECK(profile_);
}
-ConsentProviderDelegate::~ConsentProviderDelegate() {
-}
+ConsentProviderDelegate::~ConsentProviderDelegate() = default;
// static
void ConsentProviderDelegate::SetAutoDialogButtonForTest(
@@ -179,9 +157,11 @@ void ConsentProviderDelegate::SetAutoDialogButtonForTest(
}
void ConsentProviderDelegate::ShowDialog(
- const Extension& extension,
content::RenderFrameHost* host,
- const base::WeakPtr<file_manager::Volume>& volume,
+ const extensions::ExtensionId& extension_id,
+ const std::string& extension_name,
+ const std::string& volume_id,
+ const std::string& volume_label,
bool writable,
file_system_api::ConsentProvider::ShowDialogCallback callback) {
DCHECK(host);
@@ -198,7 +178,7 @@ void ConsentProviderDelegate::ShowDialog(
// If there is no web contents handle, then the method is most probably
// executed from a background page.
if (!web_contents)
- web_contents = GetWebContentsForAppId(profile_, extension.id());
+ web_contents = GetWebContentsForAppId(profile_, extension_id);
if (!web_contents) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -215,33 +195,27 @@ void ConsentProviderDelegate::ShowDialog(
return;
}
- // If the volume is gone, then cancel the dialog.
- if (!volume.get()) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback), ui::DIALOG_BUTTON_CANCEL));
- return;
- }
-
RequestFileSystemDialogView::ShowDialog(
- web_contents, extension.name(),
- (volume->volume_label().empty() ? volume->volume_id()
- : volume->volume_label()),
- writable, std::move(callback));
+ web_contents, extension_name,
+ volume_label.empty() ? volume_id : volume_label, writable,
+ std::move(callback));
}
void ConsentProviderDelegate::ShowNotification(
- const Extension& extension,
- const base::WeakPtr<file_manager::Volume>& volume,
+ const extensions::ExtensionId& extension_id,
+ const std::string& extension_name,
+ const std::string& volume_id,
+ const std::string& volume_label,
bool writable) {
- ShowNotificationForAutoGrantedRequestFileSystem(profile_, extension, volume,
- writable);
+ ShowNotificationForAutoGrantedRequestFileSystem(profile_, extension_id,
+ extension_name, volume_id,
+ volume_label, writable);
}
bool ConsentProviderDelegate::IsAutoLaunched(const Extension& extension) {
- ash::KioskAppManager::App app_info;
- return ash::KioskAppManager::Get()->GetApp(extension.id(), &app_info) &&
- app_info.was_auto_launched_with_zero_delay;
+ return ExtensionsBrowserClient::Get()
+ ->GetKioskDelegate()
+ ->IsAutoLaunchedKioskApp(extension.id());
}
bool ConsentProviderDelegate::IsAllowlistedComponent(
@@ -253,11 +227,5 @@ bool ConsentProviderDelegate::IsAllowlistedComponent(
return false;
}
-bool ConsentProviderDelegate::HasRequestDownloadsPermission(
- const Extension& extension) {
- return extension.permissions_data()->HasAPIPermission(
- mojom::APIPermissionID::kFileSystemRequestDownloads);
-}
-
} // namespace file_system_api
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/file_system/consent_provider.h b/chromium/chrome/browser/extensions/api/file_system/consent_provider.h
index e6e7aa99916..1293e8036b1 100644
--- a/chromium/chrome/browser/extensions/api/file_system/consent_provider.h
+++ b/chromium/chrome/browser/extensions/api/file_system/consent_provider.h
@@ -5,10 +5,10 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CONSENT_PROVIDER_H_
#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_CONSENT_PROVIDER_H_
+#include <string>
+
#include "base/callback_forward.h"
-#include "base/memory/weak_ptr.h"
-#include "build/build_config.h"
-#include "extensions/browser/api/file_system/file_system_delegate.h"
+#include "extensions/common/extension_id.h"
#include "ui/base/ui_base_types.h"
class Profile;
@@ -17,10 +17,6 @@ namespace content {
class RenderFrameHost;
} // content
-namespace file_manager {
-class Volume;
-} // namespace file_manager
-
namespace extensions {
class Extension;
class ScopedSkipRequestFileSystemDialog;
@@ -33,8 +29,8 @@ namespace file_system_api {
// TestingConsentProviderDelegate.
// This class may post callbacks given to it, but does not asynchronously call
// itself. It is generally safe to use a temporary ConsentProvider.
-// TODO(michaelpg): Make this easier to use by replacing member functions with
-// static methods.
+// TODO(crbug.com/1351493): Make this easier to use, perhaps by replacing member
+// functions with static methods.
class ConsentProvider {
public:
enum Consent { CONSENT_GRANTED, CONSENT_REJECTED, CONSENT_IMPOSSIBLE };
@@ -45,26 +41,26 @@ class ConsentProvider {
class DelegateInterface {
public:
// Shows a dialog for granting permissions.
- virtual void ShowDialog(const Extension& extension,
- content::RenderFrameHost* host,
- const base::WeakPtr<file_manager::Volume>& volume,
+ virtual void ShowDialog(content::RenderFrameHost* host,
+ const extensions::ExtensionId& extension_id,
+ const std::string& extension_name,
+ const std::string& volume_id,
+ const std::string& volume_label,
bool writable,
ShowDialogCallback callback) = 0;
// Shows a notification about permissions automatically granted access.
- virtual void ShowNotification(
- const Extension& extension,
- const base::WeakPtr<file_manager::Volume>& volume,
- bool writable) = 0;
+ virtual void ShowNotification(const extensions::ExtensionId& extension_id,
+ const std::string& extension_name,
+ const std::string& volume_id,
+ const std::string& volume_label,
+ bool writable) = 0;
// Checks if the extension was launched in auto-launch kiosk mode.
virtual bool IsAutoLaunched(const Extension& extension) = 0;
// Checks if the extension is a allowlisted component extension or app.
virtual bool IsAllowlistedComponent(const Extension& extension) = 0;
-
- // Checks if the extension has the permission to access Downloads.
- virtual bool HasRequestDownloadsPermission(const Extension& extension) = 0;
};
explicit ConsentProvider(DelegateInterface* delegate);
@@ -74,23 +70,18 @@ class ConsentProvider {
~ConsentProvider();
- // Requests consent for granting |writable| permissions to the |volume|
- // volume by the |extension|. Must be called only if the extension is
- // grantable, which can be checked with GetGrantVolumesMode() and
- // IsGrantableForVolume().
- void RequestConsent(const Extension& extension,
- content::RenderFrameHost* host,
- const base::WeakPtr<file_manager::Volume>& volume,
+ // Requests consent for granting |writable| permissions to a volume with
+ // |volume_id| and |volume_label| by |extension|, which is assumed to be
+ // grantable (i.e., passes IsGrantable()).
+ void RequestConsent(content::RenderFrameHost* host,
+ const Extension& extension,
+ const std::string& volume_id,
+ const std::string& volume_label,
bool writable,
ConsentCallback callback);
- // Returns granted access mode for the |extension|.
- FileSystemDelegate::GrantVolumesMode GetGrantVolumesMode(
- const Extension& extension);
-
- // Checks whether the |extension| can be granted |volume| access.
- bool IsGrantableForVolume(const Extension& extension,
- const base::WeakPtr<file_manager::Volume>& volume);
+ // Checks whether the |extension| can be granted access.
+ bool IsGrantable(const Extension& extension);
private:
DelegateInterface* const delegate_;
@@ -115,18 +106,21 @@ class ConsentProviderDelegate : public ConsentProvider::DelegateInterface {
static void SetAutoDialogButtonForTest(ui::DialogButton button);
// ConsentProvider::DelegateInterface overrides:
- void ShowDialog(
- const Extension& extension,
- content::RenderFrameHost* host,
- const base::WeakPtr<file_manager::Volume>& volume,
- bool writable,
- file_system_api::ConsentProvider::ShowDialogCallback callback) override;
- void ShowNotification(const Extension& extension,
- const base::WeakPtr<file_manager::Volume>& volume,
+ void ShowDialog(content::RenderFrameHost* host,
+ const extensions::ExtensionId& extension_id,
+ const std::string& extension_name,
+ const std::string& volume_id,
+ const std::string& volume_label,
+ bool writable,
+ ConsentProvider::ShowDialogCallback callback) override;
+
+ void ShowNotification(const extensions::ExtensionId& extension_id,
+ const std::string& extension_name,
+ const std::string& volume_id,
+ const std::string& volume_label,
bool writable) override;
bool IsAutoLaunched(const Extension& extension) override;
bool IsAllowlistedComponent(const Extension& extension) override;
- bool HasRequestDownloadsPermission(const Extension& extension) override;
Profile* const profile_;
};
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 b67115b243a..137f7aa954f 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
@@ -8,99 +8,92 @@
#include <string>
#include "base/bind.h"
-#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
-#include "chrome/browser/ash/file_manager/volume_manager.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/test/base/testing_browser_process.h"
#include "components/prefs/testing_pref_service.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user.h"
#include "content/public/test/browser_task_environment.h"
-#include "extensions/browser/api/file_system/file_system_delegate.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/manifest.h"
-#include "extensions/common/permissions/permissions_data.h"
#include "testing/gtest/include/gtest/gtest.h"
using extensions::file_system_api::ConsentProvider;
using extensions::mojom::ManifestLocation;
-using file_manager::Volume;
namespace extensions {
namespace {
+// Configurations and results for TestingConsentProviderDelegate, with directly
+// accessible fields.
+struct TestDelegateState {
+ // Used to assign a fake dialog response.
+ ui::DialogButton dialog_button = ui::DIALOG_BUTTON_NONE;
+
+ // Used to assign fake result of detection the auto launch kiosk mode.
+ bool is_auto_launched = false;
+
+ // Used to set allowlisted components list with a single id.
+ std::string allowlisted_component_id;
+
+ // Counters to record calls.
+ int show_dialog_counter = 0;
+ int show_notification_counter = 0;
+};
+
+// Test implementation of ConsentProvider::DelegateInterface that exposes
+// states to a TestDelegateState instance.
class TestingConsentProviderDelegate
: public ConsentProvider::DelegateInterface {
public:
- TestingConsentProviderDelegate()
- : show_dialog_counter_(0),
- show_notification_counter_(0),
- dialog_button_(ui::DIALOG_BUTTON_NONE),
- is_auto_launched_(false) {}
+ explicit TestingConsentProviderDelegate(TestDelegateState* state)
+ : state_(state) {}
TestingConsentProviderDelegate(const TestingConsentProviderDelegate&) =
delete;
TestingConsentProviderDelegate& operator=(
const TestingConsentProviderDelegate&) = delete;
- ~TestingConsentProviderDelegate() {}
-
- // Sets a fake dialog response.
- void SetDialogButton(ui::DialogButton button) { dialog_button_ = button; }
-
- // Sets a fake result of detection the auto launch kiosk mode.
- void SetIsAutoLaunched(bool is_auto_launched) {
- is_auto_launched_ = is_auto_launched;
- }
-
- // Sets an allowlisted components list with a single id.
- void SetComponentAllowlist(const std::string& extension_id) {
- allowlisted_component_id_ = extension_id;
- }
-
- int show_dialog_counter() const { return show_dialog_counter_; }
- int show_notification_counter() const { return show_notification_counter_; }
+ ~TestingConsentProviderDelegate() = default;
private:
- // ConsentProvider::DelegateInterface overrides:
- void ShowDialog(const extensions::Extension& extension,
- content::RenderFrameHost* host,
- const base::WeakPtr<Volume>& volume,
+ // ConsentProvider::DelegateInterface:
+ void ShowDialog(content::RenderFrameHost* host,
+ const extensions::ExtensionId& extension_id,
+ const std::string& extension_name,
+ const std::string& volume_id,
+ const std::string& volume_label,
bool writable,
ConsentProvider::ShowDialogCallback callback) override {
- ++show_dialog_counter_;
- std::move(callback).Run(dialog_button_);
+ ++state_->show_dialog_counter;
+ std::move(callback).Run(state_->dialog_button);
}
- void ShowNotification(const extensions::Extension& extension,
- const base::WeakPtr<Volume>& volume,
+ // ConsentProvider::DelegateInterface:
+ void ShowNotification(const extensions::ExtensionId& extension_id,
+ const std::string& extension_name,
+ const std::string& volume_id,
+ const std::string& volume_label,
bool writable) override {
- ++show_notification_counter_;
+ ++state_->show_notification_counter;
}
+ // ConsentProvider::DelegateInterface:
bool IsAutoLaunched(const extensions::Extension& extension) override {
- return is_auto_launched_;
+ return state_->is_auto_launched;
}
+ // ConsentProvider::DelegateInterface:
bool IsAllowlistedComponent(const extensions::Extension& extension) override {
- return allowlisted_component_id_.compare(extension.id()) == 0;
+ return state_->allowlisted_component_id.compare(extension.id()) == 0;
}
- bool HasRequestDownloadsPermission(const Extension& extension) override {
- return extension.permissions_data()->HasAPIPermission(
- mojom::APIPermissionID::kFileSystemRequestDownloads);
- }
-
- int show_dialog_counter_;
- int show_notification_counter_;
- ui::DialogButton dialog_button_;
- bool is_auto_launched_;
- std::string allowlisted_component_id_;
+ // Use raw_ptr since |state| is owned by owner.
+ base::raw_ptr<TestDelegateState> state_;
};
// Rewrites result of a consent request from |result| to |log|.
@@ -123,8 +116,6 @@ class FileSystemApiConsentProviderTest : public testing::Test {
scoped_user_manager_enabler_ =
std::make_unique<user_manager::ScopedUserManager>(
base::WrapUnique(user_manager_));
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- download_volume_ = Volume::CreateForDownloads(temp_dir_.GetPath());
}
void TearDown() override {
@@ -135,13 +126,10 @@ class FileSystemApiConsentProviderTest : public testing::Test {
}
protected:
- base::WeakPtr<Volume> volume_;
std::unique_ptr<TestingPrefServiceSimple> testing_pref_service_;
ash::FakeChromeUserManager* user_manager_; // Owned by the scope enabler.
std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_enabler_;
content::BrowserTaskEnvironment task_environment_;
- base::ScopedTempDir temp_dir_;
- std::unique_ptr<Volume> download_volume_;
};
TEST_F(FileSystemApiConsentProviderTest, ForNonKioskApps) {
@@ -151,10 +139,10 @@ TEST_F(FileSystemApiConsentProviderTest, ForNonKioskApps) {
ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
.SetLocation(ManifestLocation::kComponent)
.Build());
- TestingConsentProviderDelegate delegate;
+ TestDelegateState state;
+ TestingConsentProviderDelegate delegate(&state);
ConsentProvider provider(&delegate);
- EXPECT_EQ(provider.GetGrantVolumesMode(*component_extension),
- FileSystemDelegate::kGrantNone);
+ EXPECT_FALSE(provider.IsGrantable(*component_extension));
}
// Allowlisted component apps are instantly granted access without asking
@@ -164,48 +152,21 @@ TEST_F(FileSystemApiConsentProviderTest, ForNonKioskApps) {
ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
.SetLocation(ManifestLocation::kComponent)
.Build());
- TestingConsentProviderDelegate delegate;
- delegate.SetComponentAllowlist(allowlisted_component_extension->id());
+ TestDelegateState state;
+ state.allowlisted_component_id = allowlisted_component_extension->id();
+ TestingConsentProviderDelegate delegate(&state);
ConsentProvider provider(&delegate);
- EXPECT_EQ(provider.GetGrantVolumesMode(*allowlisted_component_extension),
- FileSystemDelegate::kGrantAll);
+ EXPECT_TRUE(provider.IsGrantable(*allowlisted_component_extension));
ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
- provider.RequestConsent(*allowlisted_component_extension.get(), nullptr,
- volume_, true /* writable */,
+ provider.RequestConsent(nullptr, *allowlisted_component_extension.get(),
+ "Volume ID 1", "Volume Label 1",
+ true /* writable */,
base::BindOnce(&OnConsentReceived, &result));
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0, delegate.show_dialog_counter());
- EXPECT_EQ(0, delegate.show_notification_counter());
- EXPECT_EQ(ConsentProvider::CONSENT_GRANTED, result);
- }
-
- // Allowlisted extensions are instantly granted downloads access without
- // asking user.
- {
- scoped_refptr<const Extension> allowlisted_extension(
- ExtensionBuilder("Test", ExtensionBuilder::Type::PLATFORM_APP)
- .SetLocation(ManifestLocation::kComponent)
- .AddPermission("fileSystem.requestDownloads")
- .Build());
- TestingConsentProviderDelegate delegate;
- ConsentProvider provider(&delegate);
- EXPECT_EQ(provider.GetGrantVolumesMode(*allowlisted_extension),
- FileSystemDelegate::kGrantPerVolume);
- EXPECT_FALSE(
- provider.IsGrantableForVolume(*allowlisted_extension, volume_));
- EXPECT_TRUE(provider.IsGrantableForVolume(*allowlisted_extension,
- download_volume_->AsWeakPtr()));
-
- ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
- provider.RequestConsent(*allowlisted_extension.get(), nullptr,
- download_volume_->AsWeakPtr(), true /* writable */,
- base::BindRepeating(&OnConsentReceived, &result));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_EQ(0, delegate.show_dialog_counter());
- EXPECT_EQ(0, delegate.show_notification_counter());
+ EXPECT_EQ(0, state.show_dialog_counter);
+ EXPECT_EQ(0, state.show_notification_counter);
EXPECT_EQ(ConsentProvider::CONSENT_GRANTED, result);
}
@@ -214,10 +175,10 @@ TEST_F(FileSystemApiConsentProviderTest, ForNonKioskApps) {
{
scoped_refptr<const Extension> non_component_extension(
ExtensionBuilder("Test").Build());
- TestingConsentProviderDelegate delegate;
+ TestDelegateState state;
+ TestingConsentProviderDelegate delegate(&state);
ConsentProvider provider(&delegate);
- EXPECT_EQ(provider.GetGrantVolumesMode(*non_component_extension),
- FileSystemDelegate::kGrantNone);
+ EXPECT_FALSE(provider.IsGrantable(*non_component_extension));
}
}
@@ -235,20 +196,20 @@ TEST_F(FileSystemApiConsentProviderTest, ForKioskApps) {
user_manager_->LoginUser(
AccountId::FromUserEmail(auto_launch_kiosk_app->id()));
- TestingConsentProviderDelegate delegate;
- delegate.SetIsAutoLaunched(true);
+ TestDelegateState state;
+ state.is_auto_launched = true;
+ TestingConsentProviderDelegate delegate(&state);
ConsentProvider provider(&delegate);
- EXPECT_EQ(provider.GetGrantVolumesMode(*auto_launch_kiosk_app),
- FileSystemDelegate::kGrantAll);
+ EXPECT_TRUE(provider.IsGrantable(*auto_launch_kiosk_app));
ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
- provider.RequestConsent(*auto_launch_kiosk_app.get(), nullptr, volume_,
- true /* writable */,
- base::BindOnce(&OnConsentReceived, &result));
+ provider.RequestConsent(
+ nullptr, *auto_launch_kiosk_app.get(), "Volume ID 2", "Volume Label 2",
+ true /* writable */, base::BindOnce(&OnConsentReceived, &result));
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0, delegate.show_dialog_counter());
- EXPECT_EQ(1, delegate.show_notification_counter());
+ EXPECT_EQ(0, state.show_dialog_counter);
+ EXPECT_EQ(1, state.show_notification_counter);
EXPECT_EQ(ConsentProvider::CONSENT_GRANTED, result);
}
@@ -264,40 +225,42 @@ TEST_F(FileSystemApiConsentProviderTest, ForKioskApps) {
AccountId::FromUserEmail(manual_launch_kiosk_app->id()));
user_manager_->KioskAppLoggedIn(manual_kiosk_app_user);
{
- TestingConsentProviderDelegate delegate;
- delegate.SetDialogButton(ui::DIALOG_BUTTON_OK);
+ TestDelegateState state;
+ state.dialog_button = ui::DIALOG_BUTTON_OK;
+ TestingConsentProviderDelegate delegate(&state);
ConsentProvider provider(&delegate);
- EXPECT_EQ(provider.GetGrantVolumesMode(*manual_launch_kiosk_app),
- FileSystemDelegate::kGrantAll);
+ EXPECT_TRUE(provider.IsGrantable(*manual_launch_kiosk_app));
ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
- provider.RequestConsent(*manual_launch_kiosk_app.get(), nullptr, volume_,
+ provider.RequestConsent(nullptr, *manual_launch_kiosk_app.get(),
+ "Volume ID 3", "Volume Label 3",
true /* writable */,
base::BindOnce(&OnConsentReceived, &result));
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, delegate.show_dialog_counter());
- EXPECT_EQ(0, delegate.show_notification_counter());
+ EXPECT_EQ(1, state.show_dialog_counter);
+ EXPECT_EQ(0, state.show_notification_counter);
EXPECT_EQ(ConsentProvider::CONSENT_GRANTED, result);
}
// Non-component apps in manual-launch kiosk mode will be rejected access
// after rejecting by a user.
{
- TestingConsentProviderDelegate delegate;
+ TestDelegateState state;
+ state.dialog_button = ui::DIALOG_BUTTON_CANCEL;
+ TestingConsentProviderDelegate delegate(&state);
ConsentProvider provider(&delegate);
- delegate.SetDialogButton(ui::DIALOG_BUTTON_CANCEL);
- EXPECT_EQ(provider.GetGrantVolumesMode(*manual_launch_kiosk_app),
- FileSystemDelegate::kGrantAll);
+ EXPECT_TRUE(provider.IsGrantable(*manual_launch_kiosk_app));
ConsentProvider::Consent result = ConsentProvider::CONSENT_IMPOSSIBLE;
- provider.RequestConsent(*manual_launch_kiosk_app.get(), nullptr, volume_,
+ provider.RequestConsent(nullptr, *manual_launch_kiosk_app.get(),
+ "Volume ID 4", "Volume Label 4",
true /* writable */,
base::BindOnce(&OnConsentReceived, &result));
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, delegate.show_dialog_counter());
- EXPECT_EQ(0, delegate.show_notification_counter());
+ EXPECT_EQ(1, state.show_dialog_counter);
+ EXPECT_EQ(0, state.show_notification_counter);
EXPECT_EQ(ConsentProvider::CONSENT_REJECTED, result);
}
}
diff --git a/chromium/chrome/browser/extensions/api/file_system/file_system_apitest.cc b/chromium/chrome/browser/extensions/api/file_system/file_system_apitest.cc
index 04c1dbc9e06..43c4f0f23a9 100644
--- a/chromium/chrome/browser/extensions/api/file_system/file_system_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/file_system/file_system_apitest.cc
@@ -9,7 +9,6 @@
#include "base/scoped_observation.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
#include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_paths.h"
@@ -731,13 +730,13 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTest, FileSystemApiRestoreDirectoryEntry) {
<< message_;
}
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(FileSystemApiTest, RequestFileSystem_NotChromeOS) {
ASSERT_TRUE(RunExtensionTest(
"api_test/file_system/request_file_system_not_chromeos",
{.launch_as_platform_app = true}, {.ignore_manifest_warnings = true}))
<< message_;
}
-#endif
+#endif // !BUILDFLAG(IS_CHROMEOS)
} // namespace extensions
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 96bcb6680a6..632e52cd2f1 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
@@ -27,14 +27,12 @@
#include "extensions/browser/api/file_system/file_system_api.h"
#include "extensions/browser/event_router.h"
#include "extensions/common/api/file_system.h"
-#include "extensions/common/switches.h"
#include "storage/browser/file_system/external_mount_points.h"
#include "ui/base/ui_base_types.h"
// TODO(michaelpg): Port these tests to app_shell: crbug.com/505926.
using file_manager::VolumeManager;
-using file_manager::VolumeType;
namespace extensions {
namespace {
@@ -42,7 +40,6 @@ namespace {
// Mount point names for chrome.fileSystem.requestFileSystem() tests.
const char kWritableMountPointName[] = "writable";
const char kReadOnlyMountPointName[] = "read-only";
-const char kDownloadsMountPointName[] = "downloads";
// Child directory created in each of the mount points.
const char kChildDirectory[] = "child-dir";
@@ -143,9 +140,7 @@ class FileSystemApiTestForDrive : public PlatformAppBrowserTest {
PlatformAppBrowserTest::SetUpOnMainThread();
}
- void TearDown() override {
- PlatformAppBrowserTest::TearDown();
- }
+ void TearDown() override { PlatformAppBrowserTest::TearDown(); }
base::FilePath GetDriveMountPoint() { return drivefs_mount_point_; }
@@ -213,12 +208,6 @@ class FileSystemApiTestForRequestFileSystem : public PlatformAppBrowserTest {
return drive::SetUpUserDataDirectoryForDriveFsTest();
}
- void SetUpCommandLine(base::CommandLine* command_line) override {
- PlatformAppBrowserTest::SetUpCommandLine(command_line);
- command_line->AppendSwitchASCII(
- extensions::switches::kAllowlistedExtensionID, kTestingExtensionId);
- }
-
// Sets up fake Drive service for tests (this has to be injected before the
// real DriveIntegrationService instance is created.)
void SetUpInProcessBrowserTestFixture() override {
@@ -235,15 +224,8 @@ class FileSystemApiTestForRequestFileSystem : public PlatformAppBrowserTest {
void SetUpOnMainThread() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- CreateTestingFileSystem(kWritableMountPointName,
- file_manager::VOLUME_TYPE_TESTING,
- false /* read_only */);
- CreateTestingFileSystem(kReadOnlyMountPointName,
- file_manager::VOLUME_TYPE_TESTING,
- true /* read_only */);
- CreateTestingFileSystem(kDownloadsMountPointName,
- file_manager::VOLUME_TYPE_DOWNLOADS_DIRECTORY,
- false /* read_only */);
+ CreateTestingFileSystem(kWritableMountPointName, false /* read_only */);
+ CreateTestingFileSystem(kReadOnlyMountPointName, true /* read_only */);
PlatformAppBrowserTest::SetUpOnMainThread();
}
@@ -260,7 +242,7 @@ class FileSystemApiTestForRequestFileSystem : public PlatformAppBrowserTest {
ASSERT_TRUE(volume_manager);
volume_manager->AddVolumeForTesting(
base::FilePath("/a/b/c"), file_manager::VOLUME_TYPE_TESTING,
- chromeos::DEVICE_TYPE_UNKNOWN, false /* read_only */);
+ ash::DeviceType::kUnknown, false /* read_only */);
}
protected:
@@ -270,7 +252,6 @@ class FileSystemApiTestForRequestFileSystem : public PlatformAppBrowserTest {
// Creates a testing file system in a testing directory.
void CreateTestingFileSystem(const std::string& mount_point_name,
- VolumeType volume_type,
bool read_only) {
const base::FilePath mount_point_path =
temp_dir_.GetPath().Append(mount_point_name);
@@ -283,9 +264,9 @@ class FileSystemApiTestForRequestFileSystem : public PlatformAppBrowserTest {
VolumeManager* const volume_manager =
VolumeManager::Get(browser()->profile());
ASSERT_TRUE(volume_manager);
- volume_manager->AddVolumeForTesting(mount_point_path, volume_type,
- chromeos::DEVICE_TYPE_UNKNOWN,
- read_only);
+ volume_manager->AddVolumeForTesting(mount_point_path,
+ file_manager::VOLUME_TYPE_TESTING,
+ ash::DeviceType::kUnknown, read_only);
}
// Simulates entering the kiosk session.
@@ -447,7 +428,7 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive,
}
IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive,
- FileSystemApiSaveNewFileWithWriteTest) {
+ FileSystemApiSaveNewFileWithWriteTest) {
base::FilePath test_file =
GetDriveMountPoint().AppendASCII("root/save_new.txt");
FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest picker(
@@ -458,7 +439,7 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive,
}
IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive,
- FileSystemApiSaveExistingFileWithWriteTest) {
+ FileSystemApiSaveExistingFileWithWriteTest) {
base::FilePath test_file =
GetDriveMountPoint().AppendASCII("root/save_existing.txt");
FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest picker(
@@ -560,13 +541,4 @@ IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem,
<< message_;
}
-IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem,
- AllowlistedExtensionForDownloads) {
- ScopedSkipRequestFileSystemDialog dialog_skipper(ui::DIALOG_BUTTON_CANCEL);
- ASSERT_TRUE(RunExtensionTest(
- "api_test/file_system/request_downloads_allowed_extension",
- {.launch_as_platform_app = true}))
- << message_;
-}
-
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/file_system/request_file_system_notification.cc b/chromium/chrome/browser/extensions/api/file_system/request_file_system_notification.cc
index d97609ce30d..18a7403de88 100644
--- a/chromium/chrome/browser/extensions/api/file_system/request_file_system_notification.cc
+++ b/chromium/chrome/browser/extensions/api/file_system/request_file_system_notification.cc
@@ -8,25 +8,23 @@
#include <utility>
#include "ash/constants/notifier_catalogs.h"
-#include "base/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ash/file_manager/volume_manager.h"
+#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/chrome_app_icon_loader.h"
#include "chrome/browser/notifications/notification_display_service.h"
+#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_icon_loader.h"
#include "chrome/grit/generated_resources.h"
-#include "extensions/common/extension.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_delegate.h"
#include "ui/message_center/public/cpp/notification_types.h"
#include "ui/message_center/public/cpp/notifier_id.h"
-using file_manager::Volume;
using message_center::Notification;
namespace extensions {
@@ -47,14 +45,14 @@ class AppNotificationLauncher : public AppIconLoaderDelegate,
AppNotificationLauncher& operator=(const AppNotificationLauncher&) = delete;
void InitAndShow(Profile* profile,
- const Extension& extension,
+ const extensions::ExtensionId& extension_id,
std::unique_ptr<message_center::Notification> notification) {
profile_ = profile;
pending_notification_ = std::move(notification);
icon_loader_ =
std::make_unique<ChromeAppIconLoader>(profile, kIconSize, this);
- icon_loader_->FetchImage(extension.id());
+ icon_loader_->FetchImage(extension_id);
}
// AppIconLoaderDelegate overrides:
@@ -90,30 +88,25 @@ class AppNotificationLauncher : public AppIconLoaderDelegate,
void ShowNotificationForAutoGrantedRequestFileSystem(
Profile* profile,
- const Extension& extension,
- const base::WeakPtr<Volume>& volume,
+ const extensions::ExtensionId& extension_id,
+ const std::string& extension_name,
+ const std::string& volume_id,
+ const std::string& volume_label,
bool writable) {
DCHECK(profile);
-
- // If the volume is gone, then do not show the notification.
- if (!volume.get())
- return;
-
static int sequence = 0;
// Create globally unique |notification_id| so that notifications are not
// suppressed, thus allowing each AppNotificationLauncher instance to
// correspond to an actual notification, and properly deallocated on close.
- const std::string notification_id =
- base::StringPrintf("%s-%s-%d", extension.id().c_str(),
- volume->volume_id().c_str(), sequence);
+ const std::string notification_id = base::StringPrintf(
+ "%s-%s-%d", extension_id.c_str(), volume_id.c_str(), sequence);
++sequence;
message_center::RichNotificationData data;
// TODO(mtomasz): Share this code with RequestFileSystemDialogView.
const std::u16string display_name =
- base::UTF8ToUTF16(!volume->volume_label().empty() ? volume->volume_label()
- : volume->volume_id());
+ base::UTF8ToUTF16(volume_label.empty() ? volume_id : volume_label);
const std::u16string message = l10n_util::GetStringFUTF16(
writable
? IDS_FILE_SYSTEM_REQUEST_FILE_SYSTEM_NOTIFICATION_WRITABLE_MESSAGE
@@ -126,16 +119,22 @@ void ShowNotificationForAutoGrantedRequestFileSystem(
std::unique_ptr<message_center::Notification> notification(new Notification(
message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
- base::UTF8ToUTF16(extension.name()), message,
+ base::UTF8ToUTF16(extension_name), message,
ui::ImageModel(), // Updated asynchronously later.
std::u16string(), // display_source
GURL(),
+#if BUILDFLAG(IS_CHROMEOS_ASH)
message_center::NotifierId(
message_center::NotifierType::SYSTEM_COMPONENT, notification_id,
ash::NotificationCatalogName::kRequestFileSystem),
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
+ notification_id),
+#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
data, app_notification_launcher));
- app_notification_launcher->InitAndShow(profile, extension,
+ app_notification_launcher->InitAndShow(profile, extension_id,
std::move(notification));
}
diff --git a/chromium/chrome/browser/extensions/api/file_system/request_file_system_notification.h b/chromium/chrome/browser/extensions/api/file_system/request_file_system_notification.h
index dade350b598..176a7000fe3 100644
--- a/chromium/chrome/browser/extensions/api/file_system/request_file_system_notification.h
+++ b/chromium/chrome/browser/extensions/api/file_system/request_file_system_notification.h
@@ -5,23 +5,20 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_REQUEST_FILE_SYSTEM_NOTIFICATION_H_
#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_REQUEST_FILE_SYSTEM_NOTIFICATION_H_
-#include "base/memory/weak_ptr.h"
+#include "extensions/common/extension_id.h"
class Profile;
-namespace file_manager {
-class Volume;
-} // namespace file_manager
-
namespace extensions {
-class Extension;
// Shows a notification about automatically granted access to a file system,
// i.e. the chrome.fileSystem.requestFileSystem() API.
void ShowNotificationForAutoGrantedRequestFileSystem(
Profile* profile,
- const extensions::Extension& extension,
- const base::WeakPtr<file_manager::Volume>& volume,
+ const extensions::ExtensionId& extension_id,
+ const std::string& extension_name,
+ const std::string& volume_id,
+ const std::string& volume_label,
bool writable);
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.cc b/chromium/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.cc
new file mode 100644
index 00000000000..fcfe9c61e9e
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.cc
@@ -0,0 +1,33 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/file_system/volume_list_provider_lacros.h"
+
+#include "base/logging.h"
+#include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate_lacros.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chromeos/lacros/lacros_service.h"
+
+namespace extensions {
+
+VolumeListProviderLacros::VolumeListProviderLacros(Profile* profile)
+ : profile_(profile) {}
+
+VolumeListProviderLacros::~VolumeListProviderLacros() = default;
+
+void VolumeListProviderLacros::Start() {
+ auto* lacros_service = chromeos::LacrosService::Get();
+ if (!lacros_service->IsAvailable<crosapi::mojom::VolumeManager>())
+ return;
+ lacros_service->GetRemote<crosapi::mojom::VolumeManager>()
+ ->AddVolumeListObserver(receiver_.BindNewPipeAndPassRemoteWithVersion());
+}
+
+void VolumeListProviderLacros::OnVolumeListChanged(
+ std::vector<crosapi::mojom::VolumePtr> volume_list) {
+ DCHECK(profile_);
+ file_system_api::DispatchVolumeListChangeEventLacros(profile_, volume_list);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.h b/chromium/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.h
new file mode 100644
index 00000000000..2c83e544bd6
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/file_system/volume_list_provider_lacros.h
@@ -0,0 +1,47 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_VOLUME_LIST_PROVIDER_LACROS_H_
+#define CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_VOLUME_LIST_PROVIDER_LACROS_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/raw_ptr.h"
+#include "chromeos/crosapi/mojom/volume_manager.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+
+class Profile;
+
+namespace extensions {
+
+// Class to monitor volume list change from Ash, and dispatch the result to
+// extensions that listens to chrome.fileSystem.onVolumeListChange.
+class VolumeListProviderLacros : public crosapi::mojom::VolumeListObserver {
+ public:
+ using Listener =
+ base::RepeatingCallback<void(std::vector<crosapi::mojom::VolumePtr>)>;
+
+ explicit VolumeListProviderLacros(Profile* profile);
+ VolumeListProviderLacros(const VolumeListProviderLacros&) = delete;
+ VolumeListProviderLacros& operator=(const VolumeListProviderLacros&) = delete;
+ ~VolumeListProviderLacros() override;
+
+ void Start();
+
+ private:
+ // crosapi::mojom::VolumeListObserver:
+ void OnVolumeListChanged(
+ std::vector<crosapi::mojom::VolumePtr> volume_list) override;
+
+ // Pointer to owner, so okay to keep as raw pointer.
+ base::raw_ptr<Profile> profile_;
+
+ // Receives mojo messages from ash-chrome.
+ mojo::Receiver<crosapi::mojom::VolumeListObserver> receiver_{this};
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_FILE_SYSTEM_VOLUME_LIST_PROVIDER_LACROS_H_
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 6674542fc48..16cc434e5b4 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
@@ -288,21 +288,21 @@ ExtensionFunction::ResponseAction FontSettingsGetFontListFunction::Run() {
}
void FontSettingsGetFontListFunction::FontListHasLoaded(
- std::unique_ptr<base::ListValue> list) {
- ExtensionFunction::ResponseValue response = CopyFontsToResult(list.get());
+ base::Value::List list) {
+ ExtensionFunction::ResponseValue response = CopyFontsToResult(list);
Respond(std::move(response));
}
ExtensionFunction::ResponseValue
-FontSettingsGetFontListFunction::CopyFontsToResult(base::ListValue* fonts) {
+FontSettingsGetFontListFunction::CopyFontsToResult(
+ const base::Value::List& fonts) {
base::Value::List result;
- for (const auto& entry : fonts->GetListDeprecated()) {
+ for (const auto& entry : fonts) {
if (!entry.is_list()) {
NOTREACHED();
return Error("");
}
- const base::Value::ConstListView font_list_value =
- entry.GetListDeprecated();
+ const base::Value::List& font_list_value = entry.GetList();
if (font_list_value.size() < 2 || !font_list_value[0].is_string() ||
!font_list_value[1].is_string()) {
diff --git a/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.h b/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.h
index ddf83ca3288..12f59789afc 100644
--- a/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.h
+++ b/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.h
@@ -12,6 +12,7 @@
#include <string>
#include "base/memory/raw_ptr.h"
+#include "base/values.h"
#include "chrome/browser/font_pref_change_notifier.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
@@ -153,8 +154,8 @@ class FontSettingsGetFontListFunction : public ExtensionFunction {
ResponseAction Run() override;
private:
- void FontListHasLoaded(std::unique_ptr<base::ListValue> list);
- ResponseValue CopyFontsToResult(base::ListValue* fonts);
+ void FontListHasLoaded(base::Value::List list);
+ ResponseValue CopyFontsToResult(const base::Value::List& fonts);
};
// Base class for extension API functions that clear a browser font pref.
diff --git a/chromium/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.cc b/chromium/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.cc
index ab71284b36b..59093f39286 100644
--- a/chromium/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.cc
@@ -15,7 +15,7 @@
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
#include "components/prefs/pref_service.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/test/result_catcher.h"
@@ -69,7 +69,7 @@ void ForceInstalledAffiliatedExtensionApiTest::
SetUpInProcessBrowserTestFixture() {
// Initialize clients here so they are available during setup. They will be
// shutdown in ChromeBrowserMain.
- chromeos::SessionManagerClient::InitializeFakeInMemory();
+ ash::SessionManagerClient::InitializeFakeInMemory();
// Init the user policy provider.
policy_provider_.SetDefaultReturns(
@@ -88,9 +88,9 @@ void ForceInstalledAffiliatedExtensionApiTest::
void ForceInstalledAffiliatedExtensionApiTest::SetUpOnMainThread() {
// Log in user that was created with
// policy::AffiliationTestHelper::PreLoginUser() in the PRE_ test.
- const base::Value* users =
- g_browser_process->local_state()->GetList("LoggedInUsers");
- if (!users->GetListDeprecated().empty()) {
+ const base::Value::List& users =
+ g_browser_process->local_state()->GetValueList("LoggedInUsers");
+ if (!users.empty()) {
policy::AffiliationTestHelper::LoginUser(affiliation_mixin_.account_id());
}
diff --git a/chromium/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.h b/chromium/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.h
index 95e2dd47abe..f6a400f5f97 100644
--- a/chromium/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.h
+++ b/chromium/chrome/browser/extensions/api/force_installed_affiliated_extension_apitest.h
@@ -7,7 +7,6 @@
#include <string>
-#include "ash/components/tpm/stub_install_attributes.h"
#include "base/values.h"
#include "chrome/browser/ash/login/test/cryptohome_mixin.h"
#include "chrome/browser/ash/policy/affiliation/affiliation_mixin.h"
@@ -15,6 +14,7 @@
#include "chrome/browser/extensions/mixin_based_extension_apitest.h"
#include "chrome/browser/policy/extension_force_install_mixin.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
+#include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "extensions/common/extension_id.h"
#include "url/gurl.h"
diff --git a/chromium/chrome/browser/extensions/api/gcm/gcm_api.cc b/chromium/chrome/browser/extensions/api/gcm/gcm_api.cc
index e0419a76dc0..e1363a22442 100644
--- a/chromium/chrome/browser/extensions/api/gcm/gcm_api.cc
+++ b/chromium/chrome/browser/extensions/api/gcm/gcm_api.cc
@@ -124,8 +124,8 @@ ExtensionFunction::ResponseAction GcmRegisterFunction::Run() {
void GcmRegisterFunction::CompleteFunctionWithResult(
const std::string& registration_id,
gcm::GCMClient::Result gcm_result) {
- std::vector<base::Value> result;
- result.emplace_back(registration_id);
+ base::Value::List result;
+ result.Append(registration_id);
const bool succeeded = gcm::GCMClient::SUCCESS == gcm_result;
Respond(succeeded
@@ -182,8 +182,8 @@ ExtensionFunction::ResponseAction GcmSendFunction::Run() {
void GcmSendFunction::CompleteFunctionWithResult(
const std::string& message_id,
gcm::GCMClient::Result gcm_result) {
- std::vector<base::Value> result;
- result.emplace_back(message_id);
+ base::Value::List result;
+ result.Append(message_id);
const bool succeeded = gcm::GCMClient::SUCCESS == gcm_result;
Respond(succeeded
diff --git a/chromium/chrome/browser/extensions/api/history/history_api.cc b/chromium/chrome/browser/extensions/api/history/history_api.cc
index b951eaf0376..bb8d7f73318 100644
--- a/chromium/chrome/browser/extensions/api/history/history_api.cc
+++ b/chromium/chrome/browser/extensions/api/history/history_api.cc
@@ -143,10 +143,9 @@ HistoryEventRouter::~HistoryEventRouter() {
}
void HistoryEventRouter::OnURLVisited(history::HistoryService* history_service,
- ui::PageTransition transition,
- const history::URLRow& row,
- base::Time visit_time) {
- auto args = OnVisited::Create(GetHistoryItem(row));
+ const history::URLRow& url_row,
+ const history::VisitRow& new_visit) {
+ auto args = OnVisited::Create(GetHistoryItem(url_row));
DispatchEvent(profile_, events::HISTORY_ON_VISITED,
api::history::OnVisited::kEventName, std::move(args));
}
@@ -170,7 +169,7 @@ void HistoryEventRouter::OnURLsDeleted(
void HistoryEventRouter::DispatchEvent(Profile* profile,
events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> event_args) {
+ base::Value::List event_args) {
if (profile && EventRouter::Get(profile)) {
auto event = std::make_unique<Event>(histogram_value, event_name,
std::move(event_args), profile);
diff --git a/chromium/chrome/browser/extensions/api/history/history_api.h b/chromium/chrome/browser/extensions/api/history/history_api.h
index 945f0dd95b9..df1ed3057d5 100644
--- a/chromium/chrome/browser/extensions/api/history/history_api.h
+++ b/chromium/chrome/browser/extensions/api/history/history_api.h
@@ -38,16 +38,15 @@ class HistoryEventRouter : public history::HistoryServiceObserver {
private:
// history::HistoryServiceObserver.
void OnURLVisited(history::HistoryService* history_service,
- ui::PageTransition transition,
- const history::URLRow& row,
- base::Time visit_time) override;
+ const history::URLRow& url_row,
+ const history::VisitRow& new_visit) override;
void OnURLsDeleted(history::HistoryService* history_service,
const history::DeletionInfo& deletion_info) override;
void DispatchEvent(Profile* profile,
events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> event_args);
+ base::Value::List event_args);
raw_ptr<Profile> profile_;
base::ScopedObservation<history::HistoryService,
diff --git a/chromium/chrome/browser/extensions/api/i18n/i18n_apitest.cc b/chromium/chrome/browser/extensions/api/i18n/i18n_apitest.cc
index f0a2d79d755..35392762ff6 100644
--- a/chromium/chrome/browser/extensions/api/i18n/i18n_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/i18n/i18n_apitest.cc
@@ -5,7 +5,6 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/ui/browser.h"
@@ -69,7 +68,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, I18NUpdate) {
std::u16string title;
ui_test_utils::GetCurrentTabTitle(browser(), &title);
- EXPECT_EQ(std::string("FIRSTMESSAGE"), base::UTF16ToUTF8(title));
+ EXPECT_EQ(u"FIRSTMESSAGE", title);
// Change messages.json file and reload extension.
base::CopyFile(
@@ -83,7 +82,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, I18NUpdate) {
EXPECT_TRUE(catcher.GetNextResult());
ui_test_utils::GetCurrentTabTitle(browser(), &title);
- EXPECT_EQ(std::string("SECONDMESSAGE"), base::UTF16ToUTF8(title));
+ EXPECT_EQ(u"SECONDMESSAGE", title);
}
// detectLanguage has some custom hooks that handle the asynchronous response
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 c08c89bc3a9..e7151a03320 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
@@ -5,7 +5,6 @@
#include "chrome/browser/extensions/api/identity/gaia_remote_consent_flow.h"
#include "base/bind.h"
-#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/escape.h"
#include "build/chromeos_buildflags.h"
@@ -16,7 +15,6 @@
#include "chrome/browser/signin/identity_manager_factory.h"
#include "components/signin/core/browser/account_reconcilor.h"
#include "components/signin/public/base/multilogin_parameters.h"
-#include "components/signin/public/base/signin_switches.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"
@@ -71,8 +69,7 @@ void GaiaRemoteConsentFlow::Start() {
WebAuthFlow::GET_AUTH_TOKEN);
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// `profile_` may be nullptr in tests.
- if (profile_ &&
- base::FeatureList::IsEnabled(switches::kLacrosNonSyncingProfiles)) {
+ if (profile_) {
AccountReconcilorFactory::GetForProfile(profile_)
->GetConsistencyCookieManager()
->AddExtraCookieManager(GetCookieManagerForPartition());
@@ -198,8 +195,7 @@ void GaiaRemoteConsentFlow::SetWebAuthFlowForTesting(
web_flow_ = std::move(web_auth_flow);
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// `profile_` may be nullptr in tests.
- if (profile_ &&
- base::FeatureList::IsEnabled(switches::kLacrosNonSyncingProfiles)) {
+ if (profile_) {
AccountReconcilorFactory::GetForProfile(profile_)
->GetConsistencyCookieManager()
->AddExtraCookieManager(GetCookieManagerForPartition());
@@ -260,8 +256,7 @@ void GaiaRemoteConsentFlow::DetachWebAuthFlow() {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
// `profile_` may be nullptr in tests.
- if (profile_ &&
- base::FeatureList::IsEnabled(switches::kLacrosNonSyncingProfiles)) {
+ if (profile_) {
AccountReconcilorFactory::GetForProfile(profile_)
->GetConsistencyCookieManager()
->RemoveExtraCookieManager(GetCookieManagerForPartition());
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 8b77aa34d26..e703920143b 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
@@ -9,9 +9,7 @@
#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 "components/signin/public/base/signin_switches.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -112,11 +110,6 @@ class IdentityGaiaRemoteConsentFlowTest : public testing::Test {
base::test::TaskEnvironment task_env_;
base::HistogramTester histogram_tester_;
testing::StrictMock<MockGaiaRemoteConsentFlowDelegate> delegate_;
-
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
- base::test::ScopedFeatureList scoped_feature_list_{
- switches::kLacrosNonSyncingProfiles};
-#endif
};
TEST_F(IdentityGaiaRemoteConsentFlowTest, ConsentResult) {
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc b/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc
index 469ae5a896a..a18afaf7450 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -84,15 +84,21 @@
#include "url/gurl.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/components/tpm/stub_install_attributes.h"
#include "chrome/browser/ash/login/users/mock_user_manager.h"
#include "chrome/browser/ash/net/network_portal_detector_test_impl.h"
-#include "chromeos/network/network_handler.h"
-#include "chromeos/network/network_state.h"
-#include "chromeos/network/network_state_handler.h"
+#include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
+#include "chromeos/ash/components/network/network_handler.h"
+#include "chromeos/ash/components/network/network_state.h"
+#include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/login/login_state/login_state.h"
#include "components/user_manager/scoped_user_manager.h"
#endif
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chromeos/crosapi/mojom/crosapi.mojom.h"
+#include "chromeos/startup/browser_init_params.h"
+#endif
+
using guest_view::GuestViewBase;
using testing::_;
using testing::Return;
@@ -116,10 +122,8 @@ const char kGetAuthTokenResultAfterConsentApprovedHistogramName[] =
#if BUILDFLAG(IS_CHROMEOS_ASH)
void InitNetwork() {
- const chromeos::NetworkState* default_network =
- chromeos::NetworkHandler::Get()
- ->network_state_handler()
- ->DefaultNetwork();
+ const ash::NetworkState* default_network =
+ ash::NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
auto* portal_detector = new ash::NetworkPortalDetectorTestImpl();
portal_detector->SetDefaultNetworkForTesting(default_network->guid());
@@ -128,7 +132,7 @@ void InitNetwork() {
default_network->guid(),
ash::NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204);
- chromeos::network_portal_detector::InitializeForTesting(portal_detector);
+ ash::network_portal_detector::InitializeForTesting(portal_detector);
}
#endif
@@ -168,19 +172,16 @@ class AsyncFunctionRunner {
return function->GetError();
}
- void WaitForTwoResults(ExtensionFunction* function,
- base::Value* first_result,
- base::Value* second_result) {
+ void WaitForOneResult(ExtensionFunction* function, base::Value* result) {
RunMessageLoopUntilResponse();
EXPECT_TRUE(function->GetError().empty())
<< "Unexpected error: " << function->GetError();
EXPECT_NE(nullptr, function->GetResultList());
const auto& result_list = *function->GetResultList();
- EXPECT_EQ(2ul, result_list.size());
+ EXPECT_EQ(1ul, result_list.size());
- *first_result = result_list[0].Clone();
- *second_result = result_list[1].Clone();
+ *result = result_list[0].Clone();
}
private:
@@ -206,11 +207,8 @@ class AsyncExtensionBrowserTest : public ExtensionBrowserTest {
return async_function_runner_->WaitForError(function);
}
- void WaitForTwoResults(ExtensionFunction* function,
- base::Value* first_result,
- base::Value* second_result) {
- return async_function_runner_->WaitForTwoResults(function, first_result,
- second_result);
+ void WaitForOneResult(ExtensionFunction* function, base::Value* result) {
+ return async_function_runner_->WaitForOneResult(function, result);
}
private:
@@ -420,7 +418,7 @@ class FakeGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
}
}
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
void StartDeviceAccessTokenRequest() override {
// In these tests requests for the device account just funnel through to
// requests for the token key account.
@@ -990,29 +988,19 @@ class GetAuthTokenFunctionTest
Browser* browser,
std::string* access_token,
std::set<std::string>* granted_scopes) {
- EXPECT_TRUE(
- utils::RunFunction(function, args, browser, api_test_utils::NONE));
-
- EXPECT_TRUE(function->GetError().empty())
- << "Unexpected error: " << function->GetError();
- EXPECT_NE(nullptr, function->GetResultList());
-
- const auto& result_list = *function->GetResultList();
- EXPECT_EQ(2ul, result_list.size());
-
- const auto& access_token_value = result_list[0];
- const auto& granted_scopes_value = result_list[1];
- EXPECT_TRUE(access_token_value.is_string());
- EXPECT_TRUE(granted_scopes_value.is_list());
-
- std::set<std::string> scopes;
- for (const auto& scope : granted_scopes_value.GetListDeprecated()) {
- EXPECT_TRUE(scope.is_string());
- scopes.insert(scope.GetString());
- }
+ std::unique_ptr<base::Value> result_value =
+ utils::RunFunctionAndReturnSingleResult(function, args, browser);
+ ASSERT_TRUE(result_value);
+ std::unique_ptr<api::identity::GetAuthTokenResult> result =
+ api::identity::GetAuthTokenResult::FromValue(*result_value);
+ ASSERT_TRUE(result);
- *access_token = access_token_value.GetString();
- *granted_scopes = std::move(scopes);
+ EXPECT_NE(nullptr, result->token);
+ *access_token = *result->token;
+ EXPECT_NE(nullptr, result->granted_scopes);
+ std::set<std::string> granted_scopes_map(result->granted_scopes->begin(),
+ result->granted_scopes->end());
+ *granted_scopes = std::move(granted_scopes_map);
}
void WaitForGetAuthTokenResults(
@@ -1020,25 +1008,22 @@ class GetAuthTokenFunctionTest
std::string* access_token,
std::set<std::string>* granted_scopes,
AsyncFunctionRunner* function_runner = nullptr) {
- base::Value access_token_value;
- base::Value granted_scopes_value;
+ base::Value result_value;
if (function_runner == nullptr) {
- WaitForTwoResults(function, &access_token_value, &granted_scopes_value);
+ WaitForOneResult(function, &result_value);
} else {
- function_runner->WaitForTwoResults(function, &access_token_value,
- &granted_scopes_value);
+ function_runner->WaitForOneResult(function, &result_value);
}
- EXPECT_TRUE(access_token_value.is_string());
- EXPECT_TRUE(granted_scopes_value.is_list());
+ std::unique_ptr<api::identity::GetAuthTokenResult> result =
+ api::identity::GetAuthTokenResult::FromValue(result_value);
+ ASSERT_TRUE(result);
- std::set<std::string> scopes;
- for (const auto& scope : granted_scopes_value.GetListDeprecated()) {
- EXPECT_TRUE(scope.is_string());
- scopes.insert(scope.GetString());
- }
-
- *access_token = access_token_value.GetString();
- *granted_scopes = std::move(scopes);
+ ASSERT_NE(nullptr, result->token);
+ *access_token = *result->token;
+ ASSERT_NE(nullptr, result->granted_scopes);
+ std::set<std::string> granted_scopes_map(result->granted_scopes->begin(),
+ result->granted_scopes->end());
+ *granted_scopes = std::move(granted_scopes_map);
}
private:
@@ -1113,9 +1098,8 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
IdentityGetAuthTokenError::State::kSignInFailed, 1);
}
+// Signin is always allowed on Lacros.
#if !BUILDFLAG(IS_CHROMEOS_LACROS)
-// TODO(crbug.com/1220066): Remove the lacros exclusion when DICE is disabled on
-// Lacros.
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
PRE_InteractiveNotSignedAndSigninNotAllowed) {
// kSigninAllowed cannot be set after the profile creation. Use
@@ -1251,7 +1235,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
IdentityGetAuthTokenError::State::kMintTokenAuthFailure, 1);
}
-// The signin flow is simply not used on ChromeOS.
+// The signin flow is simply not used on Ash.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
InteractiveMintServiceErrorShowSigninOnlyOnce) {
@@ -1304,8 +1288,8 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveLoginCanceled) {
std::string error = utils::RunFunctionAndReturnError(
func.get(), "[{\"interactive\": true}]", browser());
EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
-// ChromeOS does not support the interactive login flow, so the login UI will
-// never be shown on that platform.
+// Ash does not support the interactive login flow, so the login UI will never
+// be shown on that platform.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
EXPECT_TRUE(func->login_ui_shown());
#endif
@@ -1335,7 +1319,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
}
// The interactive login flow is always short-circuited out with failure on
-// ChromeOS, so the tests of the interactive login flow being successful are not
+// Ash, so the tests of the interactive login flow being successful are not
// relevant on that platform.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
@@ -1542,7 +1526,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveApprovalNoGrant) {
IdentityGetAuthTokenError::State::kNoGrant, 1);
}
-// The signin flow is simply not used on ChromeOS.
+// The signin flow is simply not used on Ash.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
InteractiveApprovalNoGrantShowSigninUIOnlyOnce) {
@@ -1955,8 +1939,8 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveCacheHit) {
1);
}
-// The interactive login UI is never shown on ChromeOS, so tests of the
-// interactive login flow being successful are not relevant on that platform.
+// The interactive login UI is never shown on Ash, so tests of the interactive
+// login flow being successful are not relevant on that platform.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, LoginInvalidatesTokenCache) {
scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
@@ -2586,7 +2570,7 @@ IN_PROC_BROWSER_TEST_F(
2);
}
-// The signin flow is simply not used on ChromeOS.
+// The signin flow is simply not used on Ash.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
MultiSecondaryInteractiveInvalidToken) {
@@ -2804,22 +2788,103 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, GranularPermissionsResponse) {
1);
}
+#if BUILDFLAG(IS_CHROMEOS)
+enum class DeviceLocalAccountSessionType { kPublic, kAppKiosk, kWebKiosk };
+
#if BUILDFLAG(IS_CHROMEOS_ASH)
+class GetAuthTokenFunctionDeviceLocalAccountTestPlatformHelper {
+ public:
+ explicit GetAuthTokenFunctionDeviceLocalAccountTestPlatformHelper(
+ DeviceLocalAccountSessionType session_type)
+ : session_type_(session_type), user_manager_(new ash::MockUserManager) {}
+
+ void SetUpOnMainThread() {
+ chromeos::LoginState::Get()->SetLoggedInState(
+ chromeos::LoginState::LoggedInState::LOGGED_IN_ACTIVE,
+ session_type_ == DeviceLocalAccountSessionType::kPublic
+ ? chromeos::LoginState::LoggedInUserType::
+ LOGGED_IN_USER_PUBLIC_ACCOUNT
+ : chromeos::LoginState::LoggedInUserType::LOGGED_IN_USER_KIOSK);
+ EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
+ .WillRepeatedly(
+ Return(session_type_ == DeviceLocalAccountSessionType::kAppKiosk));
+ EXPECT_CALL(*user_manager_, IsLoggedInAsWebKioskApp())
+ .WillRepeatedly(
+ Return(session_type_ == DeviceLocalAccountSessionType::kWebKiosk));
+ EXPECT_CALL(*user_manager_, IsLoggedInAsPublicAccount())
+ .WillRepeatedly(
+ Return(session_type_ == DeviceLocalAccountSessionType::kPublic));
+ EXPECT_CALL(*user_manager_, GetLoggedInUsers())
+ .WillRepeatedly(
+ testing::Invoke(user_manager_, &ash::MockUserManager::GetUsers));
+ scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
+ base::WrapUnique(user_manager_));
+ }
+
+ void TearDownOnMainThread() { scoped_user_manager_.reset(); }
+
+ private:
+ const DeviceLocalAccountSessionType session_type_;
+
+ // Set up fake install attributes to make the device appeared as
+ // enterprise-managed.
+ ash::ScopedStubInstallAttributes test_install_attributes_{
+ ash::StubInstallAttributes::CreateCloudManaged("example.com", "fake-id")};
+
+ // Owned by |scoped_user_manager_|.
+ ash::MockUserManager* user_manager_;
+ std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
+};
+#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+class GetAuthTokenFunctionDeviceLocalAccountTestPlatformHelper {
+ public:
+ explicit GetAuthTokenFunctionDeviceLocalAccountTestPlatformHelper(
+ DeviceLocalAccountSessionType session_type) {
+ crosapi::mojom::SessionType init_params_session_type =
+ crosapi::mojom::SessionType::kUnknown;
+ switch (session_type) {
+ case DeviceLocalAccountSessionType::kPublic:
+ init_params_session_type = crosapi::mojom::SessionType::kPublicSession;
+ break;
+ case DeviceLocalAccountSessionType::kAppKiosk:
+ init_params_session_type =
+ crosapi::mojom::SessionType::kAppKioskSession;
+ break;
+ case DeviceLocalAccountSessionType::kWebKiosk:
+ init_params_session_type =
+ crosapi::mojom::SessionType::kWebKioskSession;
+ break;
+ }
+ crosapi::mojom::BrowserInitParamsPtr init_params =
+ crosapi::mojom::BrowserInitParams::New();
+ init_params->session_type = init_params_session_type;
+ init_params->is_device_enterprised_managed = true;
+ init_params->device_settings = crosapi::mojom::DeviceSettings::New();
+ chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params));
+ }
+
+ void SetUpOnMainThread() {}
+ void TearDownOnMainThread() {}
+};
+#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
+
class GetAuthTokenFunctionDeviceLocalAccountTest
: public GetAuthTokenFunctionTest {
public:
- GetAuthTokenFunctionDeviceLocalAccountTest()
- : user_manager_(new ash::MockUserManager) {}
+ explicit GetAuthTokenFunctionDeviceLocalAccountTest(
+ DeviceLocalAccountSessionType session_type)
+ : platform_helper_(session_type) {}
void SetUpOnMainThread() override {
+ platform_helper_.SetUpOnMainThread();
GetAuthTokenFunctionTest::SetUpOnMainThread();
- scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
- base::WrapUnique(user_manager_));
}
void TearDownOnMainThread() override {
GetAuthTokenFunctionTest::TearDownOnMainThread();
- scoped_user_manager_.reset();
+ platform_helper_.TearDownOnMainThread();
}
protected:
@@ -2854,33 +2919,15 @@ class GetAuthTokenFunctionDeviceLocalAccountTest
.Build();
}
- // Set up fake install attributes to make the device appeared as
- // enterprise-managed.
- ash::ScopedStubInstallAttributes test_install_attributes_{
- ash::StubInstallAttributes::CreateCloudManaged("example.com", "fake-id")};
-
- // Owned by |user_manager_enabler|.
- ash::MockUserManager* user_manager_;
- std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
+ GetAuthTokenFunctionDeviceLocalAccountTestPlatformHelper platform_helper_;
};
class GetAuthTokenFunctionPublicSessionTest
: public GetAuthTokenFunctionDeviceLocalAccountTest {
protected:
- void SetUpInProcessBrowserTestFixture() override {
- GetAuthTokenFunctionTest::SetUpInProcessBrowserTestFixture();
-
- // Set up the user manager to fake a public session.
- EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
- .WillRepeatedly(Return(false));
- EXPECT_CALL(*user_manager_, IsLoggedInAsWebKioskApp())
- .WillRepeatedly(Return(false));
- EXPECT_CALL(*user_manager_, IsLoggedInAsPublicAccount())
- .WillRepeatedly(Return(true));
- EXPECT_CALL(*user_manager_, GetLoggedInUsers())
- .WillRepeatedly(
- testing::Invoke(user_manager_, &ash::MockUserManager::GetUsers));
- }
+ GetAuthTokenFunctionPublicSessionTest()
+ : GetAuthTokenFunctionDeviceLocalAccountTest(
+ DeviceLocalAccountSessionType::kPublic) {}
};
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionPublicSessionTest, NonAllowlisted) {
@@ -2901,20 +2948,9 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionPublicSessionTest, NonAllowlisted) {
class GetAuthTokenFunctionChromeKioskTest
: public GetAuthTokenFunctionDeviceLocalAccountTest {
protected:
- void SetUpInProcessBrowserTestFixture() override {
- GetAuthTokenFunctionTest::SetUpInProcessBrowserTestFixture();
-
- // Set up the user manager to fake a Chrome Kiosk session.
- EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
- .WillRepeatedly(Return(true));
- EXPECT_CALL(*user_manager_, IsLoggedInAsWebKioskApp())
- .WillRepeatedly(Return(false));
- EXPECT_CALL(*user_manager_, IsLoggedInAsPublicAccount())
- .WillRepeatedly(Return(false));
- EXPECT_CALL(*user_manager_, GetLoggedInUsers())
- .WillRepeatedly(
- testing::Invoke(user_manager_, &ash::MockUserManager::GetUsers));
- }
+ GetAuthTokenFunctionChromeKioskTest()
+ : GetAuthTokenFunctionDeviceLocalAccountTest(
+ DeviceLocalAccountSessionType::kAppKiosk) {}
};
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionChromeKioskTest, NonAllowlisted) {
@@ -2926,20 +2962,9 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionChromeKioskTest, NonAllowlisted) {
class GetAuthTokenFunctionWebKioskTest
: public GetAuthTokenFunctionDeviceLocalAccountTest {
protected:
- void SetUpInProcessBrowserTestFixture() override {
- GetAuthTokenFunctionTest::SetUpInProcessBrowserTestFixture();
-
- // Set up the user manager to fake a web Kiosk session.
- EXPECT_CALL(*user_manager_, IsLoggedInAsKioskApp())
- .WillRepeatedly(Return(false));
- EXPECT_CALL(*user_manager_, IsLoggedInAsWebKioskApp())
- .WillRepeatedly(Return(true));
- EXPECT_CALL(*user_manager_, IsLoggedInAsPublicAccount())
- .WillRepeatedly(Return(false));
- EXPECT_CALL(*user_manager_, GetLoggedInUsers())
- .WillRepeatedly(
- testing::Invoke(user_manager_, &ash::MockUserManager::GetUsers));
- }
+ GetAuthTokenFunctionWebKioskTest()
+ : GetAuthTokenFunctionDeviceLocalAccountTest(
+ DeviceLocalAccountSessionType::kWebKiosk) {}
};
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionWebKioskTest, NonAllowlisted) {
@@ -2948,7 +2973,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionWebKioskTest, NonAllowlisted) {
RunExtensionAndVerifyNoError(/*is_extension_allowlisted=*/false);
}
-#endif
+#endif // BUILDFLAG(IS_CHROMEOS)
// There are two parameters, which are stored in a std::pair, for these tests.
//
@@ -3152,7 +3177,7 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionSelectedUserIdTest,
1);
}
-// The signin flow is not used on ChromeOS.
+// The signin flow is not used on Ash.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
// Tests that Chrome does not have any selected user id value if the account
// specified by the extension is not available.
@@ -3511,7 +3536,7 @@ class OnSignInChangedEventTest : public IdentityTestWithSignin {
// been added. This is because the order of multiple events firing due to the
// same underlying state change is undefined in the
// chrome.identity.onSignInEventChanged() API.
- void AddExpectedEvent(std::vector<base::Value> args) {
+ void AddExpectedEvent(base::Value::List args) {
expected_events_.insert(
std::make_unique<Event>(events::IDENTITY_ON_SIGN_IN_CHANGED,
api::identity::OnSignInChanged::kEventName,
@@ -3526,13 +3551,13 @@ class OnSignInChangedEventTest : public IdentityTestWithSignin {
// Search for |event| in the set of expected events.
bool found_event = false;
- const auto* event_args = event->event_args.get();
+ const auto& event_args = event->event_args;
for (const auto& expected_event : expected_events_) {
EXPECT_EQ(expected_event->histogram_value, event->histogram_value);
EXPECT_EQ(expected_event->event_name, event->event_name);
- const auto* expected_event_args = expected_event->event_args.get();
- if (*event_args != *expected_event_args)
+ const auto& expected_event_args = expected_event->event_args;
+ if (event_args != expected_event_args)
continue;
expected_events_.erase(expected_event);
@@ -3546,11 +3571,11 @@ class OnSignInChangedEventTest : public IdentityTestWithSignin {
LOG(INFO) << "Was expecting events with these args:";
for (const auto& expected_event : expected_events_) {
- LOG(INFO) << *(expected_event->event_args.get());
+ LOG(INFO) << expected_event->event_args;
}
LOG(INFO) << "But received event with different args:";
- LOG(INFO) << *event_args;
+ LOG(INFO) << event_args;
}
}
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 24c2561d4cd..b425e031d91 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
@@ -8,19 +8,14 @@
#include <vector>
#include "base/bind.h"
-#include "base/feature_list.h"
#include "base/location.h"
-#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
-#include "base/strings/string_number_conversions.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_process_platform_part.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/identity_get_auth_token_error.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/chrome_device_id_helper.h"
@@ -30,7 +25,6 @@
#include "chrome/common/extensions/api/identity.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_pref_names.h"
-#include "components/signin/public/base/signin_switches.h"
#include "components/signin/public/identity_manager/access_token_info.h"
#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
#include "components/signin/public/identity_manager/scope_set.h"
@@ -38,20 +32,15 @@
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/common/api/oauth2.h"
-#include "extensions/common/extension_features.h"
-#include "extensions/common/extension_l10n_util.h"
#include "extensions/common/manifest_handlers/oauth2_manifest_handler.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_urls.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chrome/browser/app_mode/app_mode_utils.h"
-#include "chrome/browser/ash/login/session/user_session_manager.h"
-#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
-#include "chrome/browser/device_identity/device_oauth2_token_service.h"
-#include "chrome/browser/device_identity/device_oauth2_token_service_factory.h"
-#include "components/user_manager/user_manager.h"
+#if BUILDFLAG(IS_CHROMEOS)
+#include "chrome/browser/policy/chrome_browser_policy_connector.h"
+#include "chrome/browser/profiles/profiles_state.h"
+#include "components/account_manager_core/account_manager_util.h"
#include "google_apis/gaia/gaia_constants.h"
#endif
@@ -87,13 +76,7 @@ void RecordFunctionResult(const IdentityGetAuthTokenError& error,
} // namespace
-IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction()
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- : OAuth2AccessTokenManager::Consumer(
- kExtensionsIdentityAPIOAuthConsumerName)
-#endif
-{
-}
+IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction() = default;
IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {
TRACE_EVENT_NESTABLE_ASYNC_END0("identity", "IdentityGetAuthTokenFunction",
@@ -237,24 +220,18 @@ void IdentityGetAuthTokenFunction::OnReceivedExtensionAccountInfo(
const CoreAccountInfo& account_info) {
token_key_.account_info = account_info;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- policy::BrowserPolicyConnectorAsh* connector =
- g_browser_process->platform_part()->browser_policy_connector_ash();
- bool is_kiosk = user_manager::UserManager::Get()->IsLoggedInAsKioskApp() ||
- user_manager::UserManager::Get()->IsLoggedInAsWebKioskApp();
- bool is_public_session =
- user_manager::UserManager::Get()->IsLoggedInAsPublicAccount();
-
- if (connector->IsDeviceEnterpriseManaged() &&
- (is_kiosk || is_public_session)) {
- if (is_public_session) {
+#if BUILDFLAG(IS_CHROMEOS)
+ if (g_browser_process->browser_policy_connector()
+ ->IsDeviceEnterpriseManaged()) {
+ if (profiles::IsPublicSession()) {
CompleteFunctionWithError(IdentityGetAuthTokenError(
IdentityGetAuthTokenError::State::kNotAllowlistedInPublicSession));
return;
}
-
- StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE);
- return;
+ if (profiles::IsKioskSession()) {
+ StartMintTokenFlow(IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE);
+ return;
+ }
}
#endif
@@ -325,12 +302,13 @@ void IdentityGetAuthTokenFunction::CompleteFunctionWithResult(
const std::set<std::string>& granted_scopes) {
RecordFunctionResult(IdentityGetAuthTokenError(), remote_consent_approved_);
- base::Value::List granted_scopes_value;
- for (const auto& scope : granted_scopes)
- granted_scopes_value.Append(scope);
+ api::identity::GetAuthTokenResult result;
+ result.token = std::make_unique<std::string>(access_token);
+ result.granted_scopes = std::make_unique<std::vector<std::string>>(
+ granted_scopes.begin(), granted_scopes.end());
- CompleteAsyncRun(TwoArguments(base::Value(access_token),
- base::Value(std::move(granted_scopes_value))));
+ CompleteAsyncRun(
+ OneArgument(base::Value::FromUniquePtrValue(result.ToValue())));
}
void IdentityGetAuthTokenFunction::CompleteFunctionWithError(
@@ -404,7 +382,7 @@ void IdentityGetAuthTokenFunction::StartSigninFlow() {
void IdentityGetAuthTokenFunction::StartMintTokenFlow(
IdentityMintRequestQueue::MintType type) {
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !BUILDFLAG(IS_CHROMEOS)
// ChromeOS in kiosk mode may start the mint token flow without account.
DCHECK(!token_key_.account_info.IsEmpty());
DCHECK(IdentityManagerFactory::GetForProfile(GetProfile())
@@ -469,23 +447,18 @@ void IdentityGetAuthTokenFunction::StartMintToken(
if (type == IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE) {
switch (cache_status) {
case IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND:
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
// Always force minting token for ChromeOS kiosk app and public session.
- if (user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()) {
+ if (profiles::IsPublicSession()) {
CompleteFunctionWithError(
IdentityGetAuthTokenError(IdentityGetAuthTokenError::State::
kNotAllowlistedInPublicSession));
return;
}
-
- if (user_manager::UserManager::Get()->IsLoggedInAsKioskApp() ||
- user_manager::UserManager::Get()->IsLoggedInAsWebKioskApp() ||
- user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()) {
+ if (profiles::IsKioskSession()) {
gaia_mint_token_mode_ = OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE;
- policy::BrowserPolicyConnectorAsh* connector =
- g_browser_process->platform_part()
- ->browser_policy_connector_ash();
- if (connector->IsDeviceEnterpriseManaged()) {
+ if (g_browser_process->browser_policy_connector()
+ ->IsDeviceEnterpriseManaged()) {
StartDeviceAccessTokenRequest();
} else {
StartTokenKeyAccountAccessTokenRequest();
@@ -765,7 +738,9 @@ void IdentityGetAuthTokenFunction::OnGetAccessTokenComplete(
const GoogleServiceAuthError& error) {
// By the time we get here we should no longer have an outstanding access
// token request.
- DCHECK(!device_access_token_request_);
+#if BUILDFLAG(IS_CHROMEOS)
+ DCHECK(!device_oauth2_token_fetcher_);
+#endif
DCHECK(!token_key_account_access_token_fetcher_);
if (access_token) {
TRACE_EVENT_NESTABLE_ASYNC_END1(
@@ -787,21 +762,23 @@ void IdentityGetAuthTokenFunction::OnGetAccessTokenComplete(
}
}
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-void IdentityGetAuthTokenFunction::OnGetTokenSuccess(
- const OAuth2AccessTokenManager::Request* request,
- const OAuth2AccessTokenConsumer::TokenResponse& token_response) {
- device_access_token_request_.reset();
- OnGetAccessTokenComplete(token_response.access_token,
- token_response.expiration_time,
- GoogleServiceAuthError::AuthErrorNone());
-}
-
-void IdentityGetAuthTokenFunction::OnGetTokenFailure(
- const OAuth2AccessTokenManager::Request* request,
- const GoogleServiceAuthError& error) {
- device_access_token_request_.reset();
- OnGetAccessTokenComplete(absl::nullopt, base::Time(), error);
+#if BUILDFLAG(IS_CHROMEOS)
+void IdentityGetAuthTokenFunction::OnAccessTokenForDeviceAccountFetchCompleted(
+ crosapi::mojom::AccessTokenResultPtr result) {
+ absl::optional<std::string> access_token;
+ base::Time expiration_time;
+ GoogleServiceAuthError error = GoogleServiceAuthError::AuthErrorNone();
+ if (result->is_access_token_info()) {
+ access_token = result->get_access_token_info()->access_token;
+ expiration_time = result->get_access_token_info()->expiration_time;
+ } else {
+ DCHECK(result->is_error());
+ error = account_manager::FromMojoGoogleServiceAuthError(result->get_error())
+ .value_or(GoogleServiceAuthError(
+ GoogleServiceAuthError::SERVICE_ERROR));
+ }
+ device_oauth2_token_fetcher_.reset();
+ OnGetAccessTokenComplete(access_token, expiration_time, error);
}
#endif
@@ -819,7 +796,9 @@ void IdentityGetAuthTokenFunction::OnAccessTokenFetchCompleted(
}
void IdentityGetAuthTokenFunction::OnIdentityAPIShutdown() {
- device_access_token_request_.reset();
+#if BUILDFLAG(IS_CHROMEOS)
+ device_oauth2_token_fetcher_.reset();
+#endif
token_key_account_access_token_fetcher_.reset();
scoped_identity_manager_observation_.Reset();
extensions::IdentityAPI::GetFactoryInstance()
@@ -831,18 +810,18 @@ void IdentityGetAuthTokenFunction::OnIdentityAPIShutdown() {
IdentityGetAuthTokenError(IdentityGetAuthTokenError::State::kCanceled));
}
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-// Even though the DeviceOAuth2TokenService may be available on non-ChromeOS
-// platforms, its robot account is not made available because it should only be
-// used for very specific policy-related things. In fact, the device account on
-// desktop isn't scoped for anything other than policy invalidations.
+#if BUILDFLAG(IS_CHROMEOS)
void IdentityGetAuthTokenFunction::StartDeviceAccessTokenRequest() {
- DeviceOAuth2TokenService* service = DeviceOAuth2TokenServiceFactory::Get();
+ device_oauth2_token_fetcher_ = std::make_unique<DeviceOAuth2TokenFetcher>();
// Since robot account refresh tokens are scoped down to [any-api] only,
// request access token for [any-api] instead of login.
- OAuth2AccessTokenManager::ScopeSet scopes;
- scopes.insert(GaiaConstants::kAnyApiOAuth2Scope);
- device_access_token_request_ = service->StartAccessTokenRequest(scopes, this);
+ // `Unretained()` is safe because this outlives
+ // `device_oauth2_token_fetcher_`.
+ device_oauth2_token_fetcher_->FetchAccessTokenForDeviceAccount(
+ {GaiaConstants::kAnyApiOAuth2Scope},
+ base::BindOnce(&IdentityGetAuthTokenFunction::
+ OnAccessTokenForDeviceAccountFetchCompleted,
+ base::Unretained(this)));
}
#endif
@@ -850,26 +829,6 @@ void IdentityGetAuthTokenFunction::StartTokenKeyAccountAccessTokenRequest() {
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("identity", "GetAccessToken", this);
auto* identity_manager = IdentityManagerFactory::GetForProfile(GetProfile());
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- if (chrome::IsRunningInForcedAppMode()) {
- std::string app_client_id;
- std::string app_client_secret;
- if (ash::UserSessionManager::GetInstance()->GetAppModeChromeClientOAuthInfo(
- &app_client_id, &app_client_secret)) {
- token_key_account_access_token_fetcher_ =
- identity_manager->CreateAccessTokenFetcherForClient(
- token_key_.account_info.account_id, app_client_id,
- app_client_secret, kExtensionsIdentityAPIOAuthConsumerName,
- signin::ScopeSet(),
- base::BindOnce(
- &IdentityGetAuthTokenFunction::OnAccessTokenFetchCompleted,
- base::Unretained(this)),
- signin::AccessTokenFetcher::Mode::kImmediate);
- return;
- }
- }
-#endif
-
token_key_account_access_token_fetcher_ =
identity_manager->CreateAccessTokenFetcherForAccount(
token_key_.account_info.account_id,
diff --git a/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h b/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h
index fd4958bfe33..a90de50b024 100644
--- a/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h
+++ b/chromium/chrome/browser/extensions/api/identity/identity_get_auth_token_function.h
@@ -20,10 +20,17 @@
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_function_histogram_value.h"
#include "google_apis/gaia/google_service_auth_error.h"
-#include "google_apis/gaia/oauth2_access_token_manager.h"
#include "google_apis/gaia/oauth2_mint_token_flow.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/crosapi/device_oauth2_token_service_ash.h"
+#endif
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chrome/browser/lacros/device_oauth2_token_service_lacros.h"
+#endif
+
namespace signin {
class AccessTokenFetcher;
struct AccessTokenInfo;
@@ -53,9 +60,6 @@ class IdentityGetAuthTokenFunction : public ExtensionFunction,
public GaiaRemoteConsentFlow::Delegate,
public IdentityMintRequestQueue::Request,
public signin::IdentityManager::Observer,
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- public OAuth2AccessTokenManager::Consumer,
-#endif
public OAuth2MintTokenFlow::Delegate {
public:
DECLARE_EXTENSION_FUNCTION("identity.getAuthToken",
@@ -81,15 +85,9 @@ class IdentityGetAuthTokenFunction : public ExtensionFunction,
// Starts a login access token request.
virtual void StartTokenKeyAccountAccessTokenRequest();
-// TODO(blundell): Investigate feasibility of moving the ChromeOS use case
-// to use the Identity Service instead of being an
-// OAuth2AccessTokenManager::Consumer.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- void OnGetTokenSuccess(
- const OAuth2AccessTokenManager::Request* request,
- const OAuth2AccessTokenConsumer::TokenResponse& token_response) override;
- void OnGetTokenFailure(const OAuth2AccessTokenManager::Request* request,
- const GoogleServiceAuthError& error) override;
+#if BUILDFLAG(IS_CHROMEOS)
+ void OnAccessTokenForDeviceAccountFetchCompleted(
+ crosapi::mojom::AccessTokenResultPtr result);
#endif
void OnAccessTokenFetchCompleted(GoogleServiceAuthError error,
@@ -117,10 +115,16 @@ class IdentityGetAuthTokenFunction : public ExtensionFunction,
// Exposed for testing.
std::string GetSelectedUserId() const;
- // Pending request for an access token from the device account (via
- // DeviceOAuth2TokenService).
- std::unique_ptr<OAuth2AccessTokenManager::Request>
- device_access_token_request_;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ using DeviceOAuth2TokenFetcher = crosapi::DeviceOAuth2TokenServiceAsh;
+#endif
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ using DeviceOAuth2TokenFetcher = DeviceOAuth2TokenServiceLacros;
+#endif
+
+#if BUILDFLAG(IS_CHROMEOS)
+ std::unique_ptr<DeviceOAuth2TokenFetcher> device_oauth2_token_fetcher_;
+#endif
// Pending fetcher for an access token for |token_key_.account_id| (via
// IdentityManager).
@@ -194,7 +198,7 @@ class IdentityGetAuthTokenFunction : public ExtensionFunction,
void OnRemoteConsentSuccess(
const RemoteConsentResolutionData& resolution_data) override;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
// Starts a login access token request for device robot account. This method
// will be called only in Chrome OS for:
// 1. Enterprise kiosk mode.
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 ea9512fd6a8..4f96aeacb0a 100644
--- a/chromium/chrome/browser/extensions/api/identity/web_auth_flow.cc
+++ b/chromium/chrome/browser/extensions/api/identity/web_auth_flow.cc
@@ -105,19 +105,19 @@ void WebAuthFlow::Start() {
base::Base64Encode(random_bytes, &app_window_key_);
// identityPrivate.onWebFlowRequest(app_window_key, provider_url_, mode_)
- std::unique_ptr<base::ListValue> args(new base::ListValue());
- args->Append(app_window_key_);
- args->Append(provider_url_.spec());
+ base::Value::List args;
+ args.Append(app_window_key_);
+ args.Append(provider_url_.spec());
if (mode_ == WebAuthFlow::INTERACTIVE)
- args->Append("interactive");
+ args.Append("interactive");
else
- args->Append("silent");
- args->Append(GetPartitionName(partition_));
+ args.Append("silent");
+ args.Append(GetPartitionName(partition_));
auto event =
std::make_unique<Event>(events::IDENTITY_PRIVATE_ON_WEB_FLOW_REQUEST,
identity_private::OnWebFlowRequest::kEventName,
- std::move(*args).TakeListDeprecated(), profile_);
+ std::move(args), profile_);
ExtensionSystem* system = ExtensionSystem::Get(profile_);
extensions::ComponentLoader* component_loader =
diff --git a/chromium/chrome/browser/extensions/api/idltest/idltest_api.cc b/chromium/chrome/browser/extensions/api/idltest/idltest_api.cc
index b54ad539360..3ef76a3cb94 100644
--- a/chromium/chrome/browser/extensions/api/idltest/idltest_api.cc
+++ b/chromium/chrome/browser/extensions/api/idltest/idltest_api.cc
@@ -17,10 +17,10 @@ namespace {
base::Value CopyBinaryValueToIntegerList(
const base::Value::BlobStorage& input) {
- base::Value::ListStorage list;
+ base::Value::List list;
list.reserve(input.size());
for (int c : input)
- list.emplace_back(c);
+ list.Append(c);
return base::Value(std::move(list));
}
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 686d4b08a37..027ce24d140 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
@@ -5,6 +5,7 @@
#include "chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.h"
#include "base/containers/contains.h"
+#include "base/memory/raw_ptr.h"
#include "base/no_destructor.h"
#include "chrome/browser/extensions/api/image_writer_private/error_constants.h"
#include "chrome/common/extensions/api/image_writer_private.h"
@@ -117,8 +118,9 @@ class ImageWriterControllerLacros::ImageWriterClientLacros
// to be valid for the lifetime of this class, as destruction of either
// BrowserContext or ImageWriterControllerLacros will result in synchronous
// destruction of this class.
- content::BrowserContext* const browser_context_;
- extensions::image_writer::ImageWriterControllerLacros* const controller_;
+ const raw_ptr<content::BrowserContext> browser_context_;
+ const raw_ptr<extensions::image_writer::ImageWriterControllerLacros>
+ controller_;
mojo::Receiver<crosapi::mojom::ImageWriterClient> receiver_{this};
};
diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.h b/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.h
index 78d1a3be862..379c028f085 100644
--- a/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.h
+++ b/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_controller_lacros.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_EXTENSIONS_API_IMAGE_WRITER_PRIVATE_IMAGE_WRITER_CONTROLLER_LACROS_H_
#include "base/callback.h"
+#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "chromeos/crosapi/mojom/image_writer.mojom.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
@@ -86,7 +87,7 @@ class ImageWriterControllerLacros : public BrowserContextKeyedAPI,
// BrowserContextKeyedAPI with |browser_context_| which will handle the
// destruction of BrowserContext gracefully by shutting down the service
// and removing itself from the factory.
- content::BrowserContext* browser_context_;
+ raw_ptr<content::BrowserContext> browser_context_;
// Pending image writer clients by extension id.
// For each extension, we only allow one pending remote client to request
diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc b/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
index 067f00bf3dc..fab3f50caf0 100644
--- a/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/image_writer_private/image_writer_private_apitest.cc
@@ -28,7 +28,7 @@ class ImageWriterPrivateApiTest : public ExtensionApiTest {
public:
void SetUpInProcessBrowserTestFixture() override {
ExtensionApiTest::SetUpInProcessBrowserTestFixture();
- test_utils_.SetUp(true);
+ test_utils_.SetUp();
ASSERT_TRUE(test_utils_.FillFile(test_utils_.GetImagePath(),
image_writer::kImagePattern,
diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/operation.h b/chromium/chrome/browser/extensions/api/image_writer_private/operation.h
index 5dd62723945..0d6d8732764 100644
--- a/chromium/chrome/browser/extensions/api/image_writer_private/operation.h
+++ b/chromium/chrome/browser/extensions/api/image_writer_private/operation.h
@@ -187,7 +187,7 @@ class Operation : public base::RefCountedThreadSafe<Operation> {
void UnmountVolumes(base::OnceClosure continuation);
// Starts the write after unmounting.
void UnmountVolumesCallback(base::OnceClosure continuation,
- chromeos::MountError error_code);
+ ash::MountError error_code);
// Starts the ImageBurner write. Note that target_path is the file path of
// the device where device_path has been a system device path.
void StartWriteOnUIThread(const std::string& target_path,
diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc b/chromium/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc
index 61ed8e2f1da..55db9f49224 100644
--- a/chromium/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc
+++ b/chromium/chrome/browser/extensions/api/image_writer_private/operation_chromeos.cc
@@ -10,16 +10,15 @@
#include "base/bind.h"
#include "chrome/browser/extensions/api/image_writer_private/error_constants.h"
#include "chrome/browser/extensions/api/image_writer_private/operation.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/image_burner/image_burner_client.h"
+#include "chromeos/ash/components/dbus/image_burner/image_burner_client.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
namespace extensions {
namespace image_writer {
+using ::ash::ImageBurnerClient;
using ::ash::disks::DiskMountManager;
-using chromeos::ImageBurnerClient;
using content::BrowserThread;
namespace {
@@ -31,9 +30,7 @@ void ClearImageBurner() {
return;
}
- chromeos::DBusThreadManager::Get()->
- GetImageBurnerClient()->
- ResetEventHandlers();
+ ImageBurnerClient::Get()->ResetEventHandlers();
}
} // namespace
@@ -65,19 +62,19 @@ void Operation::UnmountVolumes(base::OnceClosure continuation) {
}
void Operation::UnmountVolumesCallback(base::OnceClosure continuation,
- chromeos::MountError error_code) {
+ ash::MountError error_code) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (error_code != chromeos::MOUNT_ERROR_NONE) {
+ if (error_code != ash::MountError::kNone) {
LOG(ERROR) << "Volume unmounting failed with error code " << error_code;
PostTask(
base::BindOnce(&Operation::Error, this, error::kUnmountVolumesError));
return;
}
- const DiskMountManager::DiskMap& disks =
+ const DiskMountManager::Disks& disks =
DiskMountManager::GetInstance()->disks();
- DiskMountManager::DiskMap::const_iterator iter =
+ DiskMountManager::Disks::const_iterator iter =
disks.find(device_path_.value());
if (iter == disks.end()) {
@@ -87,7 +84,7 @@ void Operation::UnmountVolumesCallback(base::OnceClosure continuation,
return;
}
- StartWriteOnUIThread(iter->second->file_path(), std::move(continuation));
+ StartWriteOnUIThread(iter->get()->file_path(), std::move(continuation));
}
void Operation::StartWriteOnUIThread(const std::string& target_path,
@@ -95,8 +92,7 @@ void Operation::StartWriteOnUIThread(const std::string& target_path,
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// TODO(haven): Image Burner cannot handle multiple burns. crbug.com/373575
- ImageBurnerClient* burner =
- chromeos::DBusThreadManager::Get()->GetImageBurnerClient();
+ ImageBurnerClient* burner = ImageBurnerClient::Get();
burner->SetEventHandlers(
base::BindOnce(&Operation::OnBurnFinished, this, std::move(continuation)),
diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos.cc b/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos.cc
index 87170877c19..04850f040ad 100644
--- a/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos.cc
+++ b/chromium/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos.cc
@@ -24,25 +24,22 @@ using ::ash::disks::DiskMountManager;
scoped_refptr<StorageDeviceList>
RemovableStorageProvider::PopulateDeviceList() {
DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance();
- const DiskMountManager::DiskMap& disks = disk_mount_manager->disks();
+ const DiskMountManager::Disks& disks = disk_mount_manager->disks();
auto device_list = base::MakeRefCounted<StorageDeviceList>();
- for (DiskMountManager::DiskMap::const_iterator iter = disks.begin();
- iter != disks.end();
- ++iter) {
- const Disk& disk = *iter->second;
- if (disk.is_parent() && !disk.on_boot_device() && disk.has_media() &&
- (disk.device_type() == chromeos::DEVICE_TYPE_USB ||
- disk.device_type() == chromeos::DEVICE_TYPE_SD)) {
+ for (const auto& disk : disks) {
+ if (disk->is_parent() && !disk->on_boot_device() && disk->has_media() &&
+ (disk->device_type() == ash::DeviceType::kUSB ||
+ disk->device_type() == ash::DeviceType::kSD)) {
api::image_writer_private::RemovableStorageDevice device;
- device.storage_unit_id = disk.device_path();
- device.capacity = disk.total_size_in_bytes();
- device.removable = disk.on_removable_device();
- device.vendor = disk.vendor_name();
- device.model = disk.product_name();
+ device.storage_unit_id = disk->device_path();
+ device.capacity = disk->total_size_in_bytes();
+ device.removable = disk->on_removable_device();
+ device.vendor = disk->vendor_name();
+ device.model = disk->product_name();
if (device.model.empty() && device.vendor.empty()) {
- if (disk.device_type() == chromeos::DEVICE_TYPE_USB) {
+ if (disk->device_type() == ash::DeviceType::kUSB) {
device.model = kUnknownUSBDiskModel;
} else {
device.model = kUnknownSDDiskModel;
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 83ad5b19b17..7ac0ef47404 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
@@ -46,7 +46,7 @@ class RemovableStorageProviderChromeOsUnitTest : public testing::Test {
}
void CreateDisk(const std::string& device_path,
- chromeos::DeviceType device_type,
+ ash::DeviceType device_type,
bool is_parent,
bool has_media,
bool on_boot_device) {
@@ -62,13 +62,12 @@ class RemovableStorageProviderChromeOsUnitTest : public testing::Test {
void CreateDisk(const std::string& device_path,
const std::string& vendor_name,
const std::string& product_name,
- chromeos::DeviceType device_type,
+ ash::DeviceType device_type,
bool is_parent,
bool has_media,
bool on_boot_device) {
- ash::disks::DiskMountManager::MountPointInfo mount_info(
- device_path, kMountPath, chromeos::MOUNT_TYPE_DEVICE,
- ash::disks::MOUNT_CONDITION_NONE);
+ ash::disks::DiskMountManager::MountPoint mount_info{
+ device_path, kMountPath, ash::MountType::kDevice};
disk_mount_manager_mock_->CreateDiskEntryForMountDevice(
mount_info, kDeviceId, kDeviceName, vendor_name, product_name,
device_type, kDeviceSize, is_parent, has_media, on_boot_device,
@@ -112,11 +111,11 @@ class RemovableStorageProviderChromeOsUnitTest : public testing::Test {
// that are parents, have media and are not boot devices. Other flags are
// uninteresting or should not occur for these device types.
TEST_F(RemovableStorageProviderChromeOsUnitTest, GetAllDevices) {
- CreateDisk(kDevicePathUSB, chromeos::DEVICE_TYPE_USB, true, true, false);
- CreateDisk(kDevicePathSD, chromeos::DEVICE_TYPE_SD, true, true, false);
- CreateDisk("/dev/NotParent", chromeos::DEVICE_TYPE_USB, false, true, false);
- CreateDisk("/dev/NoMedia", chromeos::DEVICE_TYPE_USB, true, false, false);
- CreateDisk("/dev/OnBootDevice", chromeos::DEVICE_TYPE_USB, true, true, true);
+ CreateDisk(kDevicePathUSB, ash::DeviceType::kUSB, true, true, false);
+ CreateDisk(kDevicePathSD, ash::DeviceType::kSD, true, true, false);
+ CreateDisk("/dev/NotParent", ash::DeviceType::kUSB, false, true, false);
+ CreateDisk("/dev/NoMedia", ash::DeviceType::kUSB, true, false, false);
+ CreateDisk("/dev/OnBootDevice", ash::DeviceType::kUSB, true, true, true);
RemovableStorageProvider::GetAllDevices(
base::BindOnce(&RemovableStorageProviderChromeOsUnitTest::DevicesCallback,
@@ -134,10 +133,8 @@ TEST_F(RemovableStorageProviderChromeOsUnitTest, GetAllDevices) {
// Tests that a USB drive with an empty vendor and product gets a generic name.
TEST_F(RemovableStorageProviderChromeOsUnitTest, EmptyProductAndModel) {
- CreateDisk(
- kDevicePathUSB, "", "", chromeos::DEVICE_TYPE_USB, true, true, false);
- CreateDisk(
- kDevicePathSD, "", "", chromeos::DEVICE_TYPE_SD, true, true, false);
+ CreateDisk(kDevicePathUSB, "", "", ash::DeviceType::kUSB, true, true, false);
+ CreateDisk(kDevicePathSD, "", "", ash::DeviceType::kSD, true, true, false);
RemovableStorageProvider::GetAllDevices(
base::BindOnce(&RemovableStorageProviderChromeOsUnitTest::DevicesCallback,
diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/test_utils.cc b/chromium/chrome/browser/extensions/api/image_writer_private/test_utils.cc
index ab8c0ec7152..6e42056ac58 100644
--- a/chromium/chrome/browser/extensions/api/image_writer_private/test_utils.cc
+++ b/chromium/chrome/browser/extensions/api/image_writer_private/test_utils.cc
@@ -21,18 +21,16 @@
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/components/disks/disk.h"
#include "chromeos/ash/components/dbus/concierge/concierge_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h" // nogncheck
-#include "chromeos/dbus/image_burner/fake_image_burner_client.h"
+#include "chromeos/ash/components/dbus/dbus_thread_manager.h" // nogncheck
+#include "chromeos/ash/components/dbus/image_burner/fake_image_burner_client.h"
+#include "chromeos/ash/components/dbus/image_burner/image_burner_client.h"
#endif
namespace extensions {
namespace image_writer {
#if BUILDFLAG(IS_CHROMEOS_ASH)
-namespace {
-
-class ImageWriterFakeImageBurnerClient
- : public chromeos::FakeImageBurnerClient {
+class ImageWriterFakeImageBurnerClient : public ash::FakeImageBurnerClient {
public:
ImageWriterFakeImageBurnerClient() = default;
~ImageWriterFakeImageBurnerClient() override = default;
@@ -65,8 +63,6 @@ class ImageWriterFakeImageBurnerClient
BurnFinishedHandler burn_finished_handler_;
BurnProgressUpdateHandler burn_progress_update_handler_;
};
-
-} // namespace
#endif
MockOperationManager::MockOperationManager(content::BrowserContext* context)
@@ -81,8 +77,7 @@ void FakeDiskMountManager::UnmountDeviceRecursively(
const std::string& device_path,
UnmountDeviceRecursivelyCallbackType callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(callback), chromeos::MOUNT_ERROR_NONE));
+ FROM_HERE, base::BindOnce(std::move(callback), ash::MountError::kNone));
}
#endif
@@ -227,10 +222,6 @@ void ImageWriterTestUtils::RunOnUtilityClientCreation(
#endif
void ImageWriterTestUtils::SetUp() {
- SetUp(false);
-}
-
-void ImageWriterTestUtils::SetUp(bool is_browser_test) {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
ASSERT_TRUE(
base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &test_image_path_));
@@ -241,29 +232,23 @@ void ImageWriterTestUtils::SetUp(bool is_browser_test) {
ASSERT_TRUE(FillFile(test_device_path_, kDevicePattern, kTestFileSize));
#if BUILDFLAG(IS_CHROMEOS_ASH)
- if (!chromeos::DBusThreadManager::IsInitialized()) {
- if (!is_browser_test) {
- // For browser tests, chromeos::InitializeDBus() automatically does the
- // same.
- chromeos::DBusThreadManager::Initialize();
- ash::ConciergeClient::InitializeFake(
- /*fake_cicerone_client=*/nullptr);
- }
- chromeos::DBusThreadManager::GetSetterForTesting()->SetImageBurnerClient(
- std::make_unique<ImageWriterFakeImageBurnerClient>());
+ // Browser tests might have already initialized ConciergeClient.
+ if (!ash::ConciergeClient::Get()) {
+ ash::ConciergeClient::InitializeFake(
+ /*fake_cicerone_client=*/nullptr);
+ concierge_client_initialized_ = true;
}
+ image_burner_client_ = std::make_unique<ImageWriterFakeImageBurnerClient>();
+ ash::ImageBurnerClient::SetInstanceForTest(image_burner_client_.get());
FakeDiskMountManager* disk_manager = new FakeDiskMountManager();
ash::disks::DiskMountManager::InitializeForTesting(disk_manager);
// Adds a disk entry for test_device_path_ with the same device and file path.
disk_manager->CreateDiskEntryForMountDevice(
- ash::disks::DiskMountManager::MountPointInfo(
- test_device_path_.value(), "/dummy/mount",
- chromeos::MOUNT_TYPE_DEVICE, ash::disks::MOUNT_CONDITION_NONE),
- "device_id", "device_label", "Vendor", "Product",
- chromeos::DEVICE_TYPE_USB, kTestFileSize, true, true, true, false,
- kTestFileSystemType);
+ {test_device_path_.value(), "/dummy/mount", ash::MountType::kDevice},
+ "device_id", "device_label", "Vendor", "Product", ash::DeviceType::kUSB,
+ kTestFileSize, true, true, true, false, kTestFileSystemType);
disk_manager->SetupDefaultReplies();
#else
ImageWriterUtilityClient::SetFactoryForTesting(&utility_client_factory_);
@@ -272,11 +257,12 @@ void ImageWriterTestUtils::SetUp(bool is_browser_test) {
void ImageWriterTestUtils::TearDown() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
- if (chromeos::DBusThreadManager::IsInitialized()) {
- // When in browser_tests, this path is not taken. These clients have already
- // been shut down by chromeos::ShutdownDBus().
+ ash::ImageBurnerClient::SetInstanceForTest(nullptr);
+ image_burner_client_.reset();
+
+ if (concierge_client_initialized_) {
ash::ConciergeClient::Shutdown();
- chromeos::DBusThreadManager::Shutdown();
+ concierge_client_initialized_ = false;
}
ash::disks::DiskMountManager::Shutdown();
#else
diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/test_utils.h b/chromium/chrome/browser/extensions/api/image_writer_private/test_utils.h
index 68970d4c5d6..1b5f57d1993 100644
--- a/chromium/chrome/browser/extensions/api/image_writer_private/test_utils.h
+++ b/chromium/chrome/browser/extensions/api/image_writer_private/test_utils.h
@@ -30,6 +30,10 @@
namespace extensions {
namespace image_writer {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+class ImageWriterFakeImageBurnerClient;
+#endif
+
const char kDummyExtensionId[] = "DummyExtension";
// Default file size to use in tests. Currently 32kB.
@@ -74,7 +78,7 @@ class FakeDiskMountManager : public ash::disks::MockDiskMountManager {
UnmountDeviceRecursivelyCallbackType callback) override;
private:
- DiskMap disks_;
+ Disks disks_;
};
#endif
@@ -166,14 +170,7 @@ class ImageWriterTestUtils {
const int length);
// Set up the test utils, creating temporary folders and such.
- // Note that browser tests should use the alternate form and pass "true" as an
- // argument.
virtual void SetUp();
- // Set up the test utils, creating temporary folders and such. If
- // |is_browser_test| is true then it will use alternate initialization
- // appropriate for a browser test. This should be run in
- // |SetUpInProcessBrowserTestFixture|.
- virtual void SetUp(bool is_browser_test);
virtual void TearDown();
@@ -186,7 +183,10 @@ class ImageWriterTestUtils {
base::FilePath test_image_path_;
base::FilePath test_device_path_;
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ std::unique_ptr<ImageWriterFakeImageBurnerClient> image_burner_client_;
+ bool concierge_client_initialized_ = false;
+#else
scoped_refptr<FakeImageWriterClient> client_;
ImageWriterUtilityClient::ImageWriterUtilityClientFactory
utility_client_factory_;
diff --git a/chromium/chrome/browser/extensions/api/input_ime/input_ime_api.cc b/chromium/chrome/browser/extensions/api/input_ime/input_ime_api.cc
index a2cebdc3fb0..0dfd5fb967a 100644
--- a/chromium/chrome/browser/extensions/api/input_ime/input_ime_api.cc
+++ b/chromium/chrome/browser/extensions/api/input_ime/input_ime_api.cc
@@ -164,8 +164,8 @@ ExtensionFunction::ResponseAction InputImeSetCompositionFunction::Run() {
if (!engine->SetComposition(params.context_id, params.text.c_str(),
selection_start, selection_end, params.cursor,
segments, &error)) {
- std::vector<base::Value> results;
- results.emplace_back(false);
+ base::Value::List results;
+ results.Append(false);
return RespondNow(ErrorWithArguments(
std::move(results), InformativeError(error, static_function_name())));
}
@@ -184,8 +184,8 @@ ExtensionFunction::ResponseAction InputImeCommitTextFunction::Run() {
const CommitText::Params::Parameters& params = parent_params->parameters;
if (!engine->CommitText(params.context_id, base::UTF8ToUTF16(params.text),
&error)) {
- std::vector<base::Value> results;
- results.emplace_back(false);
+ base::Value::List results;
+ results.Append(false);
return RespondNow(ErrorWithArguments(
std::move(results), InformativeError(error, static_function_name())));
}
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 df016838fa6..941d67ca173 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
@@ -291,8 +291,8 @@ class ImeObserverChromeOS
return;
}
// Note: this is a private API event.
- std::vector<base::Value> args;
- args.push_back(base::Value(is_projected));
+ base::Value::List args;
+ args.Append(is_projected);
DispatchEventToExtension(
extensions::events::INPUT_METHOD_PRIVATE_ON_SCREEN_PROJECTION_CHANGED,
@@ -412,7 +412,7 @@ class ImeObserverChromeOS
}
// Note: this is a private API event.
- std::vector<base::Value> bounds_list;
+ base::Value::List bounds_list;
bounds_list.reserve(bounds.size());
for (const auto& bound : bounds) {
base::Value bounds_value(base::Value::Type::DICTIONARY);
@@ -420,21 +420,40 @@ class ImeObserverChromeOS
bounds_value.SetIntKey("y", bound.y());
bounds_value.SetIntKey("w", bound.width());
bounds_value.SetIntKey("h", bound.height());
- bounds_list.push_back(std::move(bounds_value));
+ bounds_list.Append(std::move(bounds_value));
}
- std::vector<base::Value> args;
+ base::Value::List args;
// The old extension code uses the first parameter to get the bounds of the
// first composition character, so for backward compatibility, add it here.
- args.push_back(bounds_list[0].Clone());
- args.push_back(base::Value(std::move(bounds_list)));
+ args.Append(bounds_list[0].Clone());
+ args.Append(std::move(bounds_list));
DispatchEventToExtension(
extensions::events::INPUT_METHOD_PRIVATE_ON_COMPOSITION_BOUNDS_CHANGED,
OnCompositionBoundsChanged::kEventName, std::move(args));
}
+ void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) override {
+ if (extension_id_.empty() ||
+ !HasListener(input_method_private::OnCaretBoundsChanged::kEventName)) {
+ return;
+ }
+
+ // Note: this is a private API event;
+ input_method_private::OnCaretBoundsChanged::CaretBounds caret_bounds_arg;
+ caret_bounds_arg.x = caret_bounds.x();
+ caret_bounds_arg.y = caret_bounds.y();
+ caret_bounds_arg.w = caret_bounds.width();
+ caret_bounds_arg.h = caret_bounds.height();
+
+ DispatchEventToExtension(
+ extensions::events::INPUT_METHOD_PRIVATE_ON_CARET_BOUNDS_CHANGED,
+ input_method_private::OnCaretBoundsChanged::kEventName,
+ input_method_private::OnCaretBoundsChanged::Create(caret_bounds_arg));
+ }
+
void OnFocus(
const std::string& engine_id,
int context_id,
@@ -594,7 +613,7 @@ class ImeObserverChromeOS
void DispatchEventToExtension(
extensions::events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> args) {
+ base::Value::List args) {
if (event_name == input_ime::OnActivate::kEventName) {
// Send onActivate event regardless of it's listened by the IME.
auto event = std::make_unique<extensions::Event>(
@@ -984,8 +1003,8 @@ ExtensionFunction::ResponseAction InputImeClearCompositionFunction::Run() {
parent_params->parameters;
bool success = engine->ClearComposition(params.context_id, &error);
- std::vector<base::Value> results;
- results.emplace_back(success);
+ base::Value::List results;
+ results.Append(success);
return RespondNow(success
? ArgumentList(std::move(results))
: ErrorWithArguments(
@@ -1077,8 +1096,8 @@ InputImeSetCandidateWindowPropertiesFunction::Run() {
if (properties.visible &&
!engine->SetCandidateWindowVisible(*properties.visible, &error)) {
- std::vector<base::Value> results;
- results.emplace_back(false);
+ base::Value::List results;
+ results.Append(false);
return RespondNow(ErrorWithArguments(
std::move(results), InformativeError(error, static_function_name())));
}
@@ -1168,8 +1187,8 @@ ExtensionFunction::ResponseAction InputImeSetCandidatesFunction::Run() {
bool success =
engine->SetCandidates(params.context_id, candidates_out, &error);
- std::vector<base::Value> results;
- results.emplace_back(success);
+ base::Value::List results;
+ results.Append(success);
return RespondNow(success
? ArgumentList(std::move(results))
: ErrorWithArguments(
@@ -1192,8 +1211,8 @@ ExtensionFunction::ResponseAction InputImeSetCursorPositionFunction::Run() {
bool success =
engine->SetCursorPosition(params.context_id, params.candidate_id, &error);
- std::vector<base::Value> results;
- results.emplace_back(success);
+ base::Value::List results;
+ results.Append(success);
return RespondNow(success
? ArgumentList(std::move(results))
: ErrorWithArguments(
diff --git a/chromium/chrome/browser/extensions/api/language_settings_private/OWNERS b/chromium/chrome/browser/extensions/api/language_settings_private/OWNERS
index 2dbba8f0aab..443a569fed9 100644
--- a/chromium/chrome/browser/extensions/api/language_settings_private/OWNERS
+++ b/chromium/chrome/browser/extensions/api/language_settings_private/OWNERS
@@ -1,3 +1 @@
-michaelpg@chromium.org
-
file://chrome/browser/resources/settings/OWNERS
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 cac2da0309a..00869095b0e 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
@@ -81,7 +81,7 @@ base::flat_set<std::string> GetIMEsFromPref(PrefService* prefs,
// Returns the set of allowed UI locales.
base::flat_set<std::string> GetAllowedLanguages(PrefService* prefs) {
const auto& allowed_languages_values =
- prefs->GetList(prefs::kAllowedLanguages)->GetListDeprecated();
+ prefs->GetValueList(prefs::kAllowedLanguages);
return base::MakeFlatSet<std::string>(
allowed_languages_values, {},
[](const auto& locale_value) { return locale_value.GetString(); });
@@ -681,7 +681,6 @@ LanguageSettingsPrivateSetTranslateTargetLanguageFunction::Run() {
CreateTranslatePrefsForBrowserContext(browser_context());
std::string chrome_language = language_code;
- translate_prefs->AddToLanguageList(language_code, false);
if (language_code == translate_prefs->GetRecentTargetLanguage()) {
return RespondNow(NoArguments());
@@ -828,24 +827,22 @@ LanguageSettingsPrivateAddInputMethodFunction::Run() {
std::string input_methods = base::JoinString(input_method_list, ",");
prefs->SetString(pref_name, input_methods);
- // In LSV2 Update 2, we want to automatically enable "Show input options in
- // shelf" when the user has multiple input methods.
+ // We want to automatically enable "Show input options in shelf" when the user
+ // has multiple input methods.
// We don't want to repeatedly enable it every time the user adds an input
// method, as a user may want to intentionally turn it off - so we only enable
// it once the user reaches two input methods.
- if (base::FeatureList::IsEnabled(ash::features::kLanguageSettingsUpdate2)) {
- // As pref_name and input_method_set only refer to the preference related to
- // the list of IMEs for which this newly-added IME is in, we need the other
- // IME list to calculate the total number of IMEs.
- const char* other_ime_list_pref_name = is_component_extension_ime
- ? prefs::kLanguageEnabledImes
- : prefs::kLanguagePreloadEngines;
- base::flat_set<std::string> other_input_method_set(
- GetIMEsFromPref(prefs, other_ime_list_pref_name));
- if (input_method_set.size() + other_input_method_set.size() ==
- kNumImesToAutoEnableImeMenu) {
- prefs->SetBoolean(prefs::kLanguageImeMenuActivated, true);
- }
+ // As pref_name and input_method_set only refer to the preference related to
+ // the list of IMEs for which this newly-added IME is in, we need the other
+ // IME list to calculate the total number of IMEs.
+ const char* other_ime_list_pref_name = is_component_extension_ime
+ ? prefs::kLanguageEnabledImes
+ : prefs::kLanguagePreloadEngines;
+ base::flat_set<std::string> other_input_method_set(
+ GetIMEsFromPref(prefs, other_ime_list_pref_name));
+ if (input_method_set.size() + other_input_method_set.size() ==
+ kNumImesToAutoEnableImeMenu) {
+ prefs->SetBoolean(prefs::kLanguageImeMenuActivated, true);
}
#endif
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 8554cf307fa..328574de32f 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
@@ -9,7 +9,6 @@
#include "base/containers/contains.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
-#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -115,9 +114,6 @@ class LanguageSettingsPrivateApiTest : public ExtensionServiceTestBase {
// Force Windows hybrid spellcheck to be enabled.
feature_list_.InitAndEnableFeature(spellcheck::kWinUseBrowserSpellChecker);
#endif // BUILDFLAG(IS_WIN)
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- feature_list_.InitAndEnableFeature(ash::features::kLanguageSettingsUpdate2);
-#endif
}
#if BUILDFLAG(IS_WIN)
@@ -268,11 +264,6 @@ TEST_F(LanguageSettingsPrivateApiTest, SetTranslateTargetLanguageTest) {
api_test_utils::RunFunctionAndReturnSingleResult(function.get(),
"[\"af\"]", profile());
ASSERT_EQ(translate_prefs_->GetRecentTargetLanguage(), "af");
-
- std::vector<std::string> content_languages_after;
- translate_prefs_->GetLanguageList(&content_languages_after);
- ASSERT_EQ(std::vector<std::string>({"en-US", "en", "af"}),
- content_languages_after);
}
TEST_F(LanguageSettingsPrivateApiTest, GetNeverTranslateLanguagesListTest) {
@@ -306,7 +297,26 @@ TEST_F(LanguageSettingsPrivateApiTest, GetNeverTranslateLanguagesListTest) {
}
}
-TEST_F(LanguageSettingsPrivateApiTest, GetLanguageListTest) {
+class LanguageSettingsPrivateApiGetLanguageListTest
+ : public LanguageSettingsPrivateApiTest {
+ public:
+ LanguageSettingsPrivateApiGetLanguageListTest() = default;
+ ~LanguageSettingsPrivateApiGetLanguageListTest() override = default;
+
+ protected:
+ void InitFeatures() override {
+#if BUILDFLAG(IS_WIN)
+ // Force Windows hybrid spellcheck to be enabled, and disable the delayed
+ // init feature since that case is tested in
+ // LanguageSettingsPrivateApiTestDelayInit below.
+ feature_list_.InitWithFeatures(
+ /*enabled_features=*/{spellcheck::kWinUseBrowserSpellChecker},
+ /*disabled_features=*/{spellcheck::kWinDelaySpellcheckServiceInit});
+#endif // BUILDFLAG(IS_WIN)
+ }
+};
+
+TEST_F(LanguageSettingsPrivateApiGetLanguageListTest, GetLanguageList) {
translate::TranslateDownloadManager::GetInstance()->ResetForTesting();
RunGetLanguageListTest();
}
@@ -565,9 +575,8 @@ TEST_F(LanguageSettingsPrivateApiTest, GetInputMethodListsTest) {
input_method.FindListKey("languageCodes");
ASSERT_NE(nullptr, ime_language_codes_ptr);
for (auto& language_code : ime_language_codes_ptr->GetListDeprecated()) {
- std::string language_display_name =
- base::UTF16ToUTF8(l10n_util::GetDisplayNameForLocale(
- language_code.GetString(), "en", true));
+ std::u16string language_display_name = l10n_util::GetDisplayNameForLocale(
+ language_code.GetString(), "en", true);
if (!language_display_name.empty())
EXPECT_TRUE(base::Contains(ime_tags_ptr->GetListDeprecated(),
base::Value(language_display_name)));
diff --git a/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.cc b/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.cc
index dd00dbc5a47..1ca82052423 100644
--- a/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.cc
+++ b/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.cc
@@ -6,7 +6,6 @@
#include "chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.h"
#include "chrome/browser/spellchecker/spellcheck_factory.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/extension_system_provider.h"
#include "extensions/browser/extensions_browser_client.h"
@@ -28,9 +27,9 @@ LanguageSettingsPrivateDelegateFactory::GetInstance() {
}
LanguageSettingsPrivateDelegateFactory::LanguageSettingsPrivateDelegateFactory()
- : BrowserContextKeyedServiceFactory(
+ : ProfileKeyedServiceFactory(
"LanguageSettingsPrivateDelegate",
- BrowserContextDependencyManager::GetInstance()) {
+ ProfileSelections::BuildRedirectedInIncognito()) {
DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
DependsOn(SpellcheckServiceFactory::GetInstance());
}
@@ -44,12 +43,6 @@ KeyedService* LanguageSettingsPrivateDelegateFactory::BuildServiceInstanceFor(
return LanguageSettingsPrivateDelegate::Create(context);
}
-content::BrowserContext*
-LanguageSettingsPrivateDelegateFactory::GetBrowserContextToUse(
- content::BrowserContext* context) const {
- return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
-}
-
bool LanguageSettingsPrivateDelegateFactory::
ServiceIsCreatedWithBrowserContext() const {
return true;
diff --git a/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.h b/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.h
index 4375dbac6aa..5ca0aae9ab1 100644
--- a/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.h
+++ b/chromium/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_factory.h
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_EXTENSIONS_API_LANGUAGE_SETTINGS_PRIVATE_LANGUAGE_SETTINGS_PRIVATE_DELEGATE_FACTORY_H_
#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
namespace extensions {
@@ -17,7 +17,7 @@ class LanguageSettingsPrivateDelegate;
// (since the extension event router and language preferences are per browsing
// context).
class LanguageSettingsPrivateDelegateFactory
- : public BrowserContextKeyedServiceFactory {
+ : public ProfileKeyedServiceFactory {
public:
LanguageSettingsPrivateDelegateFactory(
const LanguageSettingsPrivateDelegateFactory&) = delete;
@@ -34,8 +34,6 @@ class LanguageSettingsPrivateDelegateFactory
protected:
// BrowserContextKeyedServiceFactory overrides:
- content::BrowserContext* GetBrowserContextToUse(
- content::BrowserContext* context) const override;
bool ServiceIsCreatedWithBrowserContext() const override;
private:
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 238ec361dc6..fffbced3a2e 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
@@ -47,6 +47,7 @@
#include "chrome/common/extensions/extension_metrics.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "components/favicon/core/favicon_service.h"
+#include "components/services/app_service/public/cpp/app_launch_util.h"
#include "components/webapps/browser/install_result_code.h"
#include "components/webapps/browser/installable/installable_manager.h"
#include "components/webapps/browser/installable/installable_metrics.h"
@@ -71,7 +72,6 @@
#include "chrome/browser/ash/arc/arc_util.h"
#include "chrome/browser/ash/login/demo_mode/demo_session.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
-#include "chrome/browser/web_applications/web_app_utils.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
@@ -336,6 +336,7 @@ class ChromeAppForLinkDelegate : public extensions::AppForLinkDelegate {
// These modes are not supported by the extension app backend.
case web_app::DisplayMode::kWindowControlsOverlay:
case web_app::DisplayMode::kTabbed:
+ case web_app::DisplayMode::kBorderless:
case web_app::DisplayMode::kUndefined:
info.launch_type = extensions::api::management::LAUNCH_TYPE_NONE;
break;
@@ -357,9 +358,9 @@ void LaunchWebApp(const web_app::AppId& app_id, Profile* profile) {
DCHECK(provider);
absl::optional<web_app::UserDisplayMode> display_mode =
provider->registrar().GetAppUserDisplayMode(app_id);
- auto launch_container = apps::mojom::LaunchContainer::kLaunchContainerWindow;
+ auto launch_container = apps::LaunchContainer::kLaunchContainerWindow;
if (display_mode == web_app::UserDisplayMode::kBrowser)
- launch_container = apps::mojom::LaunchContainer::kLaunchContainerTab;
+ launch_container = apps::LaunchContainer::kLaunchContainerTab;
if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) {
// If the profile doesn't have an App Service Proxy available, that means
@@ -372,7 +373,7 @@ void LaunchWebApp(const web_app::AppId& app_id, Profile* profile) {
apps::AppServiceProxyFactory::GetForProfile(profile)->LaunchAppWithParams(
apps::AppLaunchParams(app_id, launch_container,
WindowOpenDisposition::NEW_FOREGROUND_TAB,
- apps::mojom::LaunchSource::kFromManagementApi));
+ apps::LaunchSource::kFromManagementApi));
}
void OnWebAppInstallCompleted(InstallOrLaunchWebAppCallback callback,
@@ -429,7 +430,7 @@ void ChromeManagementAPIDelegate::LaunchAppFunctionDelegate(
// returned.
// TODO(crbug.com/1003602): Make AppLaunchParams launch container Optional or
// add a "default" launch container enum value.
- apps::mojom::LaunchContainer launch_container =
+ apps::LaunchContainer launch_container =
GetLaunchContainer(extensions::ExtensionPrefs::Get(context), extension);
Profile* profile = Profile::FromBrowserContext(context);
if (!apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) {
@@ -442,7 +443,7 @@ void ChromeManagementAPIDelegate::LaunchAppFunctionDelegate(
apps::AppServiceProxyFactory::GetForProfile(profile)->LaunchAppWithParams(
apps::AppLaunchParams(extension->id(), launch_container,
WindowOpenDisposition::NEW_FOREGROUND_TAB,
- apps::mojom::LaunchSource::kFromManagementApi));
+ apps::LaunchSource::kFromManagementApi));
#if BUILDFLAG(IS_CHROMEOS_ASH)
ash::DemoSession::RecordAppLaunchSourceIfInDemoMode(
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 c4fd49636b4..80e3d0b81e1 100644
--- a/chromium/chrome/browser/extensions/api/management/management_api_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/management/management_api_browsertest.cc
@@ -206,8 +206,15 @@ IN_PROC_BROWSER_TEST_P(ExtensionManagementApiTestWithBackgroundType,
ASSERT_TRUE(listener2.WaitUntilSatisfied());
}
+#if BUILDFLAG(IS_MAC)
+// Flaky on Mac: https://crbug.com/1132581
+#define MAYBE_SelfUninstallNoPermissions DISABLED_SelfUninstallNoPermissions
+#else
+#define MAYBE_SelfUninstallNoPermissions SelfUninstallNoPermissions
+#endif
+
IN_PROC_BROWSER_TEST_P(ExtensionManagementApiTestWithBackgroundType,
- SelfUninstallNoPermissions) {
+ MAYBE_SelfUninstallNoPermissions) {
// Wait for the helper script to finish before loading the primary
// extension. This ensures that the onUninstall event listener is
// added before we proceed to the uninstall step.
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 884e760e2c2..f7078e29359 100644
--- a/chromium/chrome/browser/extensions/api/management/management_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/management/management_api_unittest.cc
@@ -47,8 +47,6 @@
#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
#include "chrome/browser/supervised_user/supervised_user_test_util.h"
#include "content/public/browser/gpu_data_manager.h"
-#include "extensions/browser/api/management/management_api_constants.h"
-#include "extensions/common/error_utils.h"
#endif
using extensions::mojom::ManifestLocation;
@@ -389,7 +387,7 @@ TEST_F(ManagementApiUnitTest, ManagementUninstall) {
// If we try uninstall the extension itself, the uninstall should succeed
// (even though we auto-cancel any dialog), because the dialog is never
// shown.
- uninstall_args.EraseListIter(uninstall_args.GetListDeprecated().begin());
+ uninstall_args.GetList().erase(uninstall_args.GetList().begin());
function = new ManagementUninstallSelfFunction();
function->set_extension(extension);
EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
diff --git a/chromium/chrome/browser/extensions/api/mdns/OWNERS b/chromium/chrome/browser/extensions/api/mdns/OWNERS
index 2acc4e2a670..76567a3f634 100644
--- a/chromium/chrome/browser/extensions/api/mdns/OWNERS
+++ b/chromium/chrome/browser/extensions/api/mdns/OWNERS
@@ -1,2 +1,4 @@
mfoltz@chromium.org
-vitalybuka@chromium.org
+takumif@chromium.org
+
+
diff --git a/chromium/chrome/browser/extensions/api/mdns/mdns_api.cc b/chromium/chrome/browser/extensions/api/mdns/mdns_api.cc
index 41723381457..9df689413d2 100644
--- a/chromium/chrome/browser/extensions/api/mdns/mdns_api.cc
+++ b/chromium/chrome/browser/extensions/api/mdns/mdns_api.cc
@@ -10,12 +10,14 @@
#include "base/lazy_instance.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "components/version_info/channel.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_registry.h"
+#include "extensions/common/features/feature_channel.h"
#include "extensions/common/mojom/event_dispatcher.mojom.h"
namespace extensions {
@@ -198,8 +200,14 @@ bool MDnsAPI::IsMDnsAllowed(const std::string& extension_id,
ExtensionRegistry::Get(browser_context_)
->enabled_extensions()
.GetByID(extension_id);
- return (extension && (extension->is_platform_app() ||
- IsServiceTypeAllowlisted(service_type)));
+ if (!extension)
+ return false;
+
+ if (GetCurrentChannel() == version_info::Channel::DEV &&
+ extension->is_extension()) {
+ return true;
+ }
+ return extension->is_platform_app() || IsServiceTypeAllowlisted(service_type);
}
void MDnsAPI::GetValidOnServiceListListeners(
diff --git a/chromium/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc b/chromium/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
index ede617b1402..294015158c8 100644
--- a/chromium/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
@@ -25,6 +25,7 @@
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension_messages.h"
+#include "extensions/common/features/feature_channel.h"
#include "extensions/common/manifest_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -122,18 +123,14 @@ class EventServiceListSizeMatcher
virtual bool MatchAndExplain(const Event& e,
testing::MatchResultListener* listener) const {
- if (!e.event_args) {
- *listener << "event.event_arg is null when it shouldn't be";
- return false;
- }
- if (e.event_args->GetListDeprecated().size() != 1) {
+ if (e.event_args.size() != 1) {
*listener << "event.event_arg.GetSize() should be 1 but is "
- << e.event_args->GetListDeprecated().size();
+ << e.event_args.size();
return false;
}
const base::ListValue* services = nullptr;
{
- const base::Value& out = e.event_args->GetListDeprecated()[0];
+ const base::Value& out = e.event_args[0];
services = static_cast<const base::ListValue*>(&out);
}
if (!services) {
@@ -269,6 +266,10 @@ class MDnsAPIDiscoveryTest : public MDnsAPITest {
raw_ptr<MockedMDnsAPI> mdns_api_;
};
+class MDnsAPIExtensionTest
+ : public MDnsAPITest,
+ public testing::WithParamInterface<version_info::Channel> {};
+
TEST_F(MDnsAPIDiscoveryTest, ServiceListenersAddedAndRemoved) {
EventRouterFactory::GetInstance()->SetTestingFactory(
browser_context(), base::BindRepeating(&MockEventRouterFactoryFunction));
@@ -344,7 +345,10 @@ TEST_F(MDnsAPIMaxServicesTest, OnServiceListDoesNotExceedLimit) {
dns_sd_registry()->DispatchMDnsEvent("_testing._tcp.local", services);
}
-TEST_F(MDnsAPITest, ExtensionRespectsAllowlist) {
+TEST_P(MDnsAPIExtensionTest, ExtensionRespectsAllowlist) {
+ const bool is_dev = GetParam() == version_info::Channel::DEV;
+ extensions::ScopedCurrentChannel channel_override(GetParam());
+
scoped_refptr<extensions::Extension> extension =
CreateExtension("Dinosaur networker", false, kExtId);
ExtensionRegistry::Get(browser_context())->AddEnabled(extension);
@@ -358,16 +362,17 @@ TEST_F(MDnsAPITest, ExtensionRespectsAllowlist) {
filter.SetStringKey(kEventFilterServiceTypeKey, "_trex._tcp.local");
ASSERT_TRUE(dns_sd_registry());
- // Test that the extension is able to listen to a non-allowlisted service
+ // Test that the extension is not able to listen to a non-allowlisted
+ // service, unless we are on dev channel.
EXPECT_CALL(*dns_sd_registry(), RegisterDnsSdListener("_trex._tcp.local"))
- .Times(0);
+ .Times(is_dev ? 1 : 0);
EventRouter::Get(browser_context())
->AddFilteredEventListener(api::mdns::OnServiceList::kEventName,
render_process_host(), param.Clone(),
absl::nullopt, filter, false);
EXPECT_CALL(*dns_sd_registry(), UnregisterDnsSdListener("_trex._tcp.local"))
- .Times(0);
+ .Times(is_dev ? 1 : 0);
EventRouter::Get(browser_context())
->RemoveFilteredEventListener(api::mdns::OnServiceList::kEventName,
render_process_host(), param.Clone(),
@@ -395,6 +400,11 @@ TEST_F(MDnsAPITest, ExtensionRespectsAllowlist) {
}
}
+INSTANTIATE_TEST_SUITE_P(Channels,
+ MDnsAPIExtensionTest,
+ testing::Values(version_info::Channel::DEV,
+ version_info::Channel::STABLE));
+
TEST_F(MDnsAPITest, PlatformAppsNotSubjectToAllowlist) {
scoped_refptr<extensions::Extension> extension =
CreateExtension("Dinosaur networker", true, kExtId);
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 1eecb573415..b7df0906aa7 100644
--- a/chromium/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc
+++ b/chromium/chrome/browser/extensions/api/messaging/chrome_messaging_delegate.cc
@@ -51,25 +51,23 @@ ChromeMessagingDelegate::IsNativeMessagingHostAllowed(
// All native messaging hosts are allowed if there is no blocklist.
if (!pref_service->IsManagedPreference(pref_names::kNativeMessagingBlocklist))
return allow_result;
- const base::Value* blocklist =
- pref_service->GetList(pref_names::kNativeMessagingBlocklist);
- if (!blocklist)
- return allow_result;
+ const base::Value::List& blocklist =
+ pref_service->GetValueList(pref_names::kNativeMessagingBlocklist);
// Check if the name or the wildcard is in the blocklist.
base::Value name_value(native_host_name);
base::Value wildcard_value("*");
- if (!base::Contains(blocklist->GetListDeprecated(), name_value) &&
- !base::Contains(blocklist->GetListDeprecated(), wildcard_value)) {
+ if (!base::Contains(blocklist, name_value) &&
+ !base::Contains(blocklist, wildcard_value)) {
return allow_result;
}
// The native messaging host is blocklisted. Check the allowlist.
if (pref_service->IsManagedPreference(
pref_names::kNativeMessagingAllowlist)) {
- const base::Value* allowlist =
- pref_service->GetList(pref_names::kNativeMessagingAllowlist);
- if (allowlist && base::Contains(allowlist->GetListDeprecated(), name_value))
+ const base::Value::List& allowlist =
+ pref_service->GetValueList(pref_names::kNativeMessagingAllowlist);
+ if (base::Contains(allowlist, name_value))
return allow_result;
}
diff --git a/chromium/chrome/browser/extensions/api/messaging/messaging_apitest.cc b/chromium/chrome/browser/extensions/api/messaging/messaging_apitest.cc
index 1edf30fbc9b..18ca5936d38 100644
--- a/chromium/chrome/browser/extensions/api/messaging/messaging_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/messaging/messaging_apitest.cc
@@ -94,7 +94,7 @@ class MessageSender : public ExtensionHostRegistry::Observer {
GURL event_url) {
auto event = std::make_unique<Event>(
events::TEST_ON_MESSAGE, "test.onMessage",
- std::move(*event_args).TakeListDeprecated(), browser_context);
+ std::move(event_args->GetList()), browser_context);
event->event_url = std::move(event_url);
return event;
}
diff --git a/chromium/chrome/browser/extensions/api/messaging/native_message_echo_host.h b/chromium/chrome/browser/extensions/api/messaging/native_message_echo_host.h
index cb2ca90042f..510b3f8614e 100644
--- a/chromium/chrome/browser/extensions/api/messaging/native_message_echo_host.h
+++ b/chromium/chrome/browser/extensions/api/messaging/native_message_echo_host.h
@@ -8,6 +8,7 @@
#include <memory>
#include <string>
+#include "base/memory/raw_ptr.h"
#include "extensions/browser/api/messaging/native_message_host.h"
namespace base {
@@ -52,7 +53,7 @@ class NativeMessageEchoHost : public NativeMessageHost {
int message_number_ = 0;
// |client_| must outlive this test instance.
- Client* client_ = nullptr;
+ raw_ptr<Client> client_ = nullptr;
};
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc b/chromium/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
index fd8c618f857..10915088628 100644
--- a/chromium/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/messaging/native_message_process_host_unittest.cc
@@ -288,25 +288,36 @@ TEST_F(NativeMessagingTest, EchoConnect) {
run_loop_->Run();
ASSERT_FALSE(last_message_.empty());
ASSERT_TRUE(last_message_parsed_);
+ ASSERT_TRUE(last_message_parsed_->is_dict());
std::string expected_url = std::string("chrome-extension://") +
- ScopedTestNativeMessagingHost::kExtensionId + "/";
- EXPECT_EQ(1, last_message_parsed_->FindIntKey("id"));
- std::string text;
- EXPECT_TRUE(last_message_parsed_->GetString("echo.text", &text));
- EXPECT_EQ("Hello.", text);
- std::string url;
- EXPECT_TRUE(last_message_parsed_->GetString("caller_url", &url));
- EXPECT_EQ(expected_url, url);
+ ScopedTestNativeMessagingHost::kExtensionId + "/";
+
+ {
+ const base::Value::Dict& dict = last_message_parsed_->GetDict();
+ EXPECT_EQ(1, last_message_parsed_->FindIntKey("id"));
+ const std::string* text = dict.FindStringByDottedPath("echo.text");
+ ASSERT_TRUE(text);
+ EXPECT_EQ("Hello.", *text);
+ const std::string* url = dict.FindString("caller_url");
+ EXPECT_TRUE(url);
+ EXPECT_EQ(expected_url, *url);
+ }
native_message_host_->OnMessage("{\"foo\": \"bar\"}");
run_loop_ = std::make_unique<base::RunLoop>();
run_loop_->Run();
- EXPECT_EQ(2, last_message_parsed_->FindIntKey("id"));
- EXPECT_TRUE(last_message_parsed_->GetString("echo.foo", &text));
- EXPECT_EQ("bar", text);
- EXPECT_TRUE(last_message_parsed_->GetString("caller_url", &url));
- EXPECT_EQ(expected_url, url);
+
+ {
+ const base::Value::Dict& dict = last_message_parsed_->GetDict();
+ EXPECT_EQ(2, last_message_parsed_->FindIntKey("id"));
+ const std::string* text = dict.FindStringByDottedPath("echo.foo");
+ ASSERT_TRUE(text);
+ EXPECT_EQ("bar", *text);
+ const std::string* url = dict.FindString("caller_url");
+ ASSERT_TRUE(url);
+ EXPECT_EQ(expected_url, *url);
+ }
const base::Value* args = nullptr;
ASSERT_TRUE(last_message_parsed_->Get("args", &args));
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 6879c4bbe3d..3b99eb71ad2 100644
--- a/chromium/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
@@ -73,8 +73,8 @@ class NativeMessagingApiTest : public NativeMessagingApiTestBase,
bool RunTest(const char* extension_name) {
if (GetParam() == ContextType::kPersistentBackground)
return RunExtensionTest(extension_name);
- std::string lazy_exension_name = base::StrCat({extension_name, "/lazy"});
- return RunExtensionTest(lazy_exension_name.c_str());
+ std::string lazy_extension_name = base::StrCat({extension_name, "/lazy"});
+ return RunExtensionTest(lazy_extension_name.c_str());
}
};
diff --git a/chromium/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.cc b/chromium/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.cc
index 009851133bb..88480bd90a0 100644
--- a/chromium/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.cc
+++ b/chromium/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.cc
@@ -9,7 +9,6 @@
#include "base/check.h"
#include "base/json/json_file_value_serializer.h"
#include "base/strings/string_util.h"
-#include "base/values.h"
#include "chrome/common/chrome_features.h"
namespace extensions {
@@ -54,15 +53,15 @@ std::unique_ptr<NativeMessagingHostManifest> NativeMessagingHostManifest::Load(
return nullptr;
}
- base::DictionaryValue* dictionary;
- if (!parsed->GetAsDictionary(&dictionary)) {
+ if (!parsed->is_dict()) {
*error_message = "Invalid manifest file.";
return nullptr;
}
+ const base::Value::Dict& dict = parsed->GetDict();
std::unique_ptr<NativeMessagingHostManifest> result(
new NativeMessagingHostManifest());
- if (!result->Parse(dictionary, error_message)) {
+ if (!result->Parse(dict, error_message)) {
return nullptr;
}
@@ -72,45 +71,46 @@ std::unique_ptr<NativeMessagingHostManifest> NativeMessagingHostManifest::Load(
NativeMessagingHostManifest::NativeMessagingHostManifest() {
}
-bool NativeMessagingHostManifest::Parse(base::DictionaryValue* dictionary,
+bool NativeMessagingHostManifest::Parse(const base::Value::Dict& dict,
std::string* error_message) {
- if (!dictionary->GetString("name", &name_) ||
- !IsValidName(name_)) {
+ const std::string* name_str = dict.FindString("name");
+ if (!name_str || !IsValidName(*name_str)) {
*error_message = "Invalid value for name.";
return false;
}
+ name_ = *name_str;
- if (!dictionary->GetString("description", &description_) ||
- description_.empty()) {
+ const std::string* desc_str = dict.FindString("description");
+ if (!desc_str || desc_str->empty()) {
*error_message = "Invalid value for description.";
return false;
}
+ description_ = *desc_str;
- std::string type;
+ const std::string* type = dict.FindString("type");
// stdio is the only host type that's currently supported.
- if (!dictionary->GetString("type", &type) ||
- type != "stdio") {
+ if (!type || *type != "stdio") {
*error_message = "Invalid value for type.";
return false;
}
interface_ = HOST_INTERFACE_STDIO;
- std::string path;
+ const std::string* path = dict.FindString("path");
// JSON parsed checks that all strings are valid UTF8.
- if (!dictionary->GetString("path", &path) ||
- (path_ = base::FilePath::FromUTF8Unsafe(path)).empty()) {
+ if (!path || (path_ = base::FilePath::FromUTF8Unsafe(*path)).empty()) {
*error_message = "Invalid value for path.";
return false;
}
- const base::ListValue* allowed_origins_list;
- if (!dictionary->GetList("allowed_origins", &allowed_origins_list)) {
+ const base::Value::List* allowed_origins_list =
+ dict.FindList("allowed_origins");
+ if (!allowed_origins_list) {
*error_message =
"Invalid value for allowed_origins. Expected a list of strings.";
return false;
}
allowed_origins_.ClearPatterns();
- for (const auto& entry : allowed_origins_list->GetListDeprecated()) {
+ for (const auto& entry : *allowed_origins_list) {
if (!entry.is_string()) {
*error_message = "allowed_origins must be list of strings.";
return false;
@@ -136,7 +136,7 @@ bool NativeMessagingHostManifest::Parse(base::DictionaryValue* dictionary,
if (base::FeatureList::IsEnabled(features::kOnConnectNative)) {
if (const base::Value* supports_native_initiated_connections =
- dictionary->FindKey("supports_native_initiated_connections")) {
+ dict.Find("supports_native_initiated_connections")) {
if (!supports_native_initiated_connections->is_bool()) {
*error_message =
"supports_native_initiated_connections must be a boolean.";
diff --git a/chromium/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h b/chromium/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h
index 942db33460c..b2e90e82f5c 100644
--- a/chromium/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h
+++ b/chromium/chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h
@@ -9,12 +9,9 @@
#include <string>
#include "base/files/file_path.h"
+#include "base/values.h"
#include "extensions/common/url_pattern_set.h"
-namespace base {
-class DictionaryValue;
-}
-
namespace extensions {
class NativeMessagingHostManifest {
@@ -52,7 +49,7 @@ class NativeMessagingHostManifest {
// Parses manifest |dictionary|. In case of an error sets |error_message| and
// returns false.
- bool Parse(base::DictionaryValue* dictionary, std::string* error_message);
+ bool Parse(const base::Value::Dict& dict, std::string* error_message);
std::string name_;
std::string description_;
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 44907c969aa..003fdeb61b0 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
@@ -5,8 +5,6 @@
#include <memory>
#include <utility>
-#include "ash/components/cryptohome/cryptohome_parameters.h"
-#include "ash/constants/ash_switches.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
@@ -20,23 +18,6 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.h"
#include "chrome/browser/extensions/extension_apitest.h"
-#include "chromeos/ash/components/network/onc/network_onc_utils.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/shill/shill_device_client.h"
-#include "chromeos/dbus/shill/shill_ipconfig_client.h"
-#include "chromeos/dbus/shill/shill_manager_client.h"
-#include "chromeos/dbus/shill/shill_profile_client.h"
-#include "chromeos/dbus/shill/shill_service_client.h"
-#include "chromeos/dbus/userdataauth/cryptohome_misc_client.h"
-#include "chromeos/dbus/userdataauth/userdataauth_client.h"
-#include "chromeos/network/cellular_metrics_logger.h"
-#include "chromeos/network/managed_network_configuration_handler.h"
-#include "chromeos/network/network_certificate_handler.h"
-#include "chromeos/network/network_handler.h"
-#include "chromeos/network/network_handler_test_helper.h"
-#include "chromeos/network/network_state.h"
-#include "chromeos/network/network_state_handler.h"
-#include "chromeos/network/network_type_pattern.h"
#include "components/onc/onc_constants.h"
#include "components/onc/onc_pref_names.h"
#include "components/policy/core/browser/browser_policy_connector.h"
@@ -55,16 +36,44 @@
#include "components/user_manager/user_names.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_utils.h"
-#include "dbus/object_path.h"
#include "extensions/browser/api/networking_private/networking_private_chromeos.h"
#include "extensions/browser/api/networking_private/networking_private_delegate_factory.h"
#include "extensions/common/switches.h"
#include "extensions/common/value_builder.h"
#include "extensions/test/extension_test_message_listener.h"
#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/constants/ash_switches.h"
+#include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
+#include "chromeos/ash/components/dbus/dbus_thread_manager.h"
+#include "chromeos/ash/components/dbus/shill/shill_device_client.h"
+#include "chromeos/ash/components/dbus/shill/shill_ipconfig_client.h"
+#include "chromeos/ash/components/dbus/shill/shill_manager_client.h"
+#include "chromeos/ash/components/dbus/shill/shill_profile_client.h"
+#include "chromeos/ash/components/dbus/shill/shill_service_client.h"
+#include "chromeos/ash/components/dbus/userdataauth/cryptohome_misc_client.h"
+#include "chromeos/ash/components/dbus/userdataauth/userdataauth_client.h"
+#include "chromeos/ash/components/network/cellular_metrics_logger.h"
+#include "chromeos/ash/components/network/managed_network_configuration_handler.h"
+#include "chromeos/ash/components/network/network_certificate_handler.h"
+#include "chromeos/ash/components/network/network_handler.h"
+#include "chromeos/ash/components/network/network_handler_test_helper.h"
+#include "chromeos/ash/components/network/network_state.h"
+#include "chromeos/ash/components/network/network_state_handler.h"
+#include "chromeos/ash/components/network/network_type_pattern.h"
+#include "chromeos/ash/components/network/onc/network_onc_utils.h"
+#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
// (NetworkingPrivateChromeOS). Note: The test expectations for chromeos, and
// win/mac (NetworkingPrivateServiceClient) are different to reflect the
@@ -73,29 +82,224 @@
using testing::Return;
using testing::_;
-using chromeos::ShillDeviceClient;
-using chromeos::ShillIPConfigClient;
-using chromeos::ShillManagerClient;
-using chromeos::ShillProfileClient;
-using chromeos::ShillServiceClient;
-using chromeos::UserDataAuthClient;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+using ash::ShillDeviceClient;
+using ash::ShillIPConfigClient;
+using ash::ShillManagerClient;
+using ash::ShillProfileClient;
+using ash::ShillServiceClient;
+using ash::UserDataAuthClient;
using extensions::NetworkingPrivateDelegate;
using extensions::NetworkingPrivateDelegateFactory;
using extensions::NetworkingPrivateChromeOS;
+#endif
namespace {
-const char kUser1ProfilePath[] = "/profile/user1/shill";
-const char kEthernetDevicePath[] = "/device/stub_ethernet_device";
-const char kWifiDevicePath[] = "/device/stub_wifi_device1";
+const char kCellular1ServicePath[] = "stub_cellular1";
const char kCellularDevicePath[] = "/device/stub_cellular_device1";
+const char kEthernetDevicePath[] = "/device/stub_ethernet_device";
const char kIPConfigPath[] = "/ipconfig/ipconfig1";
-
+const char kUser1ProfilePath[] = "/profile/user1/shill";
const char kWifi1ServicePath[] = "stub_wifi1";
const char kWifi2ServicePath[] = "stub_wifi2";
-const char kCellular1ServicePath[] = "stub_cellular1";
+const char kWifiDevicePath[] = "/device/stub_wifi_device1";
+
+class NetworkingPrivateChromeOSApiTestBase
+ : public extensions::ExtensionApiTest {
+ public:
+ // From extensions::ExtensionApiTest
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ extensions::ExtensionApiTest::SetUpCommandLine(command_line);
+ // Allowlist the extension ID of the test extension.
+ command_line->AppendSwitchASCII(
+ extensions::switches::kAllowlistedExtensionID,
+ "epcifkihnkjgphfkloaaleeakhpmgdmn");
+ }
+
+ bool RunNetworkingSubtest(const std::string& test) {
+ const std::string arg =
+ base::StringPrintf("{\"test\": \"%s\"}", test.c_str());
+ return RunExtensionTest(
+ "networking_private/chromeos",
+ {.custom_arg = arg.c_str(), .launch_as_platform_app = true});
+ }
+
+ void ConfigFakeNetwork() {
+ ClearDevices();
+ ClearServices();
+
+ std::string userhash = GetSanitizedActiveUsername();
+
+ // Sends a notification about the added profile.
+ AddProfile(kUser1ProfilePath, userhash);
+
+ // Add IPConfigs
+ base::DictionaryValue ipconfig;
+ ipconfig.SetKey(shill::kAddressProperty, base::Value("0.0.0.0"));
+ ipconfig.SetKey(shill::kGatewayProperty, base::Value("0.0.0.1"));
+ ipconfig.SetKey(shill::kPrefixlenProperty, base::Value(0));
+ ipconfig.SetKey(shill::kMethodProperty, base::Value(shill::kTypeIPv4));
+ AddIPConfig(kIPConfigPath, ipconfig);
+
+ // Add Devices
+ AddDevice(kEthernetDevicePath, shill::kTypeEthernet,
+ "stub_ethernet_device1");
+
+ AddDevice(kWifiDevicePath, shill::kTypeWifi, "stub_wifi_device1");
+ base::ListValue wifi_ip_configs;
+ wifi_ip_configs.Append(kIPConfigPath);
+ SetDeviceProperty(kWifiDevicePath, shill::kIPConfigsProperty,
+ wifi_ip_configs);
+ SetDeviceProperty(kWifiDevicePath, shill::kAddressProperty,
+ base::Value("001122aabbcc"));
+
+ // Add Services
+ AddService("stub_ethernet", "eth0", shill::kTypeEthernet,
+ shill::kStateOnline);
+ SetServiceProperty("stub_ethernet", shill::kProfileProperty,
+ base::Value(GetSharedProfilePath()));
+ AddServiceToProfile(GetSharedProfilePath(), "stub_ethernet");
+ AddService(kWifi1ServicePath, "wifi1", shill::kTypeWifi,
+ shill::kStateOnline);
+ SetServiceProperty(kWifi1ServicePath, shill::kSecurityClassProperty,
+ base::Value(shill::kSecurityClassWep));
+ SetServiceProperty(kWifi1ServicePath, shill::kWifiBSsid,
+ base::Value("00:01:02:03:04:05"));
+ SetServiceProperty(kWifi1ServicePath, shill::kSignalStrengthProperty,
+ base::Value(40));
+ SetServiceProperty(kWifi1ServicePath, shill::kProfileProperty,
+ base::Value(kUser1ProfilePath));
+ SetServiceProperty(kWifi1ServicePath, shill::kConnectableProperty,
+ base::Value(true));
+ SetServiceProperty(kWifi1ServicePath, shill::kDeviceProperty,
+ base::Value(kWifiDevicePath));
+ base::DictionaryValue static_ipconfig;
+ static_ipconfig.SetKey(shill::kAddressProperty, base::Value("1.2.3.4"));
+ static_ipconfig.SetKey(shill::kGatewayProperty, base::Value("0.0.0.0"));
+ static_ipconfig.SetKey(shill::kPrefixlenProperty, base::Value(1));
+ SetServiceProperty(kWifi1ServicePath, shill::kStaticIPConfigProperty,
+ static_ipconfig);
+ base::ListValue frequencies1;
+ frequencies1.Append(2400);
+ SetServiceProperty(kWifi1ServicePath, shill::kWifiFrequencyListProperty,
+ frequencies1);
+ SetServiceProperty(kWifi1ServicePath, shill::kWifiFrequency,
+ base::Value(2400));
+ AddServiceToProfile(kUser1ProfilePath, kWifi1ServicePath);
+
+ AddService(kWifi2ServicePath, "wifi2_PSK", shill::kTypeWifi,
+ shill::kStateIdle);
+ SetServiceProperty(kWifi2ServicePath, shill::kSecurityClassProperty,
+ base::Value(shill::kSecurityClassPsk));
+ SetServiceProperty(kWifi2ServicePath, shill::kSignalStrengthProperty,
+ base::Value(80));
+ SetServiceProperty(kWifi2ServicePath, shill::kConnectableProperty,
+ base::Value(true));
+
+ base::ListValue frequencies2;
+ frequencies2.Append(2400);
+ frequencies2.Append(5000);
+ SetServiceProperty(kWifi2ServicePath, shill::kWifiFrequencyListProperty,
+ frequencies2);
+ SetServiceProperty(kWifi2ServicePath, shill::kWifiFrequency,
+ base::Value(5000));
+ SetServiceProperty(kWifi2ServicePath, shill::kProfileProperty,
+ base::Value(kUser1ProfilePath));
+ AddServiceToProfile(kUser1ProfilePath, kWifi2ServicePath);
+
+ AddService("stub_vpn1", "vpn1", shill::kTypeVPN, shill::kStateOnline);
+ SetServiceProperty("stub_vpn1", shill::kProviderTypeProperty,
+ base::Value(shill::kProviderOpenVpn));
+ AddServiceToProfile(kUser1ProfilePath, "stub_vpn1");
+
+ AddService("stub_vpn2", "vpn2", shill::kTypeVPN, shill::kStateOffline);
+ SetServiceProperty("stub_vpn2", shill::kProviderTypeProperty,
+ base::Value(shill::kProviderThirdPartyVpn));
+ SetServiceProperty("stub_vpn2", shill::kProviderHostProperty,
+ base::Value("third_party_provider_extension_id"));
+ AddServiceToProfile(kUser1ProfilePath, "stub_vpn2");
+ }
+
+ virtual void SetupCellular() {
+ // Add a Cellular GSM Device.
+ AddDevice(kCellularDevicePath, shill::kTypeCellular,
+ "stub_cellular_device1");
+ base::DictionaryValue home_provider;
+ home_provider.SetStringKey("name", "Cellular1_Provider");
+ home_provider.SetStringKey("code", "000000");
+ home_provider.SetStringKey("country", "us");
+ SetDeviceProperty(kCellularDevicePath, shill::kHomeProviderProperty,
+ home_provider);
+ SetDeviceProperty(kCellularDevicePath, shill::kTechnologyFamilyProperty,
+ base::Value(shill::kNetworkTechnologyGsm));
+ SetDeviceProperty(kCellularDevicePath, shill::kMeidProperty,
+ base::Value("test_meid"));
+ SetDeviceProperty(kCellularDevicePath, shill::kImeiProperty,
+ base::Value("test_imei"));
+ SetDeviceProperty(kCellularDevicePath, shill::kIccidProperty,
+ base::Value("test_iccid"));
+ SetDeviceProperty(kCellularDevicePath, shill::kEsnProperty,
+ base::Value("test_esn"));
+ SetDeviceProperty(kCellularDevicePath, shill::kMdnProperty,
+ base::Value("test_mdn"));
+ SetDeviceProperty(kCellularDevicePath, shill::kMinProperty,
+ base::Value("test_min"));
+ SetDeviceProperty(kCellularDevicePath, shill::kModelIdProperty,
+ base::Value("test_model_id"));
+ SetSimLocked(kCellularDevicePath, false);
+
+ // Add the Cellular Service.
+ AddService(kCellular1ServicePath, "cellular1", shill::kTypeCellular,
+ shill::kStateIdle);
+ SetServiceProperty(kCellular1ServicePath,
+ shill::kCellularAllowRoamingProperty,
+ base::Value(false));
+ SetServiceProperty(kCellular1ServicePath, shill::kAutoConnectProperty,
+ base::Value(true));
+ SetServiceProperty(kCellular1ServicePath, shill::kIccidProperty,
+ base::Value("test_iccid"));
+ SetServiceProperty(kCellular1ServicePath, shill::kNetworkTechnologyProperty,
+ base::Value(shill::kNetworkTechnologyGsm));
+ SetServiceProperty(kCellular1ServicePath, shill::kActivationStateProperty,
+ base::Value(shill::kActivationStateNotActivated));
+ SetServiceProperty(kCellular1ServicePath, shill::kRoamingStateProperty,
+ base::Value(shill::kRoamingStateHome));
+
+ AddServiceToProfile(kUser1ProfilePath, kCellular1ServicePath);
+ }
+
+ virtual std::string GetSanitizedActiveUsername() = 0;
+
+ virtual void AddDevice(const std::string& device_path,
+ const std::string& type,
+ const std::string& name) = 0;
+ virtual void SetDeviceProperty(const std::string& device_path,
+ const std::string& name,
+ const base::Value& value) = 0;
+ virtual void SetSimLocked(const std::string& device_path, bool enabled) = 0;
+ virtual void ClearDevices() = 0;
+ virtual void AddService(const std::string& service_path,
+ const std::string& name,
+ const std::string& type,
+ const std::string& state) = 0;
+ virtual void ClearServices() = 0;
+ virtual void SetServiceProperty(const std::string& service_path,
+ const std::string& property,
+ const base::Value& value) = 0;
+ virtual void AddProfile(const std::string& profile_path,
+ const std::string& userhash) = 0;
+
+ virtual void AddServiceToProfile(const std::string& profile_path,
+ const std::string& service_path) = 0;
+ virtual std::string GetSharedProfilePath() = 0;
+ virtual void AddIPConfig(const std::string& ip_config_path,
+ const base::Value& properties) = 0;
+};
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
class UIDelegateStub : public NetworkingPrivateDelegate::UIDelegate {
public:
static int s_show_account_details_called_;
@@ -110,23 +314,56 @@ class UIDelegateStub : public NetworkingPrivateDelegate::UIDelegate {
// static
int UIDelegateStub::s_show_account_details_called_ = 0;
-class NetworkingPrivateChromeOSApiTest : public extensions::ExtensionApiTest {
+class NetworkingPrivateChromeOSApiTestAsh
+ : public NetworkingPrivateChromeOSApiTestBase {
public:
- NetworkingPrivateChromeOSApiTest() {}
+ NetworkingPrivateChromeOSApiTestAsh() = default;
- NetworkingPrivateChromeOSApiTest(const NetworkingPrivateChromeOSApiTest&) =
- delete;
- NetworkingPrivateChromeOSApiTest& operator=(
- const NetworkingPrivateChromeOSApiTest&) = delete;
+ NetworkingPrivateChromeOSApiTestAsh(
+ const NetworkingPrivateChromeOSApiTestAsh&) = delete;
+ NetworkingPrivateChromeOSApiTestAsh& operator=(
+ const NetworkingPrivateChromeOSApiTestAsh&) = delete;
- bool RunNetworkingSubtest(const std::string& test) {
- const std::string arg =
- base::StringPrintf("{\"test\": \"%s\"}", test.c_str());
- return RunExtensionTest(
- "networking_private/chromeos",
- {.custom_arg = arg.c_str(), .launch_as_platform_app = true});
+ static std::unique_ptr<KeyedService> CreateNetworkingPrivateDelegate(
+ content::BrowserContext* context) {
+ std::unique_ptr<NetworkingPrivateDelegate> result(
+ new NetworkingPrivateChromeOS(context));
+ std::unique_ptr<NetworkingPrivateDelegate::UIDelegate> ui_delegate(
+ new UIDelegateStub);
+ result->set_ui_delegate(std::move(ui_delegate));
+ return result;
}
+ void SetupTether() {
+ ash::NetworkStateHandler* network_state_handler =
+ ash::NetworkHandler::Get()->network_state_handler();
+ network_state_handler->SetTetherTechnologyState(
+ ash::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED);
+ network_state_handler->AddTetherNetworkState(
+ "tetherGuid1", "tetherName1", "tetherCarrier1",
+ 50 /* battery_percentage */, 75 /* signal_strength */,
+ true /* has_connected_to_host */);
+ network_state_handler->AddTetherNetworkState(
+ "tetherGuid2", "tetherName2", "tetherCarrier2",
+ 75 /* battery_percentage */, 100 /* signal_strength */,
+ false /* has_connected_to_host */);
+ }
+
+ ShillServiceClient::TestInterface* service_test() {
+ return network_handler_test_helper_->service_test();
+ }
+ ShillProfileClient::TestInterface* profile_test() {
+ return network_handler_test_helper_->profile_test();
+ }
+ ShillDeviceClient::TestInterface* device_test() {
+ return network_handler_test_helper_->device_test();
+ }
+ ShillManagerClient::TestInterface* manager_test() {
+ return network_handler_test_helper_->manager_test();
+ }
+
+ // extensions::ExtensionApiTest overrides:
+
void SetUpInProcessBrowserTestFixture() override {
provider_.SetDefaultReturns(
/*is_initialization_complete_return=*/true,
@@ -136,12 +373,34 @@ class NetworkingPrivateChromeOSApiTest : public extensions::ExtensionApiTest {
extensions::ExtensionApiTest::SetUpInProcessBrowserTestFixture();
}
+ void SetUpOnMainThread() override {
+ extensions::ExtensionApiTest::SetUpOnMainThread();
+ content::RunAllPendingInMessageLoop();
+
+ NetworkingPrivateDelegateFactory::GetInstance()->SetTestingFactory(
+ profile(), base::BindRepeating(&CreateNetworkingPrivateDelegate));
+
+ network_handler_test_helper_ =
+ std::make_unique<ash::NetworkHandlerTestHelper>();
+
+ ConfigFakeNetwork();
+
+ PrefProxyConfigTrackerImpl::RegisterProfilePrefs(user_prefs_.registry());
+ PrefProxyConfigTrackerImpl::RegisterPrefs(local_state_.registry());
+ network_handler_test_helper_->RegisterPrefs(user_prefs_.registry(),
+ local_state_.registry());
+
+ network_handler_test_helper_->InitializePrefs(&user_prefs_, &local_state_);
+
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void TearDownOnMainThread() override { network_handler_test_helper_.reset(); }
+
+ // NetworkingPrivateChromeOSApiTestBase overrides:
+
void SetUpCommandLine(base::CommandLine* command_line) override {
- extensions::ExtensionApiTest::SetUpCommandLine(command_line);
- // Allowlist the extension ID of the test extension.
- command_line->AppendSwitchASCII(
- extensions::switches::kAllowlistedExtensionID,
- "epcifkihnkjgphfkloaaleeakhpmgdmn");
+ NetworkingPrivateChromeOSApiTestBase::SetUpCommandLine(command_line);
// TODO(pneubeck): Remove the following hack, once the NetworkingPrivateAPI
// uses the ProfileHelper to obtain the userhash crbug/238623.
@@ -154,7 +413,7 @@ class NetworkingPrivateChromeOSApiTest : public extensions::ExtensionApiTest {
sanitized_user);
}
- void InitializeSanitizedUsername() {
+ std::string GetSanitizedActiveUsername() override {
user_manager::UserManager* user_manager = user_manager::UserManager::Get();
user_manager::User* user = user_manager->GetActiveUser();
CHECK(user);
@@ -163,7 +422,7 @@ class NetworkingPrivateChromeOSApiTest : public extensions::ExtensionApiTest {
request.set_username(
cryptohome::CreateAccountIdentifierFromAccountId(user->GetAccountId())
.account_id());
- chromeos::CryptohomeMiscClient::Get()->GetSanitizedUsername(
+ ash::CryptohomeMiscClient::Get()->GetSanitizedUsername(
request,
base::BindOnce(
[](std::string* out,
@@ -172,310 +431,304 @@ class NetworkingPrivateChromeOSApiTest : public extensions::ExtensionApiTest {
CHECK(result.has_value());
*out = result->sanitized_username();
},
- &userhash_));
- content::RunAllPendingInMessageLoop();
- CHECK(!userhash_.empty());
+ &userhash));
+ base::RunLoop().RunUntilIdle();
+ CHECK(!userhash.empty());
+ return userhash;
}
- void SetupCellular() {
+ void SetupCellular() override {
UIDelegateStub::s_show_account_details_called_ = 0;
+ NetworkingPrivateChromeOSApiTestBase::SetupCellular();
+ base::RunLoop().RunUntilIdle();
+ }
- // Add a Cellular GSM Device.
- device_test()->AddDevice(kCellularDevicePath, shill::kTypeCellular,
- "stub_cellular_device1");
- base::DictionaryValue home_provider;
- home_provider.SetStringKey("name", "Cellular1_Provider");
- home_provider.SetStringKey("code", "000000");
- home_provider.SetStringKey("country", "us");
- SetDeviceProperty(kCellularDevicePath, shill::kHomeProviderProperty,
- home_provider);
- SetDeviceProperty(kCellularDevicePath, shill::kTechnologyFamilyProperty,
- base::Value(shill::kNetworkTechnologyGsm));
- SetDeviceProperty(kCellularDevicePath, shill::kMeidProperty,
- base::Value("test_meid"));
- SetDeviceProperty(kCellularDevicePath, shill::kImeiProperty,
- base::Value("test_imei"));
- SetDeviceProperty(kCellularDevicePath, shill::kIccidProperty,
- base::Value("test_iccid"));
- SetDeviceProperty(kCellularDevicePath, shill::kEsnProperty,
- base::Value("test_esn"));
- SetDeviceProperty(kCellularDevicePath, shill::kMdnProperty,
- base::Value("test_mdn"));
- SetDeviceProperty(kCellularDevicePath, shill::kMinProperty,
- base::Value("test_min"));
- SetDeviceProperty(kCellularDevicePath, shill::kModelIdProperty,
- base::Value("test_model_id"));
- device_test()->SetSimLocked(kCellularDevicePath, false);
+ void AddDevice(const std::string& device_path,
+ const std::string& type,
+ const std::string& name) override {
+ device_test()->AddDevice(device_path, type, name);
+ }
- // Add the Cellular Service.
- AddService(kCellular1ServicePath, "cellular1", shill::kTypeCellular,
- shill::kStateIdle);
- service_test()->SetServiceProperty(kCellular1ServicePath,
- shill::kCellularAllowRoamingProperty,
- base::Value(false));
- service_test()->SetServiceProperty(
- kCellular1ServicePath, shill::kAutoConnectProperty, base::Value(true));
- service_test()->SetServiceProperty(kCellular1ServicePath,
- shill::kIccidProperty,
- base::Value("test_iccid"));
- service_test()->SetServiceProperty(
- kCellular1ServicePath, shill::kNetworkTechnologyProperty,
- base::Value(shill::kNetworkTechnologyGsm));
- service_test()->SetServiceProperty(
- kCellular1ServicePath, shill::kActivationStateProperty,
- base::Value(shill::kActivationStateNotActivated));
- service_test()->SetServiceProperty(kCellular1ServicePath,
- shill::kRoamingStateProperty,
- base::Value(shill::kRoamingStateHome));
-
- profile_test()->AddService(kUser1ProfilePath, kCellular1ServicePath);
- content::RunAllPendingInMessageLoop();
+ void ClearDevices() override { device_test()->ClearDevices(); }
+
+ void SetDeviceProperty(const std::string& device_path,
+ const std::string& name,
+ const base::Value& value) override {
+ device_test()->SetDeviceProperty(device_path, name, value,
+ /*notify_changed=*/true);
}
- void SetupTether() {
- chromeos::NetworkStateHandler* network_state_handler =
- chromeos::NetworkHandler::Get()->network_state_handler();
- network_state_handler->SetTetherTechnologyState(
- chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED);
- network_state_handler->AddTetherNetworkState(
- "tetherGuid1", "tetherName1", "tetherCarrier1",
- 50 /* battery_percentage */, 75 /* signal_strength */,
- true /* has_connected_to_host */);
- network_state_handler->AddTetherNetworkState(
- "tetherGuid2", "tetherName2", "tetherCarrier2",
- 75 /* battery_percentage */, 100 /* signal_strength */,
- false /* has_connected_to_host */);
+ void SetSimLocked(const std::string& device_path, bool enabled) override {
+ device_test()->SetSimLocked(device_path, enabled);
}
void AddService(const std::string& service_path,
const std::string& name,
const std::string& type,
- const std::string& state) {
+ const std::string& state) override {
service_test()->AddService(service_path, service_path + "_guid", name, type,
state, true /* add_to_visible */);
}
- void SetDeviceProperty(const std::string& device_path,
- const std::string& name,
- const base::Value& value) {
- device_test()->SetDeviceProperty(device_path, name, value,
- /*notify_changed=*/true);
- }
+ void ClearServices() override { service_test()->ClearServices(); }
- static std::unique_ptr<KeyedService> CreateNetworkingPrivateDelegate(
- content::BrowserContext* context) {
- std::unique_ptr<NetworkingPrivateDelegate> result(
- new NetworkingPrivateChromeOS(context));
- std::unique_ptr<NetworkingPrivateDelegate::UIDelegate> ui_delegate(
- new UIDelegateStub);
- result->set_ui_delegate(std::move(ui_delegate));
- return result;
+ void SetServiceProperty(const std::string& service_path,
+ const std::string& property,
+ const base::Value& value) override {
+ service_test()->SetServiceProperty(service_path, property, value);
}
- void SetUpOnMainThread() override {
- extensions::ExtensionApiTest::SetUpOnMainThread();
- content::RunAllPendingInMessageLoop();
-
- NetworkingPrivateDelegateFactory::GetInstance()->SetTestingFactory(
- profile(), base::BindRepeating(&CreateNetworkingPrivateDelegate));
-
- InitializeSanitizedUsername();
+ void AddIPConfig(const std::string& ip_config_path,
+ const base::Value& properties) override {
+ network_handler_test_helper_->ip_config_test()->AddIPConfig(ip_config_path,
+ properties);
+ }
- network_handler_test_helper_ =
- std::make_unique<chromeos::NetworkHandlerTestHelper>();
- device_test()->ClearDevices();
- service_test()->ClearServices();
+ void AddProfile(const std::string& profile_path,
+ const std::string& userhash) override {
+ profile_test()->AddProfile(profile_path, userhash);
+ }
- // Sends a notification about the added profile.
- profile_test()->AddProfile(kUser1ProfilePath, userhash_);
+ void AddServiceToProfile(const std::string& profile_path,
+ const std::string& service_path) override {
+ profile_test()->AddService(profile_path, service_path);
+ }
- // Add IPConfigs
- base::DictionaryValue ipconfig;
- ipconfig.SetKey(shill::kAddressProperty, base::Value("0.0.0.0"));
- ipconfig.SetKey(shill::kGatewayProperty, base::Value("0.0.0.1"));
- ipconfig.SetKey(shill::kPrefixlenProperty, base::Value(0));
- ipconfig.SetKey(shill::kMethodProperty, base::Value(shill::kTypeIPv4));
- network_handler_test_helper_->ip_config_test()->AddIPConfig(kIPConfigPath,
- ipconfig);
+ std::string GetSharedProfilePath() override {
+ return ShillProfileClient::GetSharedProfilePath();
+ }
- // Add Devices
- device_test()->AddDevice(kEthernetDevicePath, shill::kTypeEthernet,
- "stub_ethernet_device1");
+ protected:
+ std::unique_ptr<ash::NetworkHandlerTestHelper> network_handler_test_helper_;
+ testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_;
+ sync_preferences::TestingPrefServiceSyncable user_prefs_;
+ TestingPrefServiceSimple local_state_;
+};
+#else
+class NetworkingPrivateChromeOSApiTestLacros
+ : public NetworkingPrivateChromeOSApiTestBase {
+ public:
+ NetworkingPrivateChromeOSApiTestLacros() {}
+
+ NetworkingPrivateChromeOSApiTestLacros(
+ const NetworkingPrivateChromeOSApiTestLacros&) = delete;
+ NetworkingPrivateChromeOSApiTestLacros& operator=(
+ const NetworkingPrivateChromeOSApiTestLacros&) = delete;
+
+ bool SetUpAsh() {
+ auto* service = chromeos::LacrosService::Get();
+ if (!service->IsAvailable<crosapi::mojom::TestController>() ||
+ service->GetInterfaceVersion(crosapi::mojom::TestController::Uuid_) <
+ static_cast<int>(crosapi::mojom::TestController::MethodMinVersions::
+ kBindShillClientTestInterfaceMinVersion)) {
+ 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());
+
+ ConfigFakeNetwork();
+
+ return true;
+ }
- device_test()->AddDevice(kWifiDevicePath, shill::kTypeWifi,
- "stub_wifi_device1");
- base::ListValue wifi_ip_configs;
- wifi_ip_configs.Append(kIPConfigPath);
- SetDeviceProperty(kWifiDevicePath, shill::kIPConfigsProperty,
- wifi_ip_configs);
- SetDeviceProperty(kWifiDevicePath, shill::kAddressProperty,
- base::Value("001122aabbcc"));
+ // NetworkingPrivateChromeOSApiTestBase overrides
- // Add Services
- AddService("stub_ethernet", "eth0", shill::kTypeEthernet,
- shill::kStateOnline);
- service_test()->SetServiceProperty(
- "stub_ethernet", shill::kProfileProperty,
- base::Value(ShillProfileClient::GetSharedProfilePath()));
- profile_test()->AddService(ShillProfileClient::GetSharedProfilePath(),
- "stub_ethernet");
+ std::string GetSanitizedActiveUsername() override {
+ auto* service = chromeos::LacrosService::Get();
+ if (!service->IsAvailable<crosapi::mojom::TestController>() ||
+ service->GetInterfaceVersion(crosapi::mojom::TestController::Uuid_) <
+ static_cast<int>(crosapi::mojom::TestController::MethodMinVersions::
+ kGetSanitizedActiveUsernameMinVersion)) {
+ LOG(ERROR) << "Unsupported ash version.";
+ return "";
+ }
- AddService(kWifi1ServicePath, "wifi1", shill::kTypeWifi,
- shill::kStateOnline);
- service_test()->SetServiceProperty(kWifi1ServicePath,
- shill::kSecurityClassProperty,
- base::Value(shill::kSecurityWep));
- service_test()->SetServiceProperty(kWifi1ServicePath, shill::kWifiBSsid,
- base::Value("00:01:02:03:04:05"));
- service_test()->SetServiceProperty(
- kWifi1ServicePath, shill::kSignalStrengthProperty, base::Value(40));
- service_test()->SetServiceProperty(kWifi1ServicePath,
- shill::kProfileProperty,
- base::Value(kUser1ProfilePath));
- service_test()->SetServiceProperty(
- kWifi1ServicePath, shill::kConnectableProperty, base::Value(true));
- service_test()->SetServiceProperty(kWifi1ServicePath,
- shill::kDeviceProperty,
- base::Value(kWifiDevicePath));
- base::DictionaryValue static_ipconfig;
- static_ipconfig.SetKey(shill::kAddressProperty, base::Value("1.2.3.4"));
- static_ipconfig.SetKey(shill::kGatewayProperty, base::Value("0.0.0.0"));
- static_ipconfig.SetKey(shill::kPrefixlenProperty, base::Value(1));
- service_test()->SetServiceProperty(
- kWifi1ServicePath, shill::kStaticIPConfigProperty, static_ipconfig);
- base::ListValue frequencies1;
- frequencies1.Append(2400);
- service_test()->SetServiceProperty(
- kWifi1ServicePath, shill::kWifiFrequencyListProperty, frequencies1);
- service_test()->SetServiceProperty(kWifi1ServicePath, shill::kWifiFrequency,
- base::Value(2400));
- profile_test()->AddService(kUser1ProfilePath, kWifi1ServicePath);
+ crosapi::mojom::TestControllerAsyncWaiter test_controller_waiter{
+ service->GetRemote<crosapi::mojom::TestController>().get()};
- AddService(kWifi2ServicePath, "wifi2_PSK", shill::kTypeWifi,
- shill::kStateIdle);
- service_test()->SetServiceProperty(kWifi2ServicePath,
- shill::kSecurityClassProperty,
- base::Value(shill::kSecurityPsk));
- service_test()->SetServiceProperty(
- kWifi2ServicePath, shill::kSignalStrengthProperty, base::Value(80));
- service_test()->SetServiceProperty(
- kWifi2ServicePath, shill::kConnectableProperty, base::Value(true));
+ std::string userhash;
+ test_controller_waiter.GetSanitizedActiveUsername(&userhash);
+ return userhash;
+ }
- base::ListValue frequencies2;
- frequencies2.Append(2400);
- frequencies2.Append(5000);
- service_test()->SetServiceProperty(
- kWifi2ServicePath, shill::kWifiFrequencyListProperty, frequencies2);
- service_test()->SetServiceProperty(kWifi2ServicePath, shill::kWifiFrequency,
- base::Value(5000));
- service_test()->SetServiceProperty(kWifi2ServicePath,
- shill::kProfileProperty,
- base::Value(kUser1ProfilePath));
- profile_test()->AddService(kUser1ProfilePath, kWifi2ServicePath);
+ 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);
+ }
- AddService("stub_vpn1", "vpn1", shill::kTypeVPN, shill::kStateOnline);
- service_test()->SetServiceProperty("stub_vpn1",
- shill::kProviderTypeProperty,
- base::Value(shill::kProviderOpenVpn));
- profile_test()->AddService(kUser1ProfilePath, "stub_vpn1");
+ 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);
+ }
- AddService("stub_vpn2", "vpn2", shill::kTypeVPN, shill::kStateOffline);
- service_test()->SetServiceProperty(
- "stub_vpn2", shill::kProviderTypeProperty,
- base::Value(shill::kProviderThirdPartyVpn));
- service_test()->SetServiceProperty(
- "stub_vpn2", shill::kProviderHostProperty,
- base::Value("third_party_provider_extension_id"));
- profile_test()->AddService(kUser1ProfilePath, "stub_vpn2");
+ void SetSimLocked(const std::string& device_path, bool enabled) override {
+ ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
+ .SetSimLocked(device_path, enabled);
+ }
- PrefProxyConfigTrackerImpl::RegisterProfilePrefs(user_prefs_.registry());
- PrefProxyConfigTrackerImpl::RegisterPrefs(local_state_.registry());
- network_handler_test_helper_->RegisterPrefs(user_prefs_.registry(),
- local_state_.registry());
+ void ClearDevices() override {
+ ShillClientTestInterfaceAsyncWaiter(shill_test_.get()).ClearDevices();
+ }
- network_handler_test_helper_->InitializePrefs(&user_prefs_, &local_state_);
+ 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 */);
+ }
- content::RunAllPendingInMessageLoop();
+ void ClearServices() override {
+ ShillClientTestInterfaceAsyncWaiter(shill_test_.get()).ClearServices();
}
- void TearDownOnMainThread() { network_handler_test_helper_.reset(); }
+ 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());
+ }
- ShillServiceClient::TestInterface* service_test() {
- return network_handler_test_helper_->service_test();
+ void AddIPConfig(const std::string& ip_config_path,
+ const base::Value& properties) override {
+ ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
+ .AddIPConfig(ip_config_path, properties.Clone());
}
- ShillProfileClient::TestInterface* profile_test() {
- return network_handler_test_helper_->profile_test();
+
+ void AddProfile(const std::string& profile_path,
+ const std::string& userhash) override {
+ ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
+ .AddProfile(profile_path, userhash);
}
- ShillDeviceClient::TestInterface* device_test() {
- return network_handler_test_helper_->device_test();
+
+ void AddServiceToProfile(const std::string& profile_path,
+ const std::string& service_path) override {
+ ShillClientTestInterfaceAsyncWaiter(shill_test_.get())
+ .AddServiceToProfile(profile_path, service_path);
}
- ShillManagerClient::TestInterface* manager_test() {
- return network_handler_test_helper_->manager_test();
+
+ std::string GetSharedProfilePath() override {
+ // TODO(crbug.com/): get this information from Ash
+ const char kSharedProfilePath[] = "/profile/default";
+ return kSharedProfilePath;
}
protected:
- std::unique_ptr<chromeos::NetworkHandlerTestHelper>
- network_handler_test_helper_;
- testing::NiceMock<policy::MockConfigurationPolicyProvider> provider_;
- sync_preferences::TestingPrefServiceSyncable user_prefs_;
- TestingPrefServiceSimple local_state_;
- std::string userhash_;
+ mojo::Remote<crosapi::mojom::ShillClientTestInterface> shill_test_;
};
+#endif
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+using NetworkingPrivateChromeOSApiTest = NetworkingPrivateChromeOSApiTestLacros;
+#else
+using NetworkingPrivateChromeOSApiTest = NetworkingPrivateChromeOSApiTestAsh;
+#endif
// Place each subtest into a separate browser test so that the stub networking
// library state is reset for each subtest run. This way they won't affect each
// other.
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, StartConnect) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("startConnect")) << message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, StartDisconnect) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("startDisconnect")) << message_;
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, StartActivate) {
SetupCellular();
EXPECT_TRUE(RunNetworkingSubtest("startActivate")) << message_;
EXPECT_EQ(1, UIDelegateStub::s_show_account_details_called_);
}
+#endif
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
StartConnectNonexistent) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("startConnectNonexistent")) << message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
StartDisconnectNonexistent) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("startDisconnectNonexistent")) << message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
StartGetPropertiesNonexistent) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("startGetPropertiesNonexistent"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetNetworks) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
// Hide stub_wifi2.
- service_test()->SetServiceProperty(kWifi2ServicePath, shill::kVisibleProperty,
- base::Value(false));
+ SetServiceProperty(kWifi2ServicePath, shill::kVisibleProperty,
+ base::Value(false));
// Add a couple of additional networks that are not configured (saved).
AddService("stub_wifi3", "wifi3", shill::kTypeWifi, shill::kStateIdle);
AddService("stub_wifi4", "wifi4", shill::kTypeWifi, shill::kStateIdle);
content::RunAllPendingInMessageLoop();
+
EXPECT_TRUE(RunNetworkingSubtest("getNetworks")) << message_;
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetVisibleNetworks) {
EXPECT_TRUE(RunNetworkingSubtest("getVisibleNetworks")) << message_;
}
+#endif
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
GetVisibleNetworksWifi) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("getVisibleNetworksWifi")) << message_;
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, EnabledNetworkTypes) {
EXPECT_TRUE(RunNetworkingSubtest("enabledNetworkTypesDisable")) << message_;
EXPECT_TRUE(RunNetworkingSubtest("enabledNetworkTypesEnable")) << message_;
@@ -488,13 +741,24 @@ IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetDeviceStates) {
manager_test()->SetTechnologyInitializing("cellular", true);
EXPECT_TRUE(RunNetworkingSubtest("getDeviceStates")) << message_;
}
+#endif
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, RequestNetworkScan) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("requestNetworkScan")) << message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
RequestNetworkScanCellular) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
SetupCellular();
EXPECT_TRUE(RunNetworkingSubtest("requestNetworkScanCellular")) << message_;
}
@@ -502,23 +766,41 @@ IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
// Properties are filtered and translated through
// ShillToONCTranslator::TranslateWiFiWithState
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetProperties) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("getProperties")) << message_;
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
GetCellularProperties) {
SetupCellular();
EXPECT_TRUE(RunNetworkingSubtest("getPropertiesCellular")) << message_;
}
+#endif
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetState) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("getState")) << message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetStateNonExistent) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("getStateNonExistent")) << message_;
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
SetCellularProperties) {
SetupCellular();
@@ -567,11 +849,18 @@ IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
EXPECT_TRUE(RunNetworkingSubtest("createNetworkForPolicyControlledNetwork"));
}
+#endif
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, ForgetNetwork) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("forgetNetwork")) << message_;
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
ForgetPolicyControlledNetwork) {
constexpr char kUserPolicyBlob[] =
@@ -653,45 +942,72 @@ IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetManagedProperties) {
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetErrorState) {
- chromeos::NetworkHandler::Get()->network_state_handler()->SetErrorForTest(
+ ash::NetworkHandler::Get()->network_state_handler()->SetErrorForTest(
kWifi1ServicePath, "TestErrorState");
EXPECT_TRUE(RunNetworkingSubtest("getErrorState")) << message_;
}
+#endif
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
OnNetworksChangedEventConnect) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("onNetworksChangedEventConnect"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
OnNetworksChangedEventDisconnect) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("onNetworksChangedEventDisconnect"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
OnNetworkListChangedEvent) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("onNetworkListChangedEvent")) << message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
OnDeviceStateListChangedEvent) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
EXPECT_TRUE(RunNetworkingSubtest("onDeviceStateListChangedEvent"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
OnDeviceScanningChangedEvent) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
SetupCellular();
EXPECT_TRUE(RunNetworkingSubtest("onDeviceScanningChangedEvent")) << message_;
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
OnCertificateListsChangedEvent) {
ExtensionTestMessageListener listener("eventListenerReady");
listener.SetOnSatisfied(base::BindOnce([](const std::string& message) {
- chromeos::NetworkHandler::Get()
+ ash::NetworkHandler::Get()
->network_certificate_handler()
->AddAuthorityCertificateForTest("authority_cert");
}));
@@ -703,10 +1019,10 @@ IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
GetCaptivePortalStatus) {
// Ethernet defaults to online. Set wifi1 to idle -> 'Offline', and wifi2 to
// redirect-found -> 'Portal'.
- service_test()->SetServiceProperty(kWifi1ServicePath, shill::kStateProperty,
- base::Value(shill::kStateIdle));
- service_test()->SetServiceProperty(kWifi2ServicePath, shill::kStateProperty,
- base::Value(shill::kStateRedirectFound));
+ SetServiceProperty(kWifi1ServicePath, shill::kStateProperty,
+ base::Value(shill::kStateIdle));
+ SetServiceProperty(kWifi2ServicePath, shill::kStateProperty,
+ base::Value(shill::kStateRedirectFound));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(RunNetworkingSubtest("getCaptivePortalStatus")) << message_;
@@ -722,28 +1038,43 @@ IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
ExtensionTestMessageListener listener("notifyPortalDetectorObservers");
listener.SetOnSatisfied(
base::BindLambdaForTesting([&](const std::string& message) {
- service_test()->SetServiceProperty(
- kWifi1ServicePath, shill::kStateProperty,
- base::Value(shill::kStateRedirectFound));
+ SetServiceProperty(kWifi1ServicePath, shill::kStateProperty,
+ base::Value(shill::kStateRedirectFound));
}));
EXPECT_TRUE(RunNetworkingSubtest("captivePortalNotification")) << message_;
}
+#endif
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, UnlockCellularSim) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
SetupCellular();
// Lock the SIM
- device_test()->SetSimLocked(kCellularDevicePath, true);
+ SetSimLocked(kCellularDevicePath, true);
EXPECT_TRUE(RunNetworkingSubtest("unlockCellularSim")) << message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, SetCellularSimState) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
SetupCellular();
EXPECT_TRUE(RunNetworkingSubtest("setCellularSimState")) << message_;
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
SelectCellularMobileNetwork) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
SetupCellular();
// Create fake list of found networks.
std::unique_ptr<base::ListValue> found_networks =
@@ -765,12 +1096,18 @@ IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, CellularSimPuk) {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (!SetUpAsh()) {
+ GTEST_SKIP() << "Unsupported ash version.";
+ }
+#endif
SetupCellular();
// Lock the SIM
- device_test()->SetSimLocked(kCellularDevicePath, true);
+ SetSimLocked(kCellularDevicePath, true);
EXPECT_TRUE(RunNetworkingSubtest("cellularSimPuk")) << message_;
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetGlobalPolicy) {
base::DictionaryValue global_config;
global_config.SetKey(
@@ -780,7 +1117,7 @@ IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetGlobalPolicy) {
::onc::global_network_config::kAllowOnlyPolicyWiFiToConnect,
base::Value(false));
global_config.SetKey("SomeNewGlobalPolicy", base::Value(false));
- chromeos::NetworkHandler::Get()
+ ash::NetworkHandler::Get()
->managed_network_configuration_handler()
->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY,
std::string() /* no username hash */, base::ListValue(),
@@ -816,7 +1153,7 @@ IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest,
}
IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, GetCertificateLists) {
- chromeos::NetworkHandler::Get()
+ ash::NetworkHandler::Get()
->network_certificate_handler()
->AddAuthorityCertificateForTest("authority_cert");
EXPECT_TRUE(RunNetworkingSubtest("getCertificateLists")) << message_;
@@ -831,5 +1168,6 @@ IN_PROC_BROWSER_TEST_F(NetworkingPrivateChromeOSApiTest, Alias) {
{.launch_as_platform_app = true}))
<< message_;
}
+#endif
} // namespace
diff --git a/chromium/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc b/chromium/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc
index 506ab3b70e6..4f231bd163f 100644
--- a/chromium/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc
+++ b/chromium/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc
@@ -4,9 +4,9 @@
#include "chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.h"
-#include "chromeos/network/network_connect.h"
-#include "chromeos/network/network_state.h"
-#include "chromeos/network/network_state_handler.h"
+#include "chromeos/ash/components/network/network_connect.h"
+#include "chromeos/ash/components/network/network_state.h"
+#include "chromeos/ash/components/network/network_state_handler.h"
namespace chromeos {
namespace extensions {
@@ -17,7 +17,7 @@ NetworkingPrivateUIDelegateChromeOS::~NetworkingPrivateUIDelegateChromeOS() {}
void NetworkingPrivateUIDelegateChromeOS::ShowAccountDetails(
const std::string& guid) const {
- chromeos::NetworkConnect::Get()->ShowCarrierAccountDetail(guid);
+ ash::NetworkConnect::Get()->ShowCarrierAccountDetail(guid);
}
} // namespace extensions
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 e537ef7b9ea..8459f31ef24 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
@@ -26,9 +26,9 @@ ExtensionNotificationDisplayHelperFactory::GetForProfile(Profile* profile) {
ExtensionNotificationDisplayHelperFactory::
ExtensionNotificationDisplayHelperFactory()
- : BrowserContextKeyedServiceFactory(
+ : ProfileKeyedServiceFactory(
"ExtensionNotificationDisplayHelperFactory",
- BrowserContextDependencyManager::GetInstance()) {}
+ ProfileSelections::BuildForRegularAndIncognito()) {}
ExtensionNotificationDisplayHelperFactory::
~ExtensionNotificationDisplayHelperFactory() {}
@@ -40,10 +40,4 @@ ExtensionNotificationDisplayHelperFactory::BuildServiceInstanceFor(
return new ExtensionNotificationDisplayHelper(profile);
}
-content::BrowserContext*
-ExtensionNotificationDisplayHelperFactory::GetBrowserContextToUse(
- content::BrowserContext* context) const {
- return chrome::GetBrowserContextOwnInstanceInIncognito(context);
-}
-
} // 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 c7e1ea76eab..76917b632c1 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
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_EXTENSIONS_API_NOTIFICATIONS_EXTENSION_NOTIFICATION_DISPLAY_HELPER_FACTORY_H_
#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
class Profile;
@@ -15,7 +15,7 @@ namespace extensions {
class ExtensionNotificationDisplayHelper;
class ExtensionNotificationDisplayHelperFactory
- : public BrowserContextKeyedServiceFactory {
+ : public ProfileKeyedServiceFactory {
public:
ExtensionNotificationDisplayHelperFactory(
const ExtensionNotificationDisplayHelperFactory&) = delete;
@@ -32,8 +32,6 @@ class ExtensionNotificationDisplayHelperFactory
// Overridden from BrowserContextKeyedServiceFactory.
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
- content::BrowserContext* GetBrowserContextToUse(
- content::BrowserContext* context) const override;
private:
friend struct base::DefaultSingletonTraits<
diff --git a/chromium/chrome/browser/extensions/api/notifications/extension_notification_handler.cc b/chromium/chrome/browser/extensions/api/notifications/extension_notification_handler.cc
index 9c7b408f637..a921944fa2a 100644
--- a/chromium/chrome/browser/extensions/api/notifications/extension_notification_handler.cc
+++ b/chromium/chrome/browser/extensions/api/notifications/extension_notification_handler.cc
@@ -130,8 +130,8 @@ void ExtensionNotificationHandler::SendEvent(
if (!event_router)
return;
- std::unique_ptr<Event> event(new Event(
- histogram_value, event_name, std::move(*args).TakeListDeprecated()));
+ auto event = std::make_unique<Event>(histogram_value, event_name,
+ std::move(args->GetList()));
event->user_gesture = user_gesture;
event_router->DispatchEventToExtension(extension_id, std::move(event));
}
diff --git a/chromium/chrome/browser/extensions/api/notifications/notifications_api.cc b/chromium/chrome/browser/extensions/api/notifications/notifications_api.cc
index c0ae46820a9..1d5c0bc225d 100644
--- a/chromium/chrome/browser/extensions/api/notifications/notifications_api.cc
+++ b/chromium/chrome/browser/extensions/api/notifications/notifications_api.cc
@@ -533,7 +533,7 @@ NotificationsApiFunction::MapApiTemplateTypeToType(
switch (type) {
case api::notifications::TEMPLATE_TYPE_NONE:
case api::notifications::TEMPLATE_TYPE_BASIC:
- return message_center::NOTIFICATION_TYPE_BASE_FORMAT;
+ return message_center::NOTIFICATION_TYPE_SIMPLE;
case api::notifications::TEMPLATE_TYPE_IMAGE:
return message_center::NOTIFICATION_TYPE_IMAGE;
case api::notifications::TEMPLATE_TYPE_LIST:
@@ -543,7 +543,7 @@ NotificationsApiFunction::MapApiTemplateTypeToType(
default:
// Gracefully handle newer application code that is running on an older
// runtime that doesn't recognize the requested template.
- return message_center::NOTIFICATION_TYPE_BASE_FORMAT;
+ return message_center::NOTIFICATION_TYPE_SIMPLE;
}
}
diff --git a/chromium/chrome/browser/extensions/api/notifications/notifications_apitest.cc b/chromium/chrome/browser/extensions/api/notifications/notifications_apitest.cc
index 3f5385da594..299ca5ded58 100644
--- a/chromium/chrome/browser/extensions/api/notifications/notifications_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/notifications/notifications_apitest.cc
@@ -27,6 +27,7 @@
#include "chrome/browser/notifications/notifier_state_tracker_factory.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/test/base/interactive_test_utils.h"
+#include "components/services/app_service/public/cpp/app_launch_util.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/api/test/test_api.h"
#include "extensions/browser/app_window/app_window.h"
@@ -166,9 +167,8 @@ class NotificationsApiTest : public extensions::ExtensionApiTest {
apps::AppServiceProxyFactory::GetForProfile(browser()->profile())
->BrowserAppLauncher()
->LaunchAppWithParamsForTesting(apps::AppLaunchParams(
- extension->id(), apps::mojom::LaunchContainer::kLaunchContainerNone,
- WindowOpenDisposition::NEW_WINDOW,
- apps::mojom::LaunchSource::kFromTest));
+ extension->id(), apps::LaunchContainer::kLaunchContainerNone,
+ WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromTest));
}
std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_;
diff --git a/chromium/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc b/chromium/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc
new file mode 100644
index 00000000000..b64cc18264b
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc
@@ -0,0 +1,351 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/offscreen/offscreen_api.h"
+
+#include <algorithm>
+
+#include "base/run_loop.h"
+#include "base/test/bind.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_util.h"
+#include "components/version_info/channel.h"
+#include "content/public/test/browser_test.h"
+#include "extensions/browser/api/offscreen/offscreen_document_manager.h"
+#include "extensions/browser/background_script_executor.h"
+#include "extensions/browser/extension_util.h"
+#include "extensions/browser/service_worker_task_queue.h"
+#include "extensions/browser/test_extension_registry_observer.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_features.h"
+#include "extensions/common/features/feature_channel.h"
+#include "extensions/test/extension_background_page_waiter.h"
+#include "extensions/test/result_catcher.h"
+#include "extensions/test/test_extension_dir.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace extensions {
+
+namespace {
+
+// Sets the extension to be enabled in incognito mode.
+scoped_refptr<const Extension> SetExtensionIncognitoEnabled(
+ const Extension& extension,
+ Profile& profile) {
+ // Enabling the extension in incognito results in an extension reload; wait
+ // for that to finish and return the new extension pointer.
+ TestExtensionRegistryObserver registry_observer(
+ ExtensionRegistry::Get(&profile), extension.id());
+ util::SetIsIncognitoEnabled(extension.id(), &profile, true);
+ scoped_refptr<const Extension> reloaded_extension =
+ registry_observer.WaitForExtensionLoaded();
+
+ if (!reloaded_extension) {
+ ADD_FAILURE() << "Failed to properly reload extension.";
+ return nullptr;
+ }
+
+ EXPECT_TRUE(util::IsIncognitoEnabled(reloaded_extension->id(), &profile));
+ return reloaded_extension;
+}
+
+// Wakes up the service worker for the `extension` in the given `profile`.
+void WakeUpServiceWorker(const Extension& extension, Profile& profile) {
+ base::RunLoop run_loop;
+ auto quit_loop_adapter =
+ [&run_loop](std::unique_ptr<LazyContextTaskQueue::ContextInfo>) {
+ run_loop.QuitWhenIdle();
+ };
+ ServiceWorkerTaskQueue::Get(&profile)->AddPendingTask(
+ LazyContextId(&profile, extension.id(), extension.url()),
+ base::BindLambdaForTesting(quit_loop_adapter));
+ run_loop.Run();
+}
+
+} // namespace
+
+class OffscreenApiTest : public ExtensionApiTest {
+ public:
+ OffscreenApiTest() {
+ feature_list_.InitAndEnableFeature(
+ extensions_features::kExtensionsOffscreenDocuments);
+ }
+ ~OffscreenApiTest() override = default;
+
+ // Creates a new offscreen document through an API call, expecting success.
+ void ProgrammaticallyCreateOffscreenDocument(const Extension& extension,
+ Profile& profile) {
+ static constexpr char kScript[] =
+ R"((async () => {
+ let message;
+ try {
+ await chrome.offscreen.createDocument(
+ {
+ url: 'offscreen.html',
+ reasons: ['TESTING'],
+ justification: 'testing'
+ });
+ message = 'success';
+ } catch (e) {
+ message = 'Error: ' + e.toString();
+ }
+ chrome.test.sendScriptResult(message);
+ })();)";
+ base::Value result = BackgroundScriptExecutor::ExecuteScript(
+ &profile, extension.id(), kScript,
+ BackgroundScriptExecutor::ResultCapture::kSendScriptResult);
+ ASSERT_TRUE(result.is_string());
+ EXPECT_EQ("success", result.GetString());
+ }
+
+ // Closes an offscreen document through an API call, expecting success.
+ void ProgrammaticallyCloseOffscreenDocument(const Extension& extension,
+ Profile& profile) {
+ static constexpr char kScript[] =
+ R"((async () => {
+ let message;
+ try {
+ await chrome.offscreen.closeDocument();
+ message = 'success';
+ } catch (e) {
+ message = 'Error: ' + e.toString();
+ }
+ chrome.test.sendScriptResult(message);
+ })();)";
+ base::Value result = BackgroundScriptExecutor::ExecuteScript(
+ &profile, extension.id(), kScript,
+ BackgroundScriptExecutor::ResultCapture::kSendScriptResult);
+ ASSERT_TRUE(result.is_string());
+ EXPECT_EQ("success", result.GetString());
+ }
+
+ // Returns the result of an API call to `offscreen.hasDocument()`. Expects the
+ // call to not throw an error, independent of whether a document exists.
+ bool ProgrammaticallyCheckIfHasOffscreenDocument(const Extension& extension,
+ Profile& profile) {
+ static constexpr char kScript[] =
+ R"((async () => {
+ let result;
+ try {
+ result = await chrome.offscreen.hasDocument();
+ } catch (e) {
+ result = 'Error: ' + e.toString();
+ }
+ chrome.test.sendScriptResult(result);
+ })();)";
+ base::Value result = BackgroundScriptExecutor::ExecuteScript(
+ &profile, extension.id(), kScript,
+ BackgroundScriptExecutor::ResultCapture::kSendScriptResult);
+ EXPECT_TRUE(result.is_bool()) << result;
+ return result.is_bool() && result.GetBool();
+ }
+
+ private:
+ // The `offscreen` API is currently behind both a feature and a channel
+ // restriction.
+ base::test::ScopedFeatureList feature_list_;
+ ScopedCurrentChannel current_channel_override_{version_info::Channel::CANARY};
+};
+
+// Tests the general flow of creating an offscreen document.
+IN_PROC_BROWSER_TEST_F(OffscreenApiTest, BasicDocumentManagement) {
+ ASSERT_TRUE(RunExtensionTest("offscreen/basic_document_management"))
+ << message_;
+}
+
+// Tests creating, querying, and closing offscreen documents in an incognito
+// split mode extension.
+IN_PROC_BROWSER_TEST_F(OffscreenApiTest, IncognitoModeHandling_SplitMode) {
+ // `split` incognito mode is required in order to allow the extension to
+ // have a separate process in incognito.
+ static constexpr char kManifest[] =
+ R"({
+ "name": "Offscreen Document Test",
+ "manifest_version": 3,
+ "version": "0.1",
+ "background": {"service_worker": "background.js"},
+ "permissions": ["offscreen"],
+ "incognito": "split"
+ })";
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), "// Blank.");
+ test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.html"),
+ "<html>offscreen</html>");
+
+ scoped_refptr<const Extension> extension =
+ LoadExtension(test_dir.UnpackedPath());
+ ASSERT_TRUE(extension);
+
+ extension = SetExtensionIncognitoEnabled(*extension, *profile());
+ ASSERT_TRUE(extension);
+
+ Browser* incognito_browser = CreateIncognitoBrowser();
+ ASSERT_TRUE(incognito_browser);
+ Profile* incognito_profile = incognito_browser->profile();
+
+ // We're going to be executing scripts in the service worker context, so
+ // ensure the service worker is active.
+ // TODO(devlin): Should BackgroundScriptExecutor handle that for us? (Perhaps
+ // optionally?)
+ WakeUpServiceWorker(*extension, *profile());
+ WakeUpServiceWorker(*extension, *incognito_profile);
+
+ auto has_offscreen_document = [this, extension](Profile& profile) {
+ bool programmatic =
+ ProgrammaticallyCheckIfHasOffscreenDocument(*extension, profile);
+ bool in_manager =
+ OffscreenDocumentManager::Get(&profile)
+ ->GetOffscreenDocumentForExtension(*extension) != nullptr;
+ EXPECT_EQ(programmatic, in_manager) << "Mismatch between manager and API.";
+ return programmatic && in_manager;
+ };
+
+ // Create an offscreen document in the on-the-record profile. Only it should
+ // have a document; the off-the-record profile is considered distinct.
+ ProgrammaticallyCreateOffscreenDocument(*extension, *profile());
+ EXPECT_TRUE(has_offscreen_document(*profile()));
+ EXPECT_FALSE(has_offscreen_document(*incognito_profile));
+
+ // Now, create a new document in the off-the-record profile.
+ ProgrammaticallyCreateOffscreenDocument(*extension,
+ *incognito_browser->profile());
+ EXPECT_TRUE(has_offscreen_document(*profile()));
+ EXPECT_TRUE(has_offscreen_document(*incognito_profile));
+
+ // Close the off-the-record profile - the on-the-record profile's offscreen
+ // document should remain open.
+ ProgrammaticallyCloseOffscreenDocument(*extension, *incognito_profile);
+ EXPECT_TRUE(has_offscreen_document(*profile()));
+ EXPECT_FALSE(has_offscreen_document(*incognito_profile));
+
+ // Finally, close the on-the-record profile's document.
+ ProgrammaticallyCloseOffscreenDocument(*extension, *profile());
+ EXPECT_FALSE(has_offscreen_document(*profile()));
+ EXPECT_FALSE(has_offscreen_document(*incognito_profile));
+}
+
+// Tests creating, querying, and closing offscreen documents in an incognito
+// spanning mode extension.
+IN_PROC_BROWSER_TEST_F(OffscreenApiTest, IncognitoModeHandling_SpanningMode) {
+ static constexpr char kManifest[] =
+ R"({
+ "name": "Offscreen Document Test",
+ "manifest_version": 3,
+ "version": "0.1",
+ "background": {"service_worker": "background.js"},
+ "permissions": ["offscreen"],
+ "incognito": "spanning"
+ })";
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), "// Blank.");
+ test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.html"),
+ "<html>offscreen</html>");
+
+ scoped_refptr<const Extension> extension =
+ LoadExtension(test_dir.UnpackedPath());
+ ASSERT_TRUE(extension);
+
+ extension = SetExtensionIncognitoEnabled(*extension, *profile());
+ ASSERT_TRUE(extension);
+
+ Browser* incognito_browser = CreateIncognitoBrowser();
+ ASSERT_TRUE(incognito_browser);
+ Profile* incognito_profile = incognito_browser->profile();
+
+ // Wake up the on-the-record service worker (the only one we have, as a
+ // spanning mode extension).
+ WakeUpServiceWorker(*extension, *profile());
+
+ auto has_offscreen_document = [this, extension](Profile& profile) {
+ bool programmatic =
+ ProgrammaticallyCheckIfHasOffscreenDocument(*extension, profile);
+ bool in_manager =
+ OffscreenDocumentManager::Get(&profile)
+ ->GetOffscreenDocumentForExtension(*extension) != nullptr;
+ EXPECT_EQ(programmatic, in_manager) << "Mismatch between manager and API.";
+ return programmatic && in_manager;
+ };
+
+ // There's less to do in a spanning mode extension - by definition, we can't
+ // call any methods from an incognito profile, so we just have to verify that
+ // the incognito profile is unaffected.
+ ProgrammaticallyCreateOffscreenDocument(*extension, *profile());
+ EXPECT_TRUE(has_offscreen_document(*profile()));
+ // Don't use `has_offscreen_document()` since we can't actually check the
+ // programmatic status, which requires executing script in an incognito
+ // process.
+ OffscreenDocumentManager* incognito_manager =
+ OffscreenDocumentManager::Get(incognito_profile);
+ EXPECT_EQ(nullptr,
+ incognito_manager->GetOffscreenDocumentForExtension(*extension));
+
+ ProgrammaticallyCloseOffscreenDocument(*extension, *profile());
+ EXPECT_FALSE(has_offscreen_document(*profile()));
+ EXPECT_EQ(nullptr,
+ incognito_manager->GetOffscreenDocumentForExtension(*extension));
+}
+
+class OffscreenApiTestWithoutFeature : public ExtensionApiTest {
+ public:
+ OffscreenApiTestWithoutFeature() = default;
+ ~OffscreenApiTestWithoutFeature() override = default;
+
+ private:
+ ScopedCurrentChannel current_channel_override_{
+ version_info::Channel::UNKNOWN};
+};
+
+// Tests that the `offscreen` API is unavailable if the requisite feature
+// (`ExtensionsOffscreenDocuments`) is not enabled. We have this explicit test
+// mostly to double-check our registration, since features are prone to typos.
+IN_PROC_BROWSER_TEST_F(OffscreenApiTestWithoutFeature,
+ APIUnavailableWithoutFeature) {
+ static constexpr char kManifest[] =
+ R"({
+ "name": "Offscreen Document Test",
+ "manifest_version": 3,
+ "version": "0.1",
+ "permissions": ["offscreen"],
+ "background": { "service_worker": "background.js" }
+ })";
+ // The extension validates the `offscreen` API is undefined.
+ static constexpr char kBackgroundJs[] =
+ R"(chrome.test.runTests([
+ function apiIsUnavailable() {
+ chrome.test.assertEq(undefined, chrome.offscreen);
+ chrome.test.succeed();
+ },
+ ]);)";
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundJs);
+
+ ResultCatcher result_catcher;
+ const Extension* extension = LoadExtension(
+ test_dir.UnpackedPath(), {.ignore_manifest_warnings = true});
+ ASSERT_TRUE(extension);
+
+ EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
+
+ // An install warning should be emitted since the extension requested a
+ // restricted permission.
+ const std::vector<InstallWarning>& install_warnings =
+ extension->install_warnings();
+
+ // Turn our InstallWarnings into strings for easier testing.
+ std::vector<std::string> string_warnings;
+ std::transform(install_warnings.begin(), install_warnings.end(),
+ std::back_inserter(string_warnings),
+ [](const InstallWarning& warning) { return warning.message; });
+
+ static constexpr char kExpectedWarning[] =
+ "'offscreen' requires the 'ExtensionsOffscreenDocuments' feature flag to "
+ "be enabled.";
+ EXPECT_THAT(string_warnings, testing::ElementsAre(kExpectedWarning));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/offscreen/offscreen_document_manager_browsertest.cc b/chromium/chrome/browser/extensions/api/offscreen/offscreen_document_manager_browsertest.cc
new file mode 100644
index 00000000000..c8eb402f93c
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/offscreen/offscreen_document_manager_browsertest.cc
@@ -0,0 +1,315 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/offscreen/offscreen_document_manager.h"
+
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_util.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "extensions/browser/disable_reason.h"
+#include "extensions/browser/extension_host_test_helper.h"
+#include "extensions/browser/extension_util.h"
+#include "extensions/browser/offscreen_document_host.h"
+#include "extensions/browser/test_extension_registry_observer.h"
+#include "extensions/common/extension_features.h"
+#include "extensions/common/mojom/view_type.mojom.h"
+#include "extensions/test/test_extension_dir.h"
+
+namespace extensions {
+
+class OffscreenDocumentManagerBrowserTest : public ExtensionApiTest {
+ public:
+ OffscreenDocumentManagerBrowserTest() {
+ feature_list_.InitAndEnableFeature(
+ extensions_features::kExtensionsOffscreenDocuments);
+ }
+ ~OffscreenDocumentManagerBrowserTest() override = default;
+
+ // Creates a new offscreen document with the given `extension`, `url`,
+ // and `profile`, and waits for it to load.
+ OffscreenDocumentHost* CreateDocumentAndWaitForLoad(
+ const Extension& extension,
+ const GURL& url,
+ Profile& profile) {
+ ExtensionHostTestHelper host_waiter(&profile);
+ host_waiter.RestrictToType(mojom::ViewType::kOffscreenDocument);
+ OffscreenDocumentHost* offscreen_document =
+ OffscreenDocumentManager::Get(&profile)->CreateOffscreenDocument(
+ extension, url);
+ host_waiter.WaitForHostCompletedFirstLoad();
+
+ return offscreen_document;
+ }
+
+ // Same as the above, defaulting to the on-the-record profile.
+ OffscreenDocumentHost* CreateDocumentAndWaitForLoad(
+ const Extension& extension,
+ const GURL& url) {
+ return CreateDocumentAndWaitForLoad(extension, url, *profile());
+ }
+
+ OffscreenDocumentManager* offscreen_document_manager() {
+ return OffscreenDocumentManager::Get(profile());
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+};
+
+// Tests the flow of the OffscreenDocumentManager creating a new offscreen
+// document for an extension.
+IN_PROC_BROWSER_TEST_F(OffscreenDocumentManagerBrowserTest,
+ CreateOffscreenDocument) {
+ static constexpr char kManifest[] =
+ R"({
+ "name": "Offscreen Document Test",
+ "manifest_version": 3,
+ "version": "0.1"
+ })";
+ static constexpr char kOffscreenDocumentHtml[] =
+ R"(<html>
+ <body>
+ <div id="signal">Hello, World</div>
+ </body>
+ </html>)";
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.html"),
+ kOffscreenDocumentHtml);
+
+ // Note: We wrap `extension` in a refptr because we'll unload it later in the
+ // test and need to make sure the object isn't deleted.
+ scoped_refptr<const Extension> extension =
+ LoadExtension(test_dir.UnpackedPath());
+ ASSERT_TRUE(extension);
+
+ // To start, the manager should not have any offscreen documents registered.
+ EXPECT_EQ(nullptr,
+ offscreen_document_manager()->GetOffscreenDocumentForExtension(
+ *extension));
+
+ OffscreenDocumentHost* offscreen_document = nullptr;
+ {
+ // Instruct the manager to create a new offscreen document and wait for it
+ // to load.
+ ExtensionHostTestHelper host_waiter(profile());
+ host_waiter.RestrictToType(mojom::ViewType::kOffscreenDocument);
+ offscreen_document = offscreen_document_manager()->CreateOffscreenDocument(
+ *extension, extension->GetResourceURL("offscreen.html"));
+ ASSERT_TRUE(offscreen_document);
+ host_waiter.WaitForHostCompletedFirstLoad();
+ }
+
+ {
+ // Check the document loaded properly. Note: general capabilities of
+ // offscreen documents are exercised more in the OffscreenDocumentHost
+ // tests, but this helps sanity check that the manager created it properly.
+ static constexpr char kScript[] =
+ R"({
+ let div = document.getElementById('signal');
+ domAutomationController.send(div ? div.innerText : '<no div>');
+ })";
+ std::string result;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+ offscreen_document->host_contents(), kScript, &result));
+ EXPECT_EQ("Hello, World", result);
+ }
+
+ // The manager should now have a record of a document for the extension.
+ EXPECT_EQ(offscreen_document,
+ offscreen_document_manager()->GetOffscreenDocumentForExtension(
+ *extension));
+
+ {
+ // Disable the extension. This causes it to unload, and the offscreen
+ // document should be closed.
+ ExtensionHostTestHelper host_waiter(profile());
+ host_waiter.RestrictToHost(offscreen_document);
+ extension_service()->DisableExtension(extension->id(),
+ disable_reason::DISABLE_USER_ACTION);
+ host_waiter.WaitForHostDestroyed();
+ // Note: `offscreen_document` is destroyed at this point.
+ }
+
+ // There should no longer be a document for the extension.
+ EXPECT_EQ(nullptr,
+ offscreen_document_manager()->GetOffscreenDocumentForExtension(
+ *extension));
+}
+
+// Tests creating offscreen documents for an incognito split-mode extension.
+IN_PROC_BROWSER_TEST_F(OffscreenDocumentManagerBrowserTest,
+ IncognitoOffscreenDocuments) {
+ // `split` incognito mode is required in order to allow the extension to
+ // have a separate process in incognito.
+ static constexpr char kManifest[] =
+ R"({
+ "name": "Offscreen Document Test",
+ "manifest_version": 3,
+ "version": "0.1",
+ "incognito": "split"
+ })";
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.html"),
+ "<html>offscreen</html>");
+
+ scoped_refptr<const Extension> extension =
+ LoadExtension(test_dir.UnpackedPath());
+ ASSERT_TRUE(extension);
+
+ {
+ // Enable the extension in incognito. This results in an extension reload;
+ // wait for that to finish and update the `extension` pointer.
+ TestExtensionRegistryObserver registry_observer(
+ ExtensionRegistry::Get(profile()), extension->id());
+ util::SetIsIncognitoEnabled(extension->id(), browser()->profile(),
+ /*enabled=*/true);
+ extension = registry_observer.WaitForExtensionLoaded();
+ }
+
+ ASSERT_TRUE(extension);
+ ASSERT_TRUE(util::IsIncognitoEnabled(extension->id(), profile()));
+
+ const GURL offscreen_url = extension->GetResourceURL("offscreen.html");
+
+ // Create an on-the-record offscreen document.
+ OffscreenDocumentHost* on_the_record_host =
+ CreateDocumentAndWaitForLoad(*extension, offscreen_url);
+ ASSERT_TRUE(on_the_record_host);
+ // Ensure the on-the-record context is used.
+ // Note: Throughout this test, we use
+ // `OffscreenDocumentHost::host_contents()` to access the BrowserContext
+ // instead of `OffscreenDocumentHost::browser_context()`; this is to ensure
+ // that the WebContents is hosted properly.
+ EXPECT_FALSE(on_the_record_host->host_contents()
+ ->GetBrowserContext()
+ ->IsOffTheRecord());
+
+ // Create an incognito browser and an incognito offscreen document, and
+ // validate that the proper context is used.
+ Browser* incognito_browser = CreateIncognitoBrowser();
+ ASSERT_TRUE(incognito_browser);
+
+ OffscreenDocumentHost* incognito_host = CreateDocumentAndWaitForLoad(
+ *extension, offscreen_url, *incognito_browser->profile());
+ ASSERT_TRUE(incognito_host);
+ EXPECT_TRUE(
+ incognito_host->host_contents()->GetBrowserContext()->IsOffTheRecord());
+
+ // These should be separate offscreen documents and have separate profiles,
+ // but the same original profile.
+ EXPECT_NE(incognito_host, on_the_record_host);
+ EXPECT_EQ(Profile::FromBrowserContext(
+ on_the_record_host->host_contents()->GetBrowserContext()),
+ Profile::FromBrowserContext(
+ incognito_host->host_contents()->GetBrowserContext())
+ ->GetOriginalProfile());
+
+ // Ensure the offscreen documents are registered with the appropriate
+ // context.
+ EXPECT_EQ(on_the_record_host,
+ OffscreenDocumentManager::Get(profile())
+ ->GetOffscreenDocumentForExtension(*extension));
+ EXPECT_EQ(incognito_host,
+ OffscreenDocumentManager::Get(incognito_browser->profile())
+ ->GetOffscreenDocumentForExtension(*extension));
+
+ {
+ // Shut down the incognito browser. The `incognito_host` should be
+ // destroyed.
+ ExtensionHostTestHelper host_waiter(incognito_browser->profile());
+ host_waiter.RestrictToHost(incognito_host);
+ CloseBrowserSynchronously(incognito_browser);
+ host_waiter.WaitForHostDestroyed();
+ // Note: `incognito_host` is destroyed at this point.
+ }
+
+ // The on-the-record document should remain.
+ EXPECT_EQ(on_the_record_host,
+ offscreen_document_manager()->GetOffscreenDocumentForExtension(
+ *extension));
+}
+
+// Tests the flow of closing an existing offscreen document through the
+// manager.
+IN_PROC_BROWSER_TEST_F(OffscreenDocumentManagerBrowserTest,
+ ClosingDocumentThroughTheManager) {
+ static constexpr char kManifest[] =
+ R"({
+ "name": "Offscreen Document Test",
+ "manifest_version": 3,
+ "version": "0.1"
+ })";
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.html"),
+ "<html>offscreen</html>");
+
+ const Extension* extension = LoadExtension(test_dir.UnpackedPath());
+ ASSERT_TRUE(extension);
+
+ const GURL offscreen_url = extension->GetResourceURL("offscreen.html");
+
+ OffscreenDocumentHost* offscreen_document =
+ CreateDocumentAndWaitForLoad(*extension, offscreen_url);
+ ASSERT_TRUE(offscreen_document);
+
+ {
+ ExtensionHostTestHelper host_waiter(profile());
+ host_waiter.RestrictToHost(offscreen_document);
+ offscreen_document_manager()->CloseOffscreenDocumentForExtension(
+ *extension);
+ }
+
+ EXPECT_EQ(nullptr,
+ offscreen_document_manager()->GetOffscreenDocumentForExtension(
+ *extension));
+}
+
+// Tests calling window.close() in an offscreen document closes it (through the
+// manager).
+IN_PROC_BROWSER_TEST_F(OffscreenDocumentManagerBrowserTest,
+ CallingWindowCloseInAnOffscreenDocumentClosesIt) {
+ static constexpr char kManifest[] =
+ R"({
+ "name": "Offscreen Document Test",
+ "manifest_version": 3,
+ "version": "0.1"
+ })";
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.html"),
+ "<html>offscreen</html>");
+
+ scoped_refptr<const Extension> extension =
+ LoadExtension(test_dir.UnpackedPath());
+ ASSERT_TRUE(extension);
+
+ OffscreenDocumentHost* offscreen_document = CreateDocumentAndWaitForLoad(
+ *extension, extension->GetResourceURL("offscreen.html"));
+ ASSERT_TRUE(offscreen_document);
+ EXPECT_EQ(offscreen_document,
+ offscreen_document_manager()->GetOffscreenDocumentForExtension(
+ *extension));
+
+ {
+ // Call window.close() from the offscreen document. This should cause the
+ // manager to close the document, destroying the host.
+ ExtensionHostTestHelper host_waiter(profile());
+ host_waiter.RestrictToHost(offscreen_document);
+ ASSERT_TRUE(content::ExecuteScript(offscreen_document->host_contents(),
+ "window.close();"));
+ host_waiter.WaitForHostDestroyed();
+ }
+
+ EXPECT_EQ(nullptr,
+ offscreen_document_manager()->GetOffscreenDocumentForExtension(
+ *extension));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/omnibox/omnibox_api.cc b/chromium/chrome/browser/extensions/api/omnibox/omnibox_api.cc
index 746cc75b889..39df08f5e0f 100644
--- a/chromium/chrome/browser/extensions/api/omnibox/omnibox_api.cc
+++ b/chromium/chrome/browser/extensions/api/omnibox/omnibox_api.cc
@@ -96,7 +96,7 @@ void ExtensionOmniboxEventRouter::OnInputStarted(
Profile* profile, const std::string& extension_id) {
auto event = std::make_unique<Event>(events::OMNIBOX_ON_INPUT_STARTED,
omnibox::OnInputStarted::kEventName,
- std::vector<base::Value>(), profile);
+ base::Value::List(), profile);
EventRouter::Get(profile)
->DispatchEventToExtension(extension_id, std::move(event));
}
@@ -110,13 +110,13 @@ bool ExtensionOmniboxEventRouter::OnInputChanged(
extension_id, omnibox::OnInputChanged::kEventName))
return false;
- auto args(std::make_unique<base::ListValue>());
- args->Append(input);
- args->Append(suggest_id);
+ base::Value::List args;
+ args.Append(input);
+ args.Append(suggest_id);
- auto event = std::make_unique<Event>(
- events::OMNIBOX_ON_INPUT_CHANGED, omnibox::OnInputChanged::kEventName,
- std::move(*args).TakeListDeprecated(), profile);
+ auto event = std::make_unique<Event>(events::OMNIBOX_ON_INPUT_CHANGED,
+ omnibox::OnInputChanged::kEventName,
+ std::move(args), profile);
event_router->DispatchEventToExtension(extension_id, std::move(event));
return true;
}
@@ -137,18 +137,18 @@ void ExtensionOmniboxEventRouter::OnInputEntered(
extensions::TabHelper::FromWebContents(web_contents)->
active_tab_permission_granter()->GrantIfRequested(extension);
- auto args(std::make_unique<base::ListValue>());
- args->Append(input);
+ base::Value::List args;
+ args.Append(input);
if (disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB)
- args->Append(kForegroundTabDisposition);
+ args.Append(kForegroundTabDisposition);
else if (disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB)
- args->Append(kBackgroundTabDisposition);
+ args.Append(kBackgroundTabDisposition);
else
- args->Append(kCurrentTabDisposition);
+ args.Append(kCurrentTabDisposition);
- auto event = std::make_unique<Event>(
- events::OMNIBOX_ON_INPUT_ENTERED, omnibox::OnInputEntered::kEventName,
- std::move(*args).TakeListDeprecated(), profile);
+ auto event = std::make_unique<Event>(events::OMNIBOX_ON_INPUT_ENTERED,
+ omnibox::OnInputEntered::kEventName,
+ std::move(args), profile);
EventRouter::Get(profile)
->DispatchEventToExtension(extension_id, std::move(event));
@@ -160,7 +160,7 @@ void ExtensionOmniboxEventRouter::OnInputCancelled(
Profile* profile, const std::string& extension_id) {
auto event = std::make_unique<Event>(events::OMNIBOX_ON_INPUT_CANCELLED,
omnibox::OnInputCancelled::kEventName,
- std::vector<base::Value>(), profile);
+ base::Value::List(), profile);
EventRouter::Get(profile)
->DispatchEventToExtension(extension_id, std::move(event));
}
@@ -169,13 +169,12 @@ void ExtensionOmniboxEventRouter::OnDeleteSuggestion(
Profile* profile,
const std::string& extension_id,
const std::string& suggestion_text) {
- auto args(std::make_unique<base::ListValue>());
- args->Append(suggestion_text);
+ base::Value::List args;
+ args.Append(suggestion_text);
- auto event =
- std::make_unique<Event>(events::OMNIBOX_ON_DELETE_SUGGESTION,
- omnibox::OnDeleteSuggestion::kEventName,
- std::move(*args).TakeListDeprecated(), profile);
+ auto event = std::make_unique<Event>(events::OMNIBOX_ON_DELETE_SUGGESTION,
+ omnibox::OnDeleteSuggestion::kEventName,
+ std::move(args), profile);
EventRouter::Get(profile)->DispatchEventToExtension(extension_id,
std::move(event));
diff --git a/chromium/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc b/chromium/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc
index 2921ab41c82..b239bf215b7 100644
--- a/chromium/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/omnibox/omnibox_unittest.cc
@@ -77,7 +77,7 @@ TEST(ExtensionOmniboxTest, DescriptionStylesSimple) {
styles_expected.push_back(ACMatchClassification(9, kNone));
std::unique_ptr<SendSuggestions::Params> params(
- SendSuggestions::Params::Create(list->GetListDeprecated()));
+ SendSuggestions::Params::Create(list->GetList()));
EXPECT_TRUE(params);
ASSERT_FALSE(params->suggest_results.empty());
CompareClassification(styles_expected, StyleTypesToACMatchClassifications(
@@ -109,7 +109,7 @@ TEST(ExtensionOmniboxTest, DescriptionStylesSimple) {
.Build();
std::unique_ptr<SendSuggestions::Params> swapped_params(
- SendSuggestions::Params::Create(swap_list->GetListDeprecated()));
+ SendSuggestions::Params::Create(swap_list->GetList()));
EXPECT_TRUE(swapped_params);
ASSERT_FALSE(swapped_params->suggest_results.empty());
CompareClassification(
@@ -173,7 +173,7 @@ TEST(ExtensionOmniboxTest, DescriptionStylesCombine) {
styles_expected.push_back(ACMatchClassification(9, kMatch | kDim));
std::unique_ptr<SendSuggestions::Params> params(
- SendSuggestions::Params::Create(list->GetListDeprecated()));
+ SendSuggestions::Params::Create(list->GetList()));
EXPECT_TRUE(params);
ASSERT_FALSE(params->suggest_results.empty());
CompareClassification(styles_expected, StyleTypesToACMatchClassifications(
@@ -221,7 +221,7 @@ TEST(ExtensionOmniboxTest, DescriptionStylesCombine) {
.Build();
std::unique_ptr<SendSuggestions::Params> moved_params(
- SendSuggestions::Params::Create(moved_list->GetListDeprecated()));
+ SendSuggestions::Params::Create(moved_list->GetList()));
EXPECT_TRUE(moved_params);
ASSERT_FALSE(moved_params->suggest_results.empty());
CompareClassification(styles_expected, StyleTypesToACMatchClassifications(
@@ -280,7 +280,7 @@ TEST(ExtensionOmniboxTest, DescriptionStylesCombine2) {
styles_expected.push_back(ACMatchClassification(5, kNone));
std::unique_ptr<SendSuggestions::Params> params(
- SendSuggestions::Params::Create(list->GetListDeprecated()));
+ SendSuggestions::Params::Create(list->GetList()));
EXPECT_TRUE(params);
ASSERT_FALSE(params->suggest_results.empty());
CompareClassification(styles_expected, StyleTypesToACMatchClassifications(
@@ -332,7 +332,7 @@ TEST(ExtensionOmniboxTest, DefaultSuggestResult) {
.Build();
std::unique_ptr<SetDefaultSuggestion::Params> params(
- SetDefaultSuggestion::Params::Create(list->GetListDeprecated()));
+ SetDefaultSuggestion::Params::Create(list->GetList()));
EXPECT_TRUE(params);
}
diff --git a/chromium/chrome/browser/extensions/api/omnibox/suggestion_parser.cc b/chromium/chrome/browser/extensions/api/omnibox/suggestion_parser.cc
index 66ea40e725e..33de6e9e538 100644
--- a/chromium/chrome/browser/extensions/api/omnibox/suggestion_parser.cc
+++ b/chromium/chrome/browser/extensions/api/omnibox/suggestion_parser.cc
@@ -140,25 +140,25 @@ void ConstructResultFromValue(
std::move(callback).Run(std::move(result));
};
- if (value_or_error.error) {
- run_callback_with_error(std::move(*value_or_error.error));
+ if (!value_or_error.has_value()) {
+ run_callback_with_error(std::move(value_or_error.error()));
return;
}
- DCHECK(value_or_error.value);
+ DCHECK(value_or_error.has_value());
// From this point on, we hope that everything is valid (e.g., that we don't
// get non-dictionary values or unexpected top-level types. But, if we did,
// emit a generic error.
constexpr char kGenericError[] = "Invalid XML";
- if (!value_or_error.value->is_dict()) {
+ if (!value_or_error->is_dict()) {
run_callback_with_error(kGenericError);
return;
}
std::vector<const base::Value*> entries;
- const base::Value& root_node = *value_or_error.value;
+ const base::Value& root_node = *value_or_error;
if (has_multiple_entries) {
if (!PopulateEntriesFromNode(root_node, &entries)) {
run_callback_with_error(kGenericError);
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 5f25da1f0a2..ae20864acfc 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
@@ -9,32 +9,20 @@
#include <utility>
#include "base/bind.h"
-#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/task/thread_pool.h"
#include "build/chromeos_buildflags.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profiles_state.h"
#include "components/sessions/content/session_tab_helper.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/mhtml_generation_params.h"
#include "extensions/common/extension_messages.h"
#include "extensions/common/permissions/permissions_data.h"
-#if BUILDFLAG(IS_CHROMEOS)
-#include "chrome/browser/chromeos/extensions/public_session_permission_helper.h"
-#include "extensions/common/permissions/api_permission_set.h"
-#endif
-
using content::BrowserThread;
using content::ChildProcessSecurityPolicy;
using content::WebContents;
@@ -51,9 +39,6 @@ const char kTemporaryFileError[] = "Failed to create a temporary file.";
const char kTabClosedError[] = "Cannot find the tab for this request.";
const char kPageCaptureNotAllowed[] =
"Don't have permissions required to capture this page.";
-#if BUILDFLAG(IS_CHROMEOS)
-const char kUserDenied[] = "User denied request.";
-#endif
constexpr base::TaskTraits kCreateTemporaryFileTaskTraits = {
// Requires IO.
base::MayBlock(),
@@ -91,31 +76,6 @@ ExtensionFunction::ResponseAction PageCaptureSaveAsMHTMLFunction::Run() {
params_ = SaveAsMHTML::Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(params_.get());
-#if BUILDFLAG(IS_CHROMEOS)
- // In Public Sessions, extensions (and apps) are force-installed by admin
- // policy so the user does not get a chance to review the permissions for
- // these extensions. This is not acceptable from a security/privacy
- // standpoint, so when an extension uses the PageCapture API for the first
- // time, we show the user a dialog where they can choose whether to allow
- // the extension access to the API.
- // TODO(https://crbug.com/1269409): This bypasses the CanCaptureCurrentPage()
- // check below, which means we don't check certain restrictions.
- if (profiles::ArePublicSessionRestrictionsEnabled()) {
- WebContents* web_contents = GetWebContents();
- if (!web_contents) {
- return RespondNow(Error(kTabClosedError));
- }
-
- permission_helper::HandlePermissionRequest(
- *extension(), {mojom::APIPermissionID::kPageCapture}, web_contents,
- base::BindOnce(
- &PageCaptureSaveAsMHTMLFunction::ResolvePermissionRequest,
- this), // Callback increments refcount.
- permission_helper::PromptFactory());
- return RespondLater();
- }
-#endif
-
std::string error;
if (!CanCaptureCurrentPage(&error)) {
return RespondNow(Error(std::move(error)));
@@ -187,21 +147,6 @@ void PageCaptureSaveAsMHTMLFunction::OnServiceWorkerAck() {
Release(); // Balanced in Run()
}
-#if BUILDFLAG(IS_CHROMEOS)
-void PageCaptureSaveAsMHTMLFunction::ResolvePermissionRequest(
- const PermissionIDSet& allowed_permissions) {
- if (allowed_permissions.ContainsID(
- extensions::mojom::APIPermissionID::kPageCapture)) {
- base::ThreadPool::PostTask(
- FROM_HERE, kCreateTemporaryFileTaskTraits,
- base::BindOnce(&PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile,
- this));
- } else {
- ReturnFailure(kUserDenied);
- }
-}
-#endif
-
void PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile() {
bool success = base::CreateTemporaryFile(&mhtml_path_);
content::GetIOThreadTaskRunner({})->PostTask(
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 09aa6d5a574..c31adf73f03 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
@@ -25,10 +25,6 @@ class WebContents;
namespace extensions {
-#if BUILDFLAG(IS_CHROMEOS)
-class PermissionIDSet;
-#endif
-
class PageCaptureSaveAsMHTMLFunction : public ExtensionFunction {
public:
PageCaptureSaveAsMHTMLFunction();
@@ -51,11 +47,6 @@ class PageCaptureSaveAsMHTMLFunction : public ExtensionFunction {
ResponseAction Run() override;
bool OnMessageReceived(const IPC::Message& message) override;
-#if BUILDFLAG(IS_CHROMEOS)
- // Resolves the API permission request in Public Sessions.
- void ResolvePermissionRequest(const PermissionIDSet& allowed_permissions);
-#endif
-
// Returns whether or not the extension has permission to capture the current
// page. Sets |*error| to an error value on failure.
bool CanCaptureCurrentPage(std::string* error);
diff --git a/chromium/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc b/chromium/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
index 15672ba7592..0a39556adcd 100644
--- a/chromium/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
@@ -4,37 +4,15 @@
#include <atomic>
-#include "base/base_switches.h"
#include "base/command_line.h"
-#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
-#include "chrome/browser/extensions/active_tab_permission_granter.h"
#include "chrome/browser/extensions/api/page_capture/page_capture_api.h"
-#include "chrome/browser/extensions/extension_action_runner.h"
#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/extensions/tab_helper.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/login/login_state/scoped_test_public_session_login_state.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
-#include "content/public/test/test_utils.h"
-#include "extensions/browser/extension_dialog_auto_confirm.h"
-#include "extensions/common/permissions/permission_set.h"
-#include "extensions/common/permissions/permissions_data.h"
-#include "extensions/common/url_pattern_set.h"
-#include "extensions/test/extension_test_message_listener.h"
-#include "extensions/test/result_catcher.h"
#include "net/dns/mock_host_resolver.h"
#include "third_party/blink/public/common/switches.h"
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/login/login_state/login_state.h"
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-
namespace extensions {
using ContextType = ExtensionApiTest::ContextType;
@@ -47,7 +25,7 @@ class PageCaptureSaveAsMHTMLDelegate
}
virtual ~PageCaptureSaveAsMHTMLDelegate() {
- PageCaptureSaveAsMHTMLFunction::SetTestDelegate(NULL);
+ PageCaptureSaveAsMHTMLFunction::SetTestDelegate(nullptr);
}
void OnTemporaryFileCreated(
@@ -130,28 +108,4 @@ IN_PROC_BROWSER_TEST_P(ExtensionPageCaptureApiTest, SaveAsMHTMLWithFileAccess) {
WaitForFileCleanup(&delegate);
}
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-IN_PROC_BROWSER_TEST_P(ExtensionPageCaptureApiTest,
- PublicSessionRequestAllowed) {
- ASSERT_TRUE(StartEmbeddedTestServer());
- PageCaptureSaveAsMHTMLDelegate delegate;
- chromeos::ScopedTestPublicSessionLoginState login_state;
- // Resolve Permission dialog with Allow.
- ScopedTestDialogAutoConfirm auto_confirm(ScopedTestDialogAutoConfirm::ACCEPT);
- ASSERT_TRUE(RunTest("page_capture")) << message_;
- WaitForFileCleanup(&delegate);
-}
-
-IN_PROC_BROWSER_TEST_P(ExtensionPageCaptureApiTest,
- PublicSessionRequestDenied) {
- ASSERT_TRUE(StartEmbeddedTestServer());
- PageCaptureSaveAsMHTMLDelegate delegate;
- chromeos::ScopedTestPublicSessionLoginState login_state;
- // Resolve Permission dialog with Deny.
- ScopedTestDialogAutoConfirm auto_confirm(ScopedTestDialogAutoConfirm::CANCEL);
- ASSERT_TRUE(RunTest("page_capture", "REQUEST_DENIED")) << message_;
- EXPECT_EQ(0, delegate.temp_file_count());
-}
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/OWNERS b/chromium/chrome/browser/extensions/api/passwords_private/OWNERS
index eaa48b0e3d3..53d53538317 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/OWNERS
+++ b/chromium/chrome/browser/extensions/api/passwords_private/OWNERS
@@ -1,2 +1,3 @@
file://chrome/browser/resources/settings/OWNERS
+mamir@chromium.org
vsemeniuk@google.com
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 fcd63f8338a..07031d70233 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
@@ -15,8 +15,11 @@
#include "base/bind.h"
#include "base/containers/flat_set.h"
+#include "base/feature_list.h"
#include "base/memory/ref_counted.h"
+#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/escape.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_task_runner_handle.h"
@@ -26,8 +29,10 @@
#include "chrome/browser/extensions/api/passwords_private/passwords_private_utils.h"
#include "chrome/browser/password_manager/account_password_store_factory.h"
#include "chrome/browser/password_manager/bulk_leak_check_service_factory.h"
+#include "chrome/browser/password_manager/password_scripts_fetcher_factory.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/common/extensions/api/passwords_private.h"
#include "chrome/grit/generated_resources.h"
#include "components/keyed_service/core/service_access_type.h"
@@ -37,11 +42,16 @@
#include "components/password_manager/core/browser/leak_detection/bulk_leak_check.h"
#include "components/password_manager/core/browser/leak_detection/encryption_utils.h"
#include "components/password_manager/core/browser/password_change_success_tracker.h"
+#include "components/password_manager/core/browser/password_feature_manager_impl.h"
#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
+#include "components/password_manager/core/browser/password_scripts_fetcher.h"
#include "components/password_manager/core/browser/ui/credential_utils.h"
#include "components/password_manager/core/browser/ui/insecure_credentials_manager.h"
#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
#include "components/password_manager/core/browser/well_known_change_password_util.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/url_formatter/elide_url.h"
@@ -50,6 +60,7 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/time_format.h"
#include "url/gurl.h"
+#include "url/origin.h"
namespace extensions {
@@ -61,14 +72,17 @@ using password_manager::InsecureType;
using password_manager::LeakCheckCredential;
using password_manager::PasswordChangeSuccessTracker;
using password_manager::PasswordForm;
+using password_manager::PasswordScriptsFetcher;
+using password_manager::metrics_util::PasswordCheckScriptsCacheState;
using ui::TimeFormat;
-using InsecureCredentialsView =
- password_manager::InsecureCredentialsManager::CredentialsView;
using SavedPasswordsView =
password_manager::SavedPasswordsPresenter::SavedPasswordsView;
using State = password_manager::BulkLeakCheckService::State;
+constexpr char kPasswordCheckScriptsCacheStateUmaKey[] =
+ "PasswordManager.BulkCheck.ScriptsCacheState";
+
std::unique_ptr<std::string> GetChangePasswordUrl(const GURL& url) {
return std::make_unique<std::string>(
password_manager::CreateChangePasswordUrl(url).spec());
@@ -179,20 +193,6 @@ std::string FormatElapsedTime(base::Time time) {
TimeFormat::FORMAT_ELAPSED, TimeFormat::LENGTH_LONG, elapsed_time, true));
}
-base::Time GetTimeWhenWasPhishedOrLeaked(const CredentialUIEntry& entry) {
- base::Time compromise_time;
- if (entry.IsLeaked()) {
- compromise_time =
- entry.password_issues.at(InsecureType::kLeaked).create_time;
- }
- if (entry.IsPhished()) {
- compromise_time =
- std::max(compromise_time,
- entry.password_issues.at(InsecureType::kPhished).create_time);
- }
- return compromise_time;
-}
-
api::passwords_private::CompromiseType GetCompromiseType(
const CredentialUIEntry& entry) {
if (entry.IsLeaked() && entry.IsPhished()) {
@@ -235,8 +235,7 @@ void OrderInsecureCredentials(std::vector<CredentialUIEntry>& credentials) {
// |results|. Now sort both groups by their creation date so that most recent
// compromises appear first in both lists.
auto create_time_cmp = [](auto& lhs, auto& rhs) {
- return GetTimeWhenWasPhishedOrLeaked(lhs) >
- GetTimeWhenWasPhishedOrLeaked(rhs);
+ return lhs.GetLastLeakedOrPhishedTime() > rhs.GetLastLeakedOrPhishedTime();
};
std::sort(credentials.begin(), non_phished, create_time_cmp);
std::sort(non_phished, credentials.end(), create_time_cmp);
@@ -246,9 +245,9 @@ api::passwords_private::CompromisedInfo CreateCompromiseInfo(
const CredentialUIEntry& form) {
api::passwords_private::CompromisedInfo compromise_info;
compromise_info.compromise_time =
- GetTimeWhenWasPhishedOrLeaked(form).ToJsTimeIgnoringNull();
+ form.GetLastLeakedOrPhishedTime().ToJsTimeIgnoringNull();
compromise_info.elapsed_time_since_compromise =
- FormatElapsedTime(GetTimeWhenWasPhishedOrLeaked(form));
+ FormatElapsedTime(form.GetLastLeakedOrPhishedTime());
compromise_info.compromise_type = GetCompromiseType(form);
compromise_info.is_muted = IsCredentialMuted(form);
return compromise_info;
@@ -258,8 +257,15 @@ api::passwords_private::CompromisedInfo CreateCompromiseInfo(
PasswordCheckDelegate::PasswordCheckDelegate(
Profile* profile,
- password_manager::SavedPasswordsPresenter* presenter)
+ password_manager::SavedPasswordsPresenter* presenter,
+ IdGenerator<password_manager::CredentialUIEntry,
+ int,
+ password_manager::CredentialUIEntry::Less>* id_generator)
: profile_(profile),
+ password_feature_manager_(
+ std::make_unique<password_manager::PasswordFeatureManagerImpl>(
+ profile->GetPrefs(),
+ SyncServiceFactory::GetForProfile(profile))),
saved_passwords_presenter_(presenter),
insecure_credentials_manager_(presenter,
PasswordStoreFactory::GetForProfile(
@@ -271,33 +277,28 @@ PasswordCheckDelegate::PasswordCheckDelegate(
bulk_leak_check_service_adapter_(
presenter,
BulkLeakCheckServiceFactory::GetForProfile(profile_),
- profile_->GetPrefs()) {
+ profile_->GetPrefs()),
+ id_generator_(id_generator) {
+ DCHECK(id_generator);
observed_saved_passwords_presenter_.Observe(saved_passwords_presenter_.get());
observed_insecure_credentials_manager_.Observe(
&insecure_credentials_manager_);
observed_bulk_leak_check_service_.Observe(
BulkLeakCheckServiceFactory::GetForProfile(profile_));
-
- // Instructs the provider to initialize and build its cache.
- // This will soon after invoke OnCompromisedCredentialsChanged(). Calls to
- // GetCompromisedCredentials() that might happen until then will return an
- // empty list.
- insecure_credentials_manager_.Init();
}
PasswordCheckDelegate::~PasswordCheckDelegate() = default;
-std::vector<api::passwords_private::InsecureCredential>
+std::vector<api::passwords_private::PasswordUiEntry>
PasswordCheckDelegate::GetCompromisedCredentials() {
std::vector<CredentialUIEntry> ordered_credentials =
insecure_credentials_manager_.GetInsecureCredentialEntries();
OrderInsecureCredentials(ordered_credentials);
- std::vector<api::passwords_private::InsecureCredential>
- compromised_credentials;
+ std::vector<api::passwords_private::PasswordUiEntry> compromised_credentials;
compromised_credentials.reserve(ordered_credentials.size());
for (const auto& credential : ordered_credentials) {
- api::passwords_private::InsecureCredential api_credential =
+ api::passwords_private::PasswordUiEntry api_credential =
ConstructInsecureCredential(credential);
api_credential.compromised_info =
std::make_unique<api::passwords_private::CompromisedInfo>(
@@ -308,12 +309,12 @@ PasswordCheckDelegate::GetCompromisedCredentials() {
return compromised_credentials;
}
-std::vector<api::passwords_private::InsecureCredential>
+std::vector<api::passwords_private::PasswordUiEntry>
PasswordCheckDelegate::GetWeakCredentials() {
std::vector<CredentialUIEntry> weak_credentials =
insecure_credentials_manager_.GetWeakCredentialEntries();
- std::vector<api::passwords_private::InsecureCredential> api_credentials;
+ std::vector<api::passwords_private::PasswordUiEntry> api_credentials;
api_credentials.reserve(weak_credentials.size());
for (auto& weak_credential : weak_credentials) {
api_credentials.push_back(ConstructInsecureCredential(weak_credential));
@@ -322,43 +323,8 @@ PasswordCheckDelegate::GetWeakCredentials() {
return api_credentials;
}
-absl::optional<api::passwords_private::InsecureCredential>
-PasswordCheckDelegate::GetPlaintextInsecurePassword(
- api::passwords_private::InsecureCredential credential) const {
- const CredentialUIEntry* entry = FindMatchingEntry(credential);
- if (!entry)
- return absl::nullopt;
-
- credential.password =
- std::make_unique<std::string>(base::UTF16ToUTF8(entry->password));
- return credential;
-}
-
-bool PasswordCheckDelegate::ChangeInsecureCredential(
- const api::passwords_private::InsecureCredential& credential,
- base::StringPiece new_password) {
- // Try to obtain the original CredentialUIEntry. Return false if fails.
- const CredentialUIEntry* entry = FindMatchingEntry(credential);
- if (!entry)
- return false;
-
- CredentialUIEntry credential_to_edit = *entry;
- credential_to_edit.password = base::UTF8ToUTF16(new_password);
- return saved_passwords_presenter_->EditSavedCredentials(credential_to_edit);
-}
-
-bool PasswordCheckDelegate::RemoveInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) {
- // Try to obtain the original CredentialUIEntry. Return false if fails.
- const CredentialUIEntry* entry = FindMatchingEntry(credential);
- if (!entry)
- return false;
-
- return saved_passwords_presenter_->RemoveCredential(*entry);
-}
-
bool PasswordCheckDelegate::MuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) {
+ const api::passwords_private::PasswordUiEntry& credential) {
// Try to obtain the original CredentialUIEntry. Return false if fails.
const CredentialUIEntry* entry = FindMatchingEntry(credential);
if (!entry)
@@ -368,7 +334,7 @@ bool PasswordCheckDelegate::MuteInsecureCredential(
}
bool PasswordCheckDelegate::UnmuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) {
+ const api::passwords_private::PasswordUiEntry& credential) {
// Try to obtain the original CredentialUIEntry. Return false if fails.
const CredentialUIEntry* entry = FindMatchingEntry(credential);
if (!entry)
@@ -380,7 +346,7 @@ bool PasswordCheckDelegate::UnmuteInsecureCredential(
// Records that a change password flow was started for |credential| and
// whether |is_manual_flow| applies to the flow.
void PasswordCheckDelegate::RecordChangePasswordFlowStarted(
- const api::passwords_private::InsecureCredential& credential,
+ const api::passwords_private::PasswordUiEntry& credential,
bool is_manual_flow) {
// If the |credential| does not have a |change_password_url|, skip it.
if (!credential.change_password_url)
@@ -398,6 +364,15 @@ void PasswordCheckDelegate::RecordChangePasswordFlowStarted(
}
}
+void PasswordCheckDelegate::RefreshScriptsIfNecessary(
+ RefreshScriptsIfNecessaryCallback callback) {
+ if (PasswordScriptsFetcher* fetcher = GetPasswordScriptsFetcher()) {
+ fetcher->RefreshScriptsIfNecessary(std::move(callback));
+ return;
+ }
+ std::move(callback).Run();
+}
+
void PasswordCheckDelegate::StartPasswordCheck(
StartPasswordCheckCallback callback) {
// If the delegate isn't initialized yet, enqueue the callback and return
@@ -407,13 +382,61 @@ void PasswordCheckDelegate::StartPasswordCheck(
return;
}
- // Also return early if the check is already running.
- if (bulk_leak_check_service_adapter_.GetBulkLeakCheckState() ==
- State::kRunning) {
+ // Also return early if the check is already running or scripts are fetching.
+ if (are_scripts_fetching_ ||
+ bulk_leak_check_service_adapter_.GetBulkLeakCheckState() ==
+ State::kRunning) {
std::move(callback).Run(State::kRunning);
return;
}
+ // If automated password change from password check in settings is enabled,
+ // we make sure that the cache is warm prior to analyzing passwords.
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kPasswordChange)) {
+ if (GetPasswordScriptsFetcher()->IsCacheStale()) {
+ are_scripts_fetching_ = true;
+ // The UMA metric for a stale cache is recorded on callback.
+ GetPasswordScriptsFetcher()->RefreshScriptsIfNecessary(
+ base::BindOnce(&PasswordCheckDelegate::OnPasswordScriptsFetched,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+ return;
+ }
+ UMA_HISTOGRAM_ENUMERATION(kPasswordCheckScriptsCacheStateUmaKey,
+ PasswordCheckScriptsCacheState::kCacheFresh);
+ }
+
+ // Otherwise, call directly.
+ StartPasswordAnalyses(std::move(callback));
+}
+
+void PasswordCheckDelegate::OnPasswordScriptsFetched(
+ StartPasswordCheckCallback callback) {
+ DCHECK(are_scripts_fetching_);
+ are_scripts_fetching_ = false;
+ if (PasswordsPrivateEventRouter* event_router =
+ PasswordsPrivateEventRouterFactory::GetForProfile(profile_)) {
+ // Only update if at least one credential now has a startable script.
+ std::vector<api::passwords_private::PasswordUiEntry> credentials =
+ GetCompromisedCredentials();
+ if (base::ranges::any_of(
+ credentials,
+ &api::passwords_private::PasswordUiEntry::has_startable_script)) {
+ UMA_HISTOGRAM_ENUMERATION(
+ kPasswordCheckScriptsCacheStateUmaKey,
+ PasswordCheckScriptsCacheState::kCacheStaleAndUiUpdate);
+ event_router->OnCompromisedCredentialsChanged(std::move(credentials));
+ } else {
+ UMA_HISTOGRAM_ENUMERATION(
+ kPasswordCheckScriptsCacheStateUmaKey,
+ PasswordCheckScriptsCacheState::kCacheStaleAndNoUiUpdate);
+ }
+ }
+ StartPasswordAnalyses(std::move(callback));
+}
+
+void PasswordCheckDelegate::StartPasswordAnalyses(
+ StartPasswordCheckCallback callback) {
// Start the weakness check, and notify observers once done.
insecure_credentials_manager_.StartWeakCheck(base::BindOnce(
&PasswordCheckDelegate::RecordAndNotifyAboutCompletedWeakPasswordCheck,
@@ -504,8 +527,7 @@ void PasswordCheckDelegate::OnSavedPasswordsChanged(SavedPasswordsView) {
NotifyPasswordCheckStatusChanged();
}
-void PasswordCheckDelegate::OnInsecureCredentialsChanged(
- InsecureCredentialsView credentials) {
+void PasswordCheckDelegate::OnInsecureCredentialsChanged() {
if (auto* event_router =
PasswordsPrivateEventRouterFactory::GetForProfile(profile_)) {
event_router->OnCompromisedCredentialsChanged(GetCompromisedCredentials());
@@ -553,13 +575,12 @@ void PasswordCheckDelegate::OnCredentialDone(
}
const CredentialUIEntry* PasswordCheckDelegate::FindMatchingEntry(
- const api::passwords_private::InsecureCredential& credential) const {
- const CredentialUIEntry* entry =
- insecure_credential_id_generator_.TryGetKey(credential.id);
+ const api::passwords_private::PasswordUiEntry& credential) const {
+ const CredentialUIEntry* entry = id_generator_->TryGetKey(credential.id);
if (!entry)
return nullptr;
- if (credential.signon_realm != entry->signon_realm ||
+ if (credential.urls.signon_realm != entry->signon_realm ||
credential.username != base::UTF16ToUTF8(entry->username) ||
(credential.password &&
*credential.password != base::UTF16ToUTF8(entry->password))) {
@@ -602,58 +623,61 @@ void PasswordCheckDelegate::NotifyPasswordCheckStatusChanged() {
}
}
-api::passwords_private::InsecureCredential
+api::passwords_private::PasswordUiEntry
PasswordCheckDelegate::ConstructInsecureCredential(
const CredentialUIEntry& entry) {
- api::passwords_private::InsecureCredential api_credential;
+ api::passwords_private::PasswordUiEntry api_credential;
auto facet = password_manager::FacetURI::FromPotentiallyInvalidSpec(
entry.signon_realm);
- if (facet.IsValidAndroidFacetURI()) {
- api_credential.is_android_credential = true;
- // |formatted_orgin|, |detailed_origin| and |change_password_url| need
- // special handling for Android. Here we use affiliation information
- // instead of the origin.
+ api_credential.is_android_credential = facet.IsValidAndroidFacetURI();
+ api_credential.id = id_generator_->GenerateId(entry);
+ api_credential.username = base::UTF16ToUTF8(entry.username);
+ api_credential.urls = CreateUrlCollectionFromCredential(entry);
+ api_credential.stored_in = StoreSetFromCredential(entry);
+ if (api_credential.is_android_credential) {
+ // |change_password_url| need special handling for Android. Here we use
+ // affiliation information instead of the origin.
if (!entry.app_display_name.empty()) {
- api_credential.formatted_origin = entry.app_display_name;
- api_credential.detailed_origin = entry.app_display_name;
api_credential.change_password_url =
GetChangePasswordUrl(GURL(entry.affiliated_web_realm));
- } else {
- // In case no affiliation information could be obtained show the
- // formatted package name to the user. An empty change_password_url will
- // be handled by the frontend, by not including a link in this case.
- api_credential.formatted_origin = l10n_util::GetStringFUTF8(
- IDS_SETTINGS_PASSWORDS_ANDROID_APP,
- base::UTF8ToUTF16(facet.android_package_name()));
- api_credential.detailed_origin = facet.android_package_name();
}
} else {
- api_credential.is_android_credential = false;
- api_credential.formatted_origin =
- base::UTF16ToUTF8(url_formatter::FormatUrl(
- entry.url.GetWithEmptyPath(),
- url_formatter::kFormatUrlOmitDefaults |
- url_formatter::kFormatUrlOmitHTTPS |
- url_formatter::kFormatUrlOmitTrivialSubdomains |
- url_formatter::kFormatUrlTrimAfterHost,
- base::UnescapeRule::SPACES, nullptr, nullptr, nullptr));
- api_credential.detailed_origin =
- base::UTF16ToUTF8(url_formatter::FormatUrlForSecurityDisplay(
- entry.url.GetWithEmptyPath()));
api_credential.change_password_url = GetChangePasswordUrl(entry.url);
}
-
- api_credential.id = insecure_credential_id_generator_.GenerateId(entry);
- api_credential.signon_realm = entry.signon_realm;
- api_credential.username = base::UTF16ToUTF8(entry.username);
-
+ // For the time being, the automated password change is restricted to
+ // compromised credentials. In the future, this requirement may be relaxed.
+ if ((entry.IsPhished() || entry.IsLeaked()) &&
+ IsAutomatedPasswordChangeFromSettingsEnabled() &&
+ !entry.username.empty()) {
+ GURL url = api_credential.is_android_credential
+ ? GURL(entry.affiliated_web_realm)
+ : entry.url;
+ api_credential.has_startable_script =
+ !url.is_empty() && GetPasswordScriptsFetcher()->IsScriptAvailable(
+ url::Origin::Create(entry.url));
+ } else {
+ api_credential.has_startable_script = false;
+ }
return api_credential;
}
PasswordChangeSuccessTracker*
-PasswordCheckDelegate::GetPasswordChangeSuccessTracker() {
+PasswordCheckDelegate::GetPasswordChangeSuccessTracker() const {
return password_manager::PasswordChangeSuccessTrackerFactory::
GetForBrowserContext(profile_);
}
+PasswordScriptsFetcher* PasswordCheckDelegate::GetPasswordScriptsFetcher()
+ const {
+ return PasswordScriptsFetcherFactory::GetForBrowserContext(profile_);
+}
+
+bool PasswordCheckDelegate::IsAutomatedPasswordChangeFromSettingsEnabled()
+ const {
+ return password_feature_manager_
+ ->AreRequirementsForAutomatedPasswordChangeFulfilled() &&
+ base::FeatureList::IsEnabled(
+ password_manager::features::kPasswordChange);
+}
+
} // namespace extensions
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 1280671f85a..484d407a013 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
@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_PASSWORDS_PRIVATE_PASSWORD_CHECK_DELEGATE_H_
#define CHROME_BROWSER_EXTENSIONS_API_PASSWORDS_PRIVATE_PASSWORD_CHECK_DELEGATE_H_
+#include <memory>
+
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/memory/raw_ptr.h"
@@ -28,6 +30,8 @@ class Profile;
namespace password_manager {
class PasswordChangeSuccessTracker;
+class PasswordFeatureManager;
+class PasswordScriptsFetcher;
} // namespace password_manager
namespace extensions {
@@ -45,9 +49,15 @@ class PasswordCheckDelegate
public:
using StartPasswordCheckCallback =
PasswordsPrivateDelegate::StartPasswordCheckCallback;
-
- PasswordCheckDelegate(Profile* profile,
- password_manager::SavedPasswordsPresenter* presenter);
+ using RefreshScriptsIfNecessaryCallback =
+ PasswordsPrivateDelegate::RefreshScriptsIfNecessaryCallback;
+
+ PasswordCheckDelegate(
+ Profile* profile,
+ password_manager::SavedPasswordsPresenter* presenter,
+ IdGenerator<password_manager::CredentialUIEntry,
+ int,
+ password_manager::CredentialUIEntry::Less>* id_generator);
PasswordCheckDelegate(const PasswordCheckDelegate&) = delete;
PasswordCheckDelegate& operator=(const PasswordCheckDelegate&) = delete;
~PasswordCheckDelegate() override;
@@ -55,48 +65,36 @@ class PasswordCheckDelegate
// Obtains information about compromised credentials. This includes the last
// time a check was run, as well as all compromised credentials that are
// present in the password store.
- std::vector<api::passwords_private::InsecureCredential>
+ std::vector<api::passwords_private::PasswordUiEntry>
GetCompromisedCredentials();
// Obtains information about weak credentials.
- std::vector<api::passwords_private::InsecureCredential> GetWeakCredentials();
-
- // Requests the plaintext password for |credential|. If successful, this
- // returns |credential| with its |password| member set. This can fail if no
- // matching insecure credential can be found in the password store.
- absl::optional<api::passwords_private::InsecureCredential>
- GetPlaintextInsecurePassword(
- api::passwords_private::InsecureCredential credential) const;
-
- // Attempts to change the stored password of |credential| to |new_password|.
- // Returns whether the change succeeded.
- bool ChangeInsecureCredential(
- const api::passwords_private::InsecureCredential& credential,
- base::StringPiece new_password);
-
- // Attempts to remove |credential| from the password store. Returns whether
- // the remove succeeded.
- bool RemoveInsecureCredential(
- const api::passwords_private::InsecureCredential& credential);
-
- // Attempts to mute |credential| from the password store. Returns whether
+ std::vector<api::passwords_private::PasswordUiEntry> GetWeakCredentials();
+
+ // Attempts to mute `credential` from the password store. Returns whether
// the mute succeeded.
bool MuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential);
+ const api::passwords_private::PasswordUiEntry& credential);
- // Attempts to unmute |credential| from the password store. Returns whether
+ // Attempts to unmute `credential` from the password store. Returns whether
// the unmute succeeded.
bool UnmuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential);
+ const api::passwords_private::PasswordUiEntry& credential);
- // Records that a change password flow was started for |credential| and
- // whether |is_manual_flow| applies to the flow.
+ // Records that a change password flow was started for `credential` and
+ // whether `is_manual_flow` applies to the flow.
void RecordChangePasswordFlowStarted(
- const api::passwords_private::InsecureCredential& credential,
+ const api::passwords_private::PasswordUiEntry& credential,
bool is_manual_flow);
- // Requests to start a check for insecure passwords. Invokes |callback| once a
- // check is running or the request was stopped via StopPasswordCheck().
+ // Refreshes the cache for automatic password change scripts if that is stale
+ // and runs `callback` once that is complete.
+ void RefreshScriptsIfNecessary(RefreshScriptsIfNecessaryCallback callback);
+
+ // 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.
@@ -119,9 +117,7 @@ class PasswordCheckDelegate
// password_manager::InsecureCredentialsManager::Observer:
// Invokes PasswordsPrivateEventRouter::OnInsecureCredentialsChanged if
// a valid pointer can be obtained.
- void OnInsecureCredentialsChanged(
- password_manager::InsecureCredentialsManager::CredentialsView credentials)
- override;
+ void OnInsecureCredentialsChanged() override;
// password_manager::InsecureCredentialsManager::Observer:
// Invokes PasswordsPrivateEventRouter::OnWeakCredentialsChanged if a valid
@@ -135,13 +131,21 @@ class PasswordCheckDelegate
password_manager::IsLeaked is_leaked) override;
// Tries to find the matching CredentialUIEntry for |credential|. It
- // performs a look-up in |insecure_credential_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.
+ // 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::InsecureCredential& credential) const;
+ const api::passwords_private::PasswordUiEntry& credential) const;
+
+ // Reacts to a refreshed password scripts cache. Checks whether any of the
+ // compromised credentials have a password script and only then calls the
+ // event router to update the frontend.
+ void OnPasswordScriptsFetched(StartPasswordCheckCallback callback);
+
+ // Starts the analyses of whether credentials are compromised and/or weak.
+ // Assumes that `StartPasswordCheck()` was called prior.
+ void StartPasswordAnalyses(StartPasswordCheckCallback callback);
// Invoked when a compromised password check completes. Records the current
// timestamp in `kLastTimePasswordCheckCompleted` pref.
@@ -151,24 +155,36 @@ class PasswordCheckDelegate
// in `last_completed_weak_check_`.
void RecordAndNotifyAboutCompletedWeakPasswordCheck();
- // Tries to notify the PasswordsPrivateEventRouter that the password check
- // status has changed. Invoked after OnSavedPasswordsChanged and
- // OnStateChanged.
+ // Tries to notify the `PasswordsPrivateEventRouter` that the password check
+ // status has changed. Invoked after `OnSavedPasswordsChanged` and
+ // `OnStateChanged`.
void NotifyPasswordCheckStatusChanged();
- // Constructs |InsecureCredential| from |CredentialUIEntry|.
- api::passwords_private::InsecureCredential ConstructInsecureCredential(
+ // Constructs `PasswordUiEntry` from `CredentialUIEntry`.
+ api::passwords_private::PasswordUiEntry ConstructInsecureCredential(
const password_manager::CredentialUIEntry& entry);
- // Obtain a raw pointer to the |PasswordChangeSuccessTracker| associated
- // with |profile_|.
+ // Returns a raw pointer to the `PasswordChangeSuccessTracker` associated
+ // with `profile_`.
password_manager::PasswordChangeSuccessTracker*
- GetPasswordChangeSuccessTracker();
+ GetPasswordChangeSuccessTracker() const;
+
+ // Returns a raw pointer to the `PasswordScriptsFetcher` associated with
+ // `profile_`.
+ password_manager::PasswordScriptsFetcher* GetPasswordScriptsFetcher() const;
+
+ // Returns whether automatic password changes are enabled from settings.
+ bool IsAutomatedPasswordChangeFromSettingsEnabled() const;
// Raw pointer to the underlying profile. Needs to outlive this instance.
raw_ptr<Profile> profile_ = nullptr;
- // Used by |insecure_credentials_manager_| to obtain the list of saved
+ // A password feature manager instance used to determine whether to offer
+ // automated password changes.
+ const std::unique_ptr<password_manager::PasswordFeatureManager>
+ password_feature_manager_;
+
+ // Used by `insecure_credentials_manager_` to obtain the list of saved
// passwords.
raw_ptr<password_manager::SavedPasswordsPresenter>
saved_passwords_presenter_ = nullptr;
@@ -184,45 +200,48 @@ class PasswordCheckDelegate
// when the delegate obtains the list of saved passwords for the first time.
bool is_initialized_ = false;
- // List of callbacks that were passed to StartPasswordCheck() prior to the
+ // 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, or `StopPasswordCheck()` gets invoked before hand.
std::vector<StartPasswordCheckCallback> start_check_callbacks_;
// Remembers the progress of the ongoing check. Null if no check is currently
// running.
base::WeakPtr<PasswordCheckProgress> password_check_progress_;
+ // Remembers whether scripts are fetching right now.
+ bool are_scripts_fetching_ = false;
+
// Remembers whether a password check is running right now.
bool is_check_running_ = false;
// Store when the last weak check was completed.
base::Time last_completed_weak_check_;
- // A scoped observer for |saved_passwords_presenter_|.
+ // A scoped observer for `saved_passwords_presenter_`.
base::ScopedObservation<password_manager::SavedPasswordsPresenter,
password_manager::SavedPasswordsPresenter::Observer>
observed_saved_passwords_presenter_{this};
- // A scoped observer for |insecure_credentials_manager_|.
+ // A scoped observer for `insecure_credentials_manager_`.
base::ScopedObservation<
password_manager::InsecureCredentialsManager,
password_manager::InsecureCredentialsManager::Observer>
observed_insecure_credentials_manager_{this};
- // A scoped observer for the BulkLeakCheckService.
+ // A scoped observer for the `BulkLeakCheckService`.
base::ScopedObservation<
password_manager::BulkLeakCheckServiceInterface,
password_manager::BulkLeakCheckServiceInterface::Observer>
observed_bulk_leak_check_service_{this};
// An id generator for insecure credentials. Required to match
- // api::passwords_private::InsecureCredential instances passed to the UI
- // with the underlying CredentialUIEntry they are based on.
- IdGenerator<password_manager::CredentialUIEntry,
- int,
- password_manager::CredentialUIEntry::Less>
- insecure_credential_id_generator_;
+ // `api::passwords_private::PasswordUiEntry` instances passed to the UI
+ // with the underlying `CredentialUIEntry` they are based on.
+ raw_ptr<IdGenerator<password_manager::CredentialUIEntry,
+ int,
+ password_manager::CredentialUIEntry::Less>>
+ id_generator_;
base::WeakPtrFactory<PasswordCheckDelegate> weak_ptr_factory_{this};
};
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 375950c8f8f..57fe62002de 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
@@ -19,12 +19,17 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
+#include "base/test/gmock_move_support.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router.h"
#include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h"
#include "chrome/browser/password_manager/bulk_leak_check_service_factory.h"
#include "chrome/browser/password_manager/password_manager_test_util.h"
+#include "chrome/browser/password_manager/password_scripts_fetcher_factory.h"
+#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/common/extensions/api/passwords_private.h"
#include "chrome/test/base/testing_profile.h"
#include "components/keyed_service/core/keyed_service.h"
@@ -33,17 +38,22 @@
#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"
#include "components/password_manager/core/browser/mock_password_change_success_tracker.h"
+#include "components/password_manager/core/browser/mock_password_scripts_fetcher.h"
#include "components/password_manager/core/browser/password_change_success_tracker.h"
#include "components/password_manager/core/browser/password_form.h"
+#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/test_password_store.h"
#include "components/password_manager/core/browser/ui/saved_passwords_presenter.h"
#include "components/password_manager/core/browser/well_known_change_password_util.h"
+#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
+#include "components/sync/driver/test_sync_service.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/browser/browser_context.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/event_router.h"
@@ -54,6 +64,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "url/origin.h"
namespace extensions {
@@ -74,22 +85,24 @@ constexpr char16_t kWeakPassword1[] = u"123456";
constexpr char16_t kWeakPassword2[] = u"111111";
using api::passwords_private::CompromisedInfo;
-using api::passwords_private::InsecureCredential;
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::InsecureCredentialTypeFlags;
using password_manager::InsecureType;
using password_manager::InsecurityMetadata;
using password_manager::IsLeaked;
using password_manager::IsMuted;
using password_manager::LeakCheckCredential;
using password_manager::MockPasswordChangeSuccessTracker;
+using password_manager::MockPasswordScriptsFetcher;
using password_manager::PasswordChangeSuccessTracker;
using password_manager::PasswordChangeSuccessTrackerFactory;
using password_manager::PasswordForm;
using password_manager::SavedPasswordsPresenter;
using password_manager::TestPasswordStore;
+using password_manager::metrics_util::PasswordCheckScriptsCacheState;
using password_manager::prefs::kLastTimePasswordCheckCompleted;
using signin::IdentityTestEnvironment;
using ::testing::AllOf;
@@ -101,10 +114,13 @@ using ::testing::IsNull;
using ::testing::Mock;
using ::testing::Pair;
using ::testing::Pointee;
+using ::testing::Return;
using ::testing::UnorderedElementsAre;
using MockStartPasswordCheckCallback =
base::MockCallback<PasswordCheckDelegate::StartPasswordCheckCallback>;
+using MockRefreshScriptsIfNecessaryCallback = base::MockCallback<
+ PasswordsPrivateDelegate::RefreshScriptsIfNecessaryCallback>;
PasswordsPrivateEventRouter* CreateAndUsePasswordsPrivateEventRouter(
Profile* profile) {
@@ -140,6 +156,17 @@ MockPasswordChangeSuccessTracker* CreateAndUsePasswordChangeSuccessTracker(
})));
}
+MockPasswordScriptsFetcher* CreateAndUsePasswordScriptsFetcher(
+ Profile* profile) {
+ return static_cast<MockPasswordScriptsFetcher*>(
+ PasswordScriptsFetcherFactory::GetInstance()
+ ->SetTestingSubclassFactoryAndUse(
+ profile, base::BindRepeating([](content::BrowserContext*) {
+ return std::make_unique<
+ testing::NiceMock<MockPasswordScriptsFetcher>>();
+ })));
+}
+
BulkLeakCheckService* CreateAndUseBulkLeakCheckService(
signin::IdentityManager* identity_manager,
Profile* profile) {
@@ -154,6 +181,13 @@ BulkLeakCheckService* CreateAndUseBulkLeakCheckService(
})));
}
+syncer::TestSyncService* CreateAndUseSyncService(Profile* profile) {
+ return SyncServiceFactory::GetInstance()->SetTestingSubclassFactoryAndUse(
+ profile, base::BindLambdaForTesting([](content::BrowserContext*) {
+ return std::make_unique<syncer::TestSyncService>();
+ }));
+}
+
PasswordForm MakeSavedPassword(base::StringPiece signon_realm,
base::StringPiece16 username,
base::StringPiece16 password = kPassword1,
@@ -196,22 +230,10 @@ PasswordForm MakeSavedAndroidPassword(
return form;
}
-// Creates matcher for a given insecure credential.
-auto ExpectInsecureCredential(
- const std::string& formatted_origin,
- const std::string& detailed_origin,
- const absl::optional<std::string>& change_password_url,
- const std::u16string& username) {
- auto change_password_url_field_matcher =
- change_password_url.has_value()
- ? Field(&InsecureCredential::change_password_url,
- Pointee(change_password_url.value()))
- : Field(&InsecureCredential::change_password_url, IsNull());
- return AllOf(
- Field(&InsecureCredential::formatted_origin, formatted_origin),
- Field(&InsecureCredential::detailed_origin, detailed_origin),
- change_password_url_field_matcher,
- Field(&InsecureCredential::username, base::UTF16ToASCII(username)));
+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.
@@ -228,6 +250,22 @@ auto ExpectCompromisedInfo(
}
// Creates matcher for a given compromised credential
+auto ExpectWeakCredential(
+ const std::string& formatted_origin,
+ const std::string& detailed_origin,
+ const absl::optional<std::string>& change_password_url,
+ const std::u16string& username) {
+ auto change_password_url_field_matcher =
+ change_password_url.has_value()
+ ? Field(&PasswordUiEntry::change_password_url,
+ Pointee(change_password_url.value()))
+ : Field(&PasswordUiEntry::change_password_url, IsNull());
+ return AllOf(Field(&PasswordUiEntry::username, base::UTF16ToASCII(username)),
+ Field(&PasswordUiEntry::urls,
+ ExpectUrls(formatted_origin, detailed_origin)));
+}
+
+// Creates matcher for a given compromised credential
auto ExpectCompromisedCredential(
const std::string& formatted_origin,
const std::string& detailed_origin,
@@ -236,14 +274,30 @@ auto ExpectCompromisedCredential(
base::TimeDelta elapsed_time_since_compromise,
const std::string& elapsed_time_since_compromise_str,
api::passwords_private::CompromiseType compromise_type) {
- return AllOf(ExpectInsecureCredential(formatted_origin, detailed_origin,
- change_password_url, username),
- Field(&InsecureCredential::compromised_info,
+ auto change_password_url_field_matcher =
+ change_password_url.has_value()
+ ? Field(&PasswordUiEntry::change_password_url,
+ Pointee(change_password_url.value()))
+ : Field(&PasswordUiEntry::change_password_url, IsNull());
+ 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,
Pointee(ExpectCompromisedInfo(
elapsed_time_since_compromise,
elapsed_time_since_compromise_str, compromise_type))));
}
+// Creates a simplified matcher that only checks the username name and
+// whether a startable script exists.
+auto ExpectCredentialWithScriptInfo(const std::u16string& username,
+ bool has_startable_script) {
+ return AllOf(
+ Field(&PasswordUiEntry::username, base::UTF16ToASCII(username)),
+ Field(&PasswordUiEntry::has_startable_script, has_startable_script));
+}
+
class PasswordCheckDelegateTest : public ::testing::Test {
public:
PasswordCheckDelegateTest() {
@@ -263,9 +317,18 @@ class PasswordCheckDelegateTest : public ::testing::Test {
MockPasswordChangeSuccessTracker& password_change_success_tracker() {
return *password_change_success_tracker_;
}
+ MockPasswordScriptsFetcher& password_scripts_fetcher() {
+ return *password_scripts_fetcher_;
+ }
+ syncer::TestSyncService& sync_service() { return *sync_service_; }
SavedPasswordsPresenter& presenter() { return presenter_; }
PasswordCheckDelegate& delegate() { return delegate_; }
+ PasswordCheckDelegate CreateDelegate(SavedPasswordsPresenter* presenter) {
+ return PasswordCheckDelegate(&profile_, presenter,
+ &credential_id_generator_);
+ }
+
private:
content::BrowserTaskEnvironment task_env_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
@@ -282,33 +345,21 @@ class PasswordCheckDelegateTest : public ::testing::Test {
CreateAndUseTestPasswordStore(&profile_);
raw_ptr<MockPasswordChangeSuccessTracker> password_change_success_tracker_ =
CreateAndUsePasswordChangeSuccessTracker(&profile_);
+ raw_ptr<MockPasswordScriptsFetcher> password_scripts_fetcher_ =
+ CreateAndUsePasswordScriptsFetcher(&profile_);
+ raw_ptr<syncer::TestSyncService> sync_service_ =
+ CreateAndUseSyncService(&profile_);
+ IdGenerator<password_manager::CredentialUIEntry,
+ int,
+ password_manager::CredentialUIEntry::Less>
+ credential_id_generator_;
SavedPasswordsPresenter presenter_{store_};
- PasswordCheckDelegate delegate_{&profile_, &presenter_};
+ PasswordCheckDelegate delegate_{&profile_, &presenter_,
+ &credential_id_generator_};
};
} // namespace
-TEST_F(PasswordCheckDelegateTest, VerifyCastingOfCompromisedCredentialTypes) {
- static_assert(
- static_cast<int>(api::passwords_private::COMPROMISE_TYPE_NONE) ==
- static_cast<int>(InsecureCredentialTypeFlags::kSecure),
- "");
- static_assert(
- static_cast<int>(api::passwords_private::COMPROMISE_TYPE_LEAKED) ==
- static_cast<int>(InsecureCredentialTypeFlags::kCredentialLeaked),
- "");
- static_assert(
- static_cast<int>(api::passwords_private::COMPROMISE_TYPE_PHISHED) ==
- static_cast<int>(InsecureCredentialTypeFlags::kCredentialPhished),
- "");
- static_assert(
- static_cast<int>(
- api::passwords_private::COMPROMISE_TYPE_PHISHED_AND_LEAKED) ==
- static_cast<int>(InsecureCredentialTypeFlags::kCredentialLeaked |
- InsecureCredentialTypeFlags::kCredentialPhished),
- "");
-}
-
// Verify that GetWeakCredentials() correctly represents weak credentials.
TEST_F(PasswordCheckDelegateTest, GetWeakCredentialsFillsFieldsCorrectly) {
store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kWeakPassword1));
@@ -321,11 +372,12 @@ TEST_F(PasswordCheckDelegateTest, GetWeakCredentialsFillsFieldsCorrectly) {
EXPECT_THAT(
delegate().GetWeakCredentials(),
UnorderedElementsAre(
- ExpectInsecureCredential(
- "example.com", "https://example.com",
+ ExpectWeakCredential(
+ "example.com", "https://example.com/",
"https://example.com/.well-known/change-password", kUsername1),
- ExpectInsecureCredential(
- "Example App", "Example App",
+ ExpectWeakCredential(
+ "Example App",
+ "https://play.google.com/store/apps/details?id=com.example.app",
"https://example.com/.well-known/change-password", kUsername2)));
}
@@ -353,8 +405,8 @@ TEST_F(PasswordCheckDelegateTest, WeakCheckWhenUserSignedOut) {
EXPECT_THAT(
delegate().GetWeakCredentials(),
- ElementsAre(ExpectInsecureCredential(
- "example.com", "https://example.com",
+ ElementsAre(ExpectWeakCredential(
+ "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);
@@ -386,22 +438,22 @@ TEST_F(PasswordCheckDelegateTest, GetCompromisedCredentialsOrders) {
EXPECT_THAT(
delegate().GetCompromisedCredentials(),
ElementsAre(ExpectCompromisedCredential(
- "example.com", "https://example.com",
+ "example.com", "https://example.com/",
"https://example.com/.well-known/change-password",
kUsername2, base::Minutes(2), "2 minutes ago",
api::passwords_private::COMPROMISE_TYPE_PHISHED),
ExpectCompromisedCredential(
- "example.org", "http://www.example.org",
+ "example.org", "http://www.example.org/",
"http://www.example.org/.well-known/change-password",
kUsername1, base::Minutes(4), "4 minutes ago",
api::passwords_private::COMPROMISE_TYPE_PHISHED),
ExpectCompromisedCredential(
- "example.com", "https://example.com",
+ "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),
ExpectCompromisedCredential(
- "example.org", "http://www.example.org",
+ "example.org", "http://www.example.org/",
"http://www.example.org/.well-known/change-password",
kUsername2, base::Minutes(3), "3 minutes ago",
api::passwords_private::COMPROMISE_TYPE_LEAKED)));
@@ -432,22 +484,22 @@ TEST_F(PasswordCheckDelegateTest, GetCompromisedCredentialsHandlesTimes) {
EXPECT_THAT(
delegate().GetCompromisedCredentials(),
ElementsAre(ExpectCompromisedCredential(
- "example.com", "https://example.com",
+ "example.com", "https://example.com/",
"https://example.com/.well-known/change-password",
kUsername1, base::Seconds(59), "Just now",
api::passwords_private::COMPROMISE_TYPE_LEAKED),
ExpectCompromisedCredential(
- "example.com", "https://example.com",
+ "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),
ExpectCompromisedCredential(
- "example.org", "http://www.example.org",
+ "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),
ExpectCompromisedCredential(
- "example.org", "http://www.example.org",
+ "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)));
@@ -483,22 +535,22 @@ TEST_F(PasswordCheckDelegateTest,
delegate().GetCompromisedCredentials(),
ElementsAre(
ExpectCompromisedCredential(
- "example.com", "https://example.com",
+ "example.com", "https://example.com/",
"https://example.com/.well-known/change-password", kUsername1,
base::Minutes(1), "1 minute ago",
api::passwords_private::COMPROMISE_TYPE_PHISHED_AND_LEAKED),
ExpectCompromisedCredential(
- "example.org", "http://www.example.org",
+ "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),
ExpectCompromisedCredential(
- "example.org", "http://www.example.org",
+ "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_PHISHED_AND_LEAKED),
ExpectCompromisedCredential(
- "example.com", "https://example.com",
+ "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)));
@@ -525,20 +577,23 @@ TEST_F(PasswordCheckDelegateTest, GetCompromisedCredentialsInjectsAndroid) {
// password store.
EXPECT_THAT(
delegate().GetCompromisedCredentials(),
- ElementsAre(ExpectCompromisedCredential(
- "Example App", "Example App",
- "https://example.com/.well-known/change-password",
- kUsername2, base::Days(3), "3 days ago",
- api::passwords_private::COMPROMISE_TYPE_PHISHED),
- ExpectCompromisedCredential(
- "App (com.example.app)", "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)));
+ ElementsAre(
+ 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)));
}
// Test that a change to compromised credential notifies observers.
@@ -568,214 +623,6 @@ TEST_F(PasswordCheckDelegateTest, OnGetCompromisedCredentials) {
event_router_observer().events().at(kEventName)->histogram_value);
}
-TEST_F(PasswordCheckDelegateTest, GetPlaintextInsecurePasswordRejectsWrongId) {
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
-
- RunUntilIdle();
-
- InsecureCredential credential =
- std::move(delegate().GetCompromisedCredentials().at(0));
- EXPECT_EQ(0, credential.id);
-
- // Purposefully set a wrong id and verify that trying to get a plaintext
- // password fails.
- credential.id = 1;
- EXPECT_EQ(absl::nullopt,
- delegate().GetPlaintextInsecurePassword(std::move(credential)));
-}
-
-TEST_F(PasswordCheckDelegateTest,
- GetPlaintextInsecurePasswordRejectsWrongSignonRealm) {
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
-
- RunUntilIdle();
- InsecureCredential credential =
- std::move(delegate().GetCompromisedCredentials().at(0));
- EXPECT_EQ(kExampleCom, credential.signon_realm);
-
- // Purposefully set a wrong signon realm and verify that trying to get a
- // plaintext password fails.
- credential.signon_realm = kExampleOrg;
- EXPECT_EQ(absl::nullopt,
- delegate().GetPlaintextInsecurePassword(std::move(credential)));
-}
-
-TEST_F(PasswordCheckDelegateTest,
- GetPlaintextInsecurePasswordRejectsWrongUsername) {
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
- RunUntilIdle();
-
- InsecureCredential credential =
- std::move(delegate().GetCompromisedCredentials().at(0));
- EXPECT_EQ(base::UTF16ToASCII(kUsername1), credential.username);
-
- // Purposefully set a wrong username and verify that trying to get a
- // plaintext password fails.
- credential.signon_realm = base::UTF16ToASCII(kUsername2);
- EXPECT_EQ(absl::nullopt,
- delegate().GetPlaintextInsecurePassword(std::move(credential)));
-}
-
-TEST_F(PasswordCheckDelegateTest,
- GetPlaintextInsecurePasswordReturnsCorrectPassword) {
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
- RunUntilIdle();
-
- InsecureCredential credential =
- std::move(delegate().GetCompromisedCredentials().at(0));
- EXPECT_EQ(0, credential.id);
- EXPECT_EQ(kExampleCom, credential.signon_realm);
- EXPECT_EQ(base::UTF16ToASCII(kUsername1), credential.username);
- EXPECT_EQ(nullptr, credential.password);
-
- absl::optional<InsecureCredential> opt_credential =
- delegate().GetPlaintextInsecurePassword(std::move(credential));
- ASSERT_TRUE(opt_credential.has_value());
- EXPECT_EQ(0, opt_credential->id);
- EXPECT_EQ(kExampleCom, opt_credential->signon_realm);
- EXPECT_EQ(base::UTF16ToASCII(kUsername1), opt_credential->username);
- EXPECT_EQ(base::UTF16ToASCII(kPassword1), *opt_credential->password);
-}
-
-// Test that changing a insecure password fails if the ids don't match.
-TEST_F(PasswordCheckDelegateTest, ChangeInsecureCredentialIdMismatch) {
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
- RunUntilIdle();
-
- InsecureCredential credential =
- std::move(delegate().GetCompromisedCredentials().at(0));
- EXPECT_EQ(0, credential.id);
- credential.id = 1;
-
- EXPECT_FALSE(delegate().ChangeInsecureCredential(credential, "new_pass"));
-}
-
-// Test that changing a insecure password fails if the underlying insecure
-// credential no longer exists.
-TEST_F(PasswordCheckDelegateTest, ChangeInsecureCredentialStaleData) {
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
- RunUntilIdle();
-
- InsecureCredential credential =
- std::move(delegate().GetCompromisedCredentials().at(0));
-
- store().RemoveLogin(form);
- RunUntilIdle();
-
- EXPECT_FALSE(delegate().ChangeInsecureCredential(credential, "new_pass"));
-}
-
-// Test that changing a insecure password succeeds.
-TEST_F(PasswordCheckDelegateTest, ChangeInsecureCredentialSuccess) {
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
- RunUntilIdle();
-
- InsecureCredential credential =
- std::move(delegate().GetCompromisedCredentials().at(0));
- EXPECT_EQ(0, credential.id);
- EXPECT_EQ(kExampleCom, credential.signon_realm);
- EXPECT_EQ(base::UTF16ToASCII(kUsername1), credential.username);
- EXPECT_EQ(kPassword1,
- store().stored_passwords().at(kExampleCom).at(0).password_value);
-
- EXPECT_TRUE(delegate().ChangeInsecureCredential(
- credential, base::UTF16ToASCII(kPassword2)));
- RunUntilIdle();
-
- EXPECT_EQ(kPassword2,
- store().stored_passwords().at(kExampleCom).at(0).password_value);
-}
-
-// Test that changing a insecure password removes duplicates from store.
-// https://crbug.com/1334160
-TEST_F(PasswordCheckDelegateTest,
- DISABLED_ChangeInsecureCredentialRemovesDupes) {
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
-
- PasswordForm duplicate_form = MakeSavedPassword(
- kExampleCom, kUsername1, kPassword1, u"different_element");
- AddIssueToForm(&duplicate_form, InsecureType::kLeaked);
- store().AddLogin(duplicate_form);
-
- RunUntilIdle();
-
- EXPECT_EQ(2u, store().stored_passwords().at(kExampleCom).size());
-
- InsecureCredential credential =
- std::move(delegate().GetCompromisedCredentials().at(0));
- EXPECT_TRUE(delegate().ChangeInsecureCredential(
- credential, base::UTF16ToASCII(kPassword2)));
- RunUntilIdle();
-
- EXPECT_EQ(1u, store().stored_passwords().at(kExampleCom).size());
- EXPECT_EQ(kPassword2,
- store().stored_passwords().at(kExampleCom).at(0).password_value);
-}
-
-// Test that removing a insecure password fails if the ids don't match.
-TEST_F(PasswordCheckDelegateTest, RemoveInsecureCredentialIdMismatch) {
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
- RunUntilIdle();
-
- InsecureCredential credential =
- std::move(delegate().GetCompromisedCredentials().at(0));
- EXPECT_EQ(0, credential.id);
- credential.id = 1;
-
- EXPECT_FALSE(delegate().RemoveInsecureCredential(credential));
-}
-
-// Test that removing a insecure password fails if the underlying insecure
-// credential no longer exists.
-TEST_F(PasswordCheckDelegateTest, RemoveInsecureCredentialStaleData) {
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
- RunUntilIdle();
-
- InsecureCredential credential =
- std::move(delegate().GetCompromisedCredentials().at(0));
- store().RemoveLogin(form);
- RunUntilIdle();
-
- EXPECT_FALSE(delegate().RemoveInsecureCredential(credential));
-}
-
-// Test that removing a insecure password succeeds.
-TEST_F(PasswordCheckDelegateTest, RemoveInsecureCredentialSuccess) {
- PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1);
- AddIssueToForm(&form, InsecureType::kLeaked);
- store().AddLogin(form);
- RunUntilIdle();
-
- InsecureCredential credential =
- std::move(delegate().GetCompromisedCredentials().at(0));
- EXPECT_TRUE(delegate().RemoveInsecureCredential(credential));
- RunUntilIdle();
- EXPECT_TRUE(store().IsEmpty());
-
- // Expect another removal of the same credential to fail.
- EXPECT_FALSE(delegate().RemoveInsecureCredential(credential));
-}
-
// Test that muting a insecure password succeeds.
TEST_F(PasswordCheckDelegateTest, MuteInsecureCredentialSuccess) {
PasswordForm form = MakeSavedPassword(kExampleCom, kUsername1);
@@ -783,7 +630,7 @@ TEST_F(PasswordCheckDelegateTest, MuteInsecureCredentialSuccess) {
store().AddLogin(form);
RunUntilIdle();
- InsecureCredential credential =
+ PasswordUiEntry credential =
std::move(delegate().GetCompromisedCredentials().at(0));
EXPECT_TRUE(delegate().MuteInsecureCredential(credential));
RunUntilIdle();
@@ -806,7 +653,7 @@ TEST_F(PasswordCheckDelegateTest, MuteInsecureCredentialStaleData) {
store().AddLogin(form);
RunUntilIdle();
- InsecureCredential credential =
+ PasswordUiEntry credential =
std::move(delegate().GetCompromisedCredentials().at(0));
store().RemoveLogin(form);
RunUntilIdle();
@@ -821,7 +668,7 @@ TEST_F(PasswordCheckDelegateTest, MuteInsecureCredentialIdMismatch) {
store().AddLogin(form);
RunUntilIdle();
- InsecureCredential credential =
+ PasswordUiEntry credential =
std::move(delegate().GetCompromisedCredentials().at(0));
EXPECT_EQ(0, credential.id);
credential.id = 1;
@@ -836,7 +683,7 @@ TEST_F(PasswordCheckDelegateTest, UnmuteInsecureCredentialSuccess) {
store().AddLogin(form);
RunUntilIdle();
- InsecureCredential credential =
+ PasswordUiEntry credential =
std::move(delegate().GetCompromisedCredentials().at(0));
EXPECT_TRUE(delegate().UnmuteInsecureCredential(credential));
RunUntilIdle();
@@ -859,7 +706,7 @@ TEST_F(PasswordCheckDelegateTest, UnmuteInsecureCredentialStaleData) {
store().AddLogin(form);
RunUntilIdle();
- InsecureCredential credential =
+ PasswordUiEntry credential =
std::move(delegate().GetCompromisedCredentials().at(0));
store().RemoveLogin(form);
RunUntilIdle();
@@ -874,7 +721,7 @@ TEST_F(PasswordCheckDelegateTest, UnmuteInsecureCredentialIdMismatch) {
store().AddLogin(form);
RunUntilIdle();
- InsecureCredential credential =
+ PasswordUiEntry credential =
std::move(delegate().GetCompromisedCredentials().at(0));
EXPECT_EQ(0, credential.id);
credential.id = 1;
@@ -889,7 +736,7 @@ TEST_F(PasswordCheckDelegateTest, RecordChangePasswordFlowStartedManual) {
store().AddLogin(form);
RunUntilIdle();
- InsecureCredential credential =
+ PasswordUiEntry credential =
std::move(delegate().GetCompromisedCredentials().at(0));
ASSERT_EQ(base::UTF16ToASCII(kUsername1), credential.username);
@@ -910,7 +757,7 @@ TEST_F(PasswordCheckDelegateTest, RecordChangePasswordFlowStartedAutomated) {
store().AddLogin(form);
RunUntilIdle();
- InsecureCredential credential =
+ PasswordUiEntry credential =
std::move(delegate().GetCompromisedCredentials().at(0));
ASSERT_EQ(base::UTF16ToASCII(kUsername1), credential.username);
@@ -925,6 +772,18 @@ TEST_F(PasswordCheckDelegateTest, RecordChangePasswordFlowStartedAutomated) {
/*is_manual_flow=*/false);
}
+TEST_F(PasswordCheckDelegateTest, RefreshScriptsIfNecessary) {
+ base::OnceClosure refresh_callback = base::DoNothing();
+ EXPECT_CALL(password_scripts_fetcher(), RefreshScriptsIfNecessary)
+ .WillOnce(MoveArg<0>(&refresh_callback));
+
+ MockRefreshScriptsIfNecessaryCallback callback;
+ delegate().RefreshScriptsIfNecessary(callback.Get());
+
+ EXPECT_CALL(callback, Run);
+ std::move(refresh_callback).Run();
+}
+
TEST_F(PasswordCheckDelegateTest,
RecordChangePasswordFlowStartedForAppWithWebRealm) {
// Create an insecure credential.
@@ -934,7 +793,7 @@ TEST_F(PasswordCheckDelegateTest,
store().AddLogin(form);
RunUntilIdle();
- InsecureCredential credential =
+ PasswordUiEntry credential =
std::move(delegate().GetCompromisedCredentials().at(0));
ASSERT_EQ(base::UTF16ToASCII(kUsername2), credential.username);
@@ -957,7 +816,7 @@ TEST_F(PasswordCheckDelegateTest,
store().AddLogin(form);
RunUntilIdle();
- InsecureCredential credential =
+ PasswordUiEntry credential =
std::move(delegate().GetCompromisedCredentials().at(0));
ASSERT_EQ(base::UTF16ToASCII(kUsername1), credential.username);
@@ -1265,8 +1124,8 @@ TEST_F(PasswordCheckDelegateTest, OnCredentialDoneUpdatesProgress) {
delegate().StartPasswordCheck();
EXPECT_EQ(events::PASSWORDS_PRIVATE_ON_PASSWORD_CHECK_STATUS_CHANGED,
event_iter->second->histogram_value);
- auto status = PasswordCheckStatus::FromValue(
- event_iter->second->event_args->GetListDeprecated().front());
+ auto status =
+ PasswordCheckStatus::FromValue(event_iter->second->event_args.front());
EXPECT_EQ(api::passwords_private::PASSWORD_CHECK_STATE_RUNNING,
status->state);
EXPECT_EQ(0, *status->already_processed);
@@ -1275,8 +1134,8 @@ TEST_F(PasswordCheckDelegateTest, OnCredentialDoneUpdatesProgress) {
static_cast<BulkLeakCheckDelegateInterface*>(service())->OnFinishedCredential(
LeakCheckCredential(kUsername1, kPassword1), IsLeaked(false));
- status = PasswordCheckStatus::FromValue(
- event_iter->second->event_args->GetListDeprecated().front());
+ status =
+ PasswordCheckStatus::FromValue(event_iter->second->event_args.front());
EXPECT_EQ(api::passwords_private::PASSWORD_CHECK_STATE_RUNNING,
status->state);
EXPECT_EQ(2, *status->already_processed);
@@ -1285,8 +1144,8 @@ TEST_F(PasswordCheckDelegateTest, OnCredentialDoneUpdatesProgress) {
static_cast<BulkLeakCheckDelegateInterface*>(service())->OnFinishedCredential(
LeakCheckCredential(kUsername2, kPassword2), IsLeaked(false));
- status = PasswordCheckStatus::FromValue(
- event_iter->second->event_args->GetListDeprecated().front());
+ status =
+ PasswordCheckStatus::FromValue(event_iter->second->event_args.front());
EXPECT_EQ(api::passwords_private::PASSWORD_CHECK_STATE_RUNNING,
status->state);
EXPECT_EQ(4, *status->already_processed);
@@ -1326,7 +1185,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.
SavedPasswordsPresenter new_presenter(&store());
- PasswordCheckDelegate delegate(&profile(), &new_presenter);
+ PasswordCheckDelegate delegate = CreateDelegate(&new_presenter);
new_presenter.Init();
delegate.StartPasswordCheck(callback1.Get());
delegate.StartPasswordCheck(callback2.Get());
@@ -1366,4 +1225,210 @@ TEST_F(PasswordCheckDelegateTest, WellKnownChangePasswordUrl_androidrealm) {
password_manager::kWellKnownChangePasswordPath);
}
+TEST_F(PasswordCheckDelegateTest, HasStartableScript) {
+ base::test::ScopedFeatureList feature_list(
+ password_manager::features::kPasswordChange);
+ base::HistogramTester histogram_tester;
+
+ identity_test_env().MakeAccountAvailable(kTestEmail);
+ // Enable password sync.
+ sync_service().SetActiveDataTypes(syncer::ModelTypeSet(syncer::PASSWORDS));
+
+ // Add two forms, but only one already has a known issue.
+ PasswordForm form1 = MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ AddIssueToForm(&form1, InsecureType::kLeaked);
+ store().AddLogin(form1);
+ const url::Origin origin1 = url::Origin::Create(GURL(kExampleCom));
+
+ PasswordForm form2 = MakeSavedPassword(kExampleOrg, kUsername2, kPassword2);
+ store().AddLogin(form2);
+ const url::Origin origin2 = url::Origin::Create(GURL(kExampleOrg));
+
+ RunUntilIdle();
+
+ EXPECT_CALL(password_scripts_fetcher(), IsScriptAvailable(origin1))
+ .WillOnce(Return(false));
+
+ // Only the form with the known issue shows up and does not have a startable
+ // script.
+ EXPECT_THAT(delegate().GetCompromisedCredentials(),
+ UnorderedElementsAre(ExpectCredentialWithScriptInfo(
+ kUsername1, /*has_startable_script=*/false)));
+
+ // Simulate a stale cache.
+ EXPECT_CALL(password_scripts_fetcher(), IsCacheStale).WillOnce(Return(true));
+
+ base::OnceClosure refresh_callback;
+ EXPECT_CALL(password_scripts_fetcher(), RefreshScriptsIfNecessary)
+ .WillOnce(MoveArg<0>(&refresh_callback));
+
+ MockStartPasswordCheckCallback start_callback1;
+ delegate().StartPasswordCheck(start_callback1.Get());
+
+ // Starting another check will indicate that the first one is still running.
+ MockStartPasswordCheckCallback start_callback2;
+ EXPECT_CALL(start_callback2, Run(BulkLeakCheckService::State::kRunning));
+ delegate().StartPasswordCheck(start_callback2.Get());
+
+ EXPECT_CALL(start_callback1, Run(BulkLeakCheckService::State::kRunning));
+
+ // From now on, always return that scripts are available.
+ EXPECT_CALL(password_scripts_fetcher(), IsScriptAvailable)
+ .WillRepeatedly(Return(true));
+
+ // Signal that scripts are fetched.
+ std::move(refresh_callback).Run();
+
+ static_cast<BulkLeakCheckDelegateInterface*>(service())->OnFinishedCredential(
+ LeakCheckCredential(kUsername1, kPassword1), IsLeaked(true));
+ static_cast<BulkLeakCheckDelegateInterface*>(service())->OnFinishedCredential(
+ LeakCheckCredential(kUsername2, kPassword2), IsLeaked(true));
+ RunUntilIdle();
+
+ EXPECT_THAT(
+ delegate().GetCompromisedCredentials(),
+ UnorderedElementsAre(ExpectCredentialWithScriptInfo(
+ kUsername1, /*has_startable_script=*/true),
+ ExpectCredentialWithScriptInfo(
+ kUsername2, /*has_startable_script=*/true)));
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.BulkCheck.ScriptsCacheState",
+ PasswordCheckScriptsCacheState::kCacheStaleAndUiUpdate, 1);
+}
+
+TEST_F(PasswordCheckDelegateTest, HasStartableScript_SyncDisabled) {
+ base::test::ScopedFeatureList feature_list(
+ password_manager::features::kPasswordChange);
+ base::HistogramTester histogram_tester;
+
+ identity_test_env().MakeAccountAvailable(kTestEmail);
+ // Disable password sync.
+ sync_service().SetActiveDataTypes(syncer::ModelTypeSet());
+
+ PasswordForm form1 = MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ AddIssueToForm(&form1, InsecureType::kLeaked);
+ store().AddLogin(form1);
+ const url::Origin origin1 = url::Origin::Create(GURL(kExampleCom));
+
+ RunUntilIdle();
+
+ EXPECT_CALL(password_scripts_fetcher(), IsScriptAvailable)
+ .WillRepeatedly(Return(true));
+
+ EXPECT_THAT(delegate().GetCompromisedCredentials(),
+ UnorderedElementsAre(ExpectCredentialWithScriptInfo(
+ kUsername1, /*has_startable_script=*/false)));
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.BulkCheck.ScriptsCacheState", 0u);
+}
+
+TEST_F(PasswordCheckDelegateTest, HasStartableScript_FeatureDisabled) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndDisableFeature(
+ password_manager::features::kPasswordChange);
+ base::HistogramTester histogram_tester;
+
+ identity_test_env().MakeAccountAvailable(kTestEmail);
+ // Enable password sync.
+ sync_service().SetActiveDataTypes(syncer::ModelTypeSet(syncer::PASSWORDS));
+
+ PasswordForm form1 = MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ AddIssueToForm(&form1, InsecureType::kLeaked);
+ store().AddLogin(form1);
+ const url::Origin origin1 = url::Origin::Create(GURL(kExampleCom));
+
+ RunUntilIdle();
+
+ EXPECT_CALL(password_scripts_fetcher(), IsScriptAvailable)
+ .WillRepeatedly(Return(true));
+
+ EXPECT_THAT(delegate().GetCompromisedCredentials(),
+ UnorderedElementsAre(ExpectCredentialWithScriptInfo(
+ kUsername1, /*has_startable_script=*/false)));
+ histogram_tester.ExpectTotalCount(
+ "PasswordManager.BulkCheck.ScriptsCacheState", 0u);
+}
+
+TEST_F(PasswordCheckDelegateTest, HasStartableScript_CacheFresh) {
+ base::test::ScopedFeatureList feature_list(
+ password_manager::features::kPasswordChange);
+ base::HistogramTester histogram_tester;
+
+ identity_test_env().MakeAccountAvailable(kTestEmail);
+ // Enable password sync.
+ sync_service().SetActiveDataTypes(syncer::ModelTypeSet(syncer::PASSWORDS));
+
+ PasswordForm form1 = MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ AddIssueToForm(&form1, InsecureType::kLeaked);
+ store().AddLogin(form1);
+ const url::Origin origin1 = url::Origin::Create(GURL(kExampleCom));
+
+ RunUntilIdle();
+
+ EXPECT_CALL(password_scripts_fetcher(), IsCacheStale).WillOnce(Return(false));
+ EXPECT_CALL(password_scripts_fetcher(), RefreshScriptsIfNecessary).Times(0);
+ EXPECT_CALL(password_scripts_fetcher(), IsScriptAvailable)
+ .WillRepeatedly(Return(true));
+
+ delegate().StartPasswordCheck();
+ event_router_observer().ClearEvents();
+
+ RunUntilIdle();
+
+ // Check that no update event was fired.
+ EXPECT_FALSE(base::Contains(
+ event_router_observer().events(),
+ api::passwords_private::OnCompromisedCredentialsChanged::kEventName));
+
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.BulkCheck.ScriptsCacheState",
+ PasswordCheckScriptsCacheState::kCacheFresh, 1);
+}
+
+TEST_F(PasswordCheckDelegateTest,
+ HasStartableScript_CredentialListUpdateAfterScriptsFetched) {
+ base::test::ScopedFeatureList feature_list(
+ password_manager::features::kPasswordChange);
+ base::HistogramTester histogram_tester;
+
+ identity_test_env().MakeAccountAvailable(kTestEmail);
+ // Enable password sync.
+ sync_service().SetActiveDataTypes(syncer::ModelTypeSet(syncer::PASSWORDS));
+
+ PasswordForm form1 = MakeSavedPassword(kExampleCom, kUsername1, kPassword1);
+ AddIssueToForm(&form1, InsecureType::kLeaked);
+ store().AddLogin(form1);
+ const url::Origin origin1 = url::Origin::Create(GURL(kExampleCom));
+
+ RunUntilIdle();
+
+ EXPECT_CALL(password_scripts_fetcher(), IsCacheStale).WillOnce(Return(true));
+ base::OnceClosure refresh_callback;
+ EXPECT_CALL(password_scripts_fetcher(), RefreshScriptsIfNecessary)
+ .WillOnce(MoveArg<0>(&refresh_callback));
+
+ delegate().StartPasswordCheck();
+
+ EXPECT_CALL(password_scripts_fetcher(), IsScriptAvailable)
+ .WillRepeatedly(Return(true));
+
+ event_router_observer().ClearEvents();
+
+ // Signal that scripts are fetched.
+ std::move(refresh_callback).Run();
+ RunUntilIdle();
+
+ // Check that an update event was fired after the scripts were fetched.
+ EXPECT_EQ(events::PASSWORDS_PRIVATE_ON_COMPROMISED_CREDENTIALS_INFO_CHANGED,
+ event_router_observer()
+ .events()
+ .at(api::passwords_private::OnCompromisedCredentialsChanged::
+ kEventName)
+ ->histogram_value);
+ histogram_tester.ExpectUniqueSample(
+ "PasswordManager.BulkCheck.ScriptsCacheState",
+ PasswordCheckScriptsCacheState::kCacheStaleAndUiUpdate, 1);
+}
+
} // namespace extensions
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 8ac904a0f2d..d266eaf8371 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
@@ -22,6 +22,7 @@
#include "components/sync/driver/sync_service.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_function_registry.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace extensions {
@@ -52,15 +53,17 @@ ResponseAction PasswordsPrivateChangeSavedPasswordFunction::Run() {
api::passwords_private::ChangeSavedPassword::Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(parameters);
- if (!GetDelegate(browser_context())
- ->ChangeSavedPassword(parameters->ids, parameters->params)) {
- return RespondNow(Error(
- "Could not change the password. Either the password is empty, the user "
- "is not authenticated, vector of ids is empty or no matching password "
- "could be found at least for one of the ids."));
+ 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(NoArguments());
+ 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."));
}
// PasswordsPrivateRemoveSavedPasswordFunction
@@ -68,16 +71,8 @@ ResponseAction PasswordsPrivateRemoveSavedPasswordFunction::Run() {
auto parameters =
api::passwords_private::RemoveSavedPassword::Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(parameters);
- GetDelegate(browser_context())->RemoveSavedPasswords({parameters->id});
- return RespondNow(NoArguments());
-}
-
-// PasswordsPrivateRemoveSavedPasswordsFunction
-ResponseAction PasswordsPrivateRemoveSavedPasswordsFunction::Run() {
- auto parameters =
- api::passwords_private::RemoveSavedPasswords::Params::Create(args());
- EXTENSION_FUNCTION_VALIDATE(parameters);
- GetDelegate(browser_context())->RemoveSavedPasswords(parameters->ids);
+ GetDelegate(browser_context())
+ ->RemoveSavedPassword(parameters->id, parameters->from_stores);
return RespondNow(NoArguments());
}
@@ -86,16 +81,7 @@ ResponseAction PasswordsPrivateRemovePasswordExceptionFunction::Run() {
auto parameters =
api::passwords_private::RemovePasswordException::Params::Create(args());
EXTENSION_FUNCTION_VALIDATE(parameters);
- GetDelegate(browser_context())->RemovePasswordExceptions({parameters->id});
- return RespondNow(NoArguments());
-}
-
-// PasswordsPrivateRemovePasswordExceptionsFunction
-ResponseAction PasswordsPrivateRemovePasswordExceptionsFunction::Run() {
- auto parameters =
- api::passwords_private::RemovePasswordExceptions::Params::Create(args());
- EXTENSION_FUNCTION_VALIDATE(parameters);
- GetDelegate(browser_context())->RemovePasswordExceptions(parameters->ids);
+ GetDelegate(browser_context())->RemovePasswordException(parameters->id);
return RespondNow(NoArguments());
}
@@ -138,6 +124,40 @@ void PasswordsPrivateRequestPlaintextPasswordFunction::GotPassword(
->id)));
}
+// PasswordsPrivateRequestCredentialDetailsFunction
+ResponseAction PasswordsPrivateRequestCredentialDetailsFunction::Run() {
+ auto parameters =
+ api::passwords_private::RequestCredentialDetails::Params::Create(args());
+ EXTENSION_FUNCTION_VALIDATE(parameters);
+
+ GetDelegate(browser_context())
+ ->RequestCredentialDetails(
+ parameters->id,
+ base::BindOnce(&PasswordsPrivateRequestCredentialDetailsFunction::
+ GotPasswordUiEntry,
+ this),
+ GetSenderWebContents());
+
+ // GotPasswordUiEntry() might have responded before we reach this point.
+ return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+void PasswordsPrivateRequestCredentialDetailsFunction::GotPasswordUiEntry(
+ absl::optional<api::passwords_private::PasswordUiEntry> password_ui_entry) {
+ if (password_ui_entry) {
+ Respond(ArgumentList(
+ api::passwords_private::RequestCredentialDetails::Results::Create(
+ std::move(*password_ui_entry))));
+ return;
+ }
+
+ Respond(Error(base::StringPrintf(
+ "Could not obtain password entry. Either the user is not "
+ "authenticated or no credential with id = %d could be found.",
+ api::passwords_private::RequestCredentialDetails::Params::Create(args())
+ ->id)));
+}
+
// PasswordsPrivateGetSavedPasswordListFunction
ResponseAction PasswordsPrivateGetSavedPasswordListFunction::Run() {
// GetList() can immediately call GotList() (which would Respond() before
@@ -197,8 +217,25 @@ ResponseAction PasswordsPrivateMovePasswordsToAccountFunction::Run() {
// PasswordsPrivateImportPasswordsFunction
ResponseAction PasswordsPrivateImportPasswordsFunction::Run() {
- GetDelegate(browser_context())->ImportPasswords(GetSenderWebContents());
- return RespondNow(NoArguments());
+ auto parameters =
+ api::passwords_private::ImportPasswords::Params::Create(args());
+ EXTENSION_FUNCTION_VALIDATE(parameters);
+ GetDelegate(browser_context())
+ ->ImportPasswords(
+ parameters->to_store,
+ base::BindOnce(
+ &PasswordsPrivateImportPasswordsFunction::ImportRequestCompleted,
+ this),
+ GetSenderWebContents());
+
+ // `ImportRequestCompleted()` might respond before we reach this point.
+ return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+void PasswordsPrivateImportPasswordsFunction::ImportRequestCompleted(
+ const api::passwords_private::ImportResults& result) {
+ Respond(ArgumentList(
+ api::passwords_private::ImportPasswords::Results::Create(result)));
}
// PasswordsPrivateExportPasswordsFunction
@@ -217,7 +254,7 @@ void PasswordsPrivateExportPasswordsFunction::ExportRequestCompleted(
if (error.empty())
Respond(NoArguments());
else
- Error(error);
+ Respond(Error(error));
}
// PasswordsPrivateCancelExportPasswordsFunction
@@ -270,87 +307,6 @@ ResponseAction PasswordsPrivateGetWeakCredentialsFunction::Run() {
GetDelegate(browser_context())->GetWeakCredentials())));
}
-// PasswordsPrivateGetPlaintextInsecurePasswordFunction:
-PasswordsPrivateGetPlaintextInsecurePasswordFunction::
- ~PasswordsPrivateGetPlaintextInsecurePasswordFunction() = default;
-
-ResponseAction PasswordsPrivateGetPlaintextInsecurePasswordFunction::Run() {
- auto parameters =
- api::passwords_private::GetPlaintextInsecurePassword::Params::Create(
- args());
- EXTENSION_FUNCTION_VALIDATE(parameters);
-
- GetDelegate(browser_context())
- ->GetPlaintextInsecurePassword(
- std::move(parameters->credential), parameters->reason,
- GetSenderWebContents(),
- base::BindOnce(&PasswordsPrivateGetPlaintextInsecurePasswordFunction::
- GotCredential,
- this));
-
- // GotCredential() might respond before we reach this point.
- return did_respond() ? AlreadyResponded() : RespondLater();
-}
-
-void PasswordsPrivateGetPlaintextInsecurePasswordFunction::GotCredential(
- absl::optional<api::passwords_private::InsecureCredential> credential) {
- if (!credential) {
- Respond(
- Error("Could not obtain plaintext insecure password. Either the user "
- "is not authenticated or no matching password could be found."));
- return;
- }
-
- Respond(ArgumentList(
- api::passwords_private::GetPlaintextInsecurePassword::Results::Create(
- *credential)));
-}
-
-// PasswordsPrivateChangeInsecureCredentialFunction:
-PasswordsPrivateChangeInsecureCredentialFunction::
- ~PasswordsPrivateChangeInsecureCredentialFunction() = default;
-
-ResponseAction PasswordsPrivateChangeInsecureCredentialFunction::Run() {
- auto parameters =
- api::passwords_private::ChangeInsecureCredential::Params::Create(args());
- EXTENSION_FUNCTION_VALIDATE(parameters);
-
- if (parameters->new_password.empty()) {
- return RespondNow(
- Error("Could not change the insecure credential. The new password "
- "can't be empty."));
- }
-
- if (!GetDelegate(browser_context())
- ->ChangeInsecureCredential(parameters->credential,
- parameters->new_password)) {
- return RespondNow(Error(
- "Could not change the insecure credential. Either the user is not "
- "authenticated or no matching password could be found."));
- }
-
- return RespondNow(NoArguments());
-}
-
-// PasswordsPrivateRemoveInsecureCredentialFunction:
-PasswordsPrivateRemoveInsecureCredentialFunction::
- ~PasswordsPrivateRemoveInsecureCredentialFunction() = default;
-
-ResponseAction PasswordsPrivateRemoveInsecureCredentialFunction::Run() {
- auto parameters =
- api::passwords_private::RemoveInsecureCredential::Params::Create(args());
- EXTENSION_FUNCTION_VALIDATE(parameters);
-
- if (!GetDelegate(browser_context())
- ->RemoveInsecureCredential(parameters->credential)) {
- return RespondNow(
- Error("Could not remove the insecure credential. Probably no matching "
- "password could be found."));
- }
-
- return RespondNow(NoArguments());
-}
-
// PasswordsPrivateMuteInsecureCredentialFunction:
PasswordsPrivateMuteInsecureCredentialFunction::
~PasswordsPrivateMuteInsecureCredentialFunction() = default;
@@ -405,6 +361,24 @@ ResponseAction PasswordsPrivateRecordChangePasswordFlowStartedFunction::Run() {
return RespondNow(NoArguments());
}
+// PasswordsPrivateRefreshScriptsIfNecessaryFunction:
+PasswordsPrivateRefreshScriptsIfNecessaryFunction::
+ ~PasswordsPrivateRefreshScriptsIfNecessaryFunction() = default;
+
+ResponseAction PasswordsPrivateRefreshScriptsIfNecessaryFunction::Run() {
+ GetDelegate(browser_context())
+ ->RefreshScriptsIfNecessary(base::BindOnce(
+ &PasswordsPrivateRefreshScriptsIfNecessaryFunction::OnRefreshed,
+ base::RetainedRef(this)));
+
+ // OnRefreshed() might respond before we reach this point.
+ return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+void PasswordsPrivateRefreshScriptsIfNecessaryFunction::OnRefreshed() {
+ Respond(NoArguments());
+}
+
// PasswordsPrivateStartPasswordCheckFunction:
PasswordsPrivateStartPasswordCheckFunction::
~PasswordsPrivateStartPasswordCheckFunction() = default;
@@ -445,6 +419,35 @@ ResponseAction PasswordsPrivateGetPasswordCheckStatusFunction::Run() {
GetDelegate(browser_context())->GetPasswordCheckStatus())));
}
+// PasswordsPrivateStartAutomatedPasswordChangeFunction:
+PasswordsPrivateStartAutomatedPasswordChangeFunction::
+ ~PasswordsPrivateStartAutomatedPasswordChangeFunction() = default;
+
+ResponseAction PasswordsPrivateStartAutomatedPasswordChangeFunction::Run() {
+ auto parameters =
+ api::passwords_private::StartAutomatedPasswordChange::Params::Create(
+ args());
+ EXTENSION_FUNCTION_VALIDATE(parameters);
+
+ // Forward the call to the delegate.
+ GetDelegate(browser_context())
+ ->StartAutomatedPasswordChange(
+ parameters->credential,
+ base::BindOnce(&PasswordsPrivateStartAutomatedPasswordChangeFunction::
+ OnResultReceived,
+ base::RetainedRef(this)));
+
+ // `OnResultReceived()` might respond before we reach this point.
+ return did_respond() ? AlreadyResponded() : RespondLater();
+}
+
+void PasswordsPrivateStartAutomatedPasswordChangeFunction::OnResultReceived(
+ bool success) {
+ Respond(ArgumentList(
+ api::passwords_private::StartAutomatedPasswordChange::Results::Create(
+ success)));
+}
+
// PasswordsPrivateIsAccountStoreDefaultFunction
ResponseAction PasswordsPrivateIsAccountStoreDefaultFunction::Run() {
return RespondNow(OneArgument(
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 01878f1dc2d..ec17329c1b7 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
@@ -53,18 +53,6 @@ class PasswordsPrivateRemoveSavedPasswordFunction : public ExtensionFunction {
ResponseAction Run() override;
};
-class PasswordsPrivateRemoveSavedPasswordsFunction : public ExtensionFunction {
- public:
- DECLARE_EXTENSION_FUNCTION("passwordsPrivate.removeSavedPasswords",
- PASSWORDSPRIVATE_REMOVESAVEDPASSWORDS)
-
- protected:
- ~PasswordsPrivateRemoveSavedPasswordsFunction() override = default;
-
- // ExtensionFunction overrides.
- ResponseAction Run() override;
-};
-
class PasswordsPrivateRemovePasswordExceptionFunction
: public ExtensionFunction {
public:
@@ -78,19 +66,6 @@ class PasswordsPrivateRemovePasswordExceptionFunction
ResponseAction Run() override;
};
-class PasswordsPrivateRemovePasswordExceptionsFunction
- : public ExtensionFunction {
- public:
- DECLARE_EXTENSION_FUNCTION("passwordsPrivate.removePasswordExceptions",
- PASSWORDSPRIVATE_REMOVEPASSWORDEXCEPTIONS)
-
- protected:
- ~PasswordsPrivateRemovePasswordExceptionsFunction() override = default;
-
- // ExtensionFunction overrides.
- ResponseAction Run() override;
-};
-
class PasswordsPrivateUndoRemoveSavedPasswordOrExceptionFunction
: public ExtensionFunction {
public:
@@ -122,6 +97,23 @@ class PasswordsPrivateRequestPlaintextPasswordFunction
void GotPassword(absl::optional<std::u16string> password);
};
+class PasswordsPrivateRequestCredentialDetailsFunction
+ : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("passwordsPrivate.requestCredentialDetails",
+ PASSWORDSPRIVATE_REQUESTCREDENTIALDETAILS)
+ protected:
+ ~PasswordsPrivateRequestCredentialDetailsFunction() override = default;
+
+ // ExtensionFunction overrides.
+ ResponseAction Run() override;
+
+ private:
+ void GotPasswordUiEntry(
+ absl::optional<api::passwords_private::PasswordUiEntry>
+ password_ui_entry);
+};
+
class PasswordsPrivateGetSavedPasswordListFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("passwordsPrivate.getSavedPasswordList",
@@ -178,6 +170,10 @@ class PasswordsPrivateImportPasswordsFunction : public ExtensionFunction {
// ExtensionFunction overrides.
ResponseAction Run() override;
+
+ private:
+ void ImportRequestCompleted(
+ const api::passwords_private::ImportResults& results);
};
class PasswordsPrivateExportPasswordsFunction : public ExtensionFunction {
@@ -271,49 +267,6 @@ class PasswordsPrivateGetWeakCredentialsFunction : public ExtensionFunction {
ResponseAction Run() override;
};
-class PasswordsPrivateGetPlaintextInsecurePasswordFunction
- : public ExtensionFunction {
- public:
- DECLARE_EXTENSION_FUNCTION("passwordsPrivate.getPlaintextInsecurePassword",
- PASSWORDSPRIVATE_GETPLAINTEXTINSECUREPASSWORD)
-
- protected:
- ~PasswordsPrivateGetPlaintextInsecurePasswordFunction() override;
-
- // ExtensionFunction overrides.
- ResponseAction Run() override;
-
- private:
- void GotCredential(
- absl::optional<api::passwords_private::InsecureCredential> credential);
-};
-
-class PasswordsPrivateChangeInsecureCredentialFunction
- : public ExtensionFunction {
- public:
- DECLARE_EXTENSION_FUNCTION("passwordsPrivate.changeInsecureCredential",
- PASSWORDSPRIVATE_CHANGEINSECURECREDENTIAL)
-
- protected:
- ~PasswordsPrivateChangeInsecureCredentialFunction() override;
-
- // ExtensionFunction overrides.
- ResponseAction Run() override;
-};
-
-class PasswordsPrivateRemoveInsecureCredentialFunction
- : public ExtensionFunction {
- public:
- DECLARE_EXTENSION_FUNCTION("passwordsPrivate.removeInsecureCredential",
- PASSWORDSPRIVATE_REMOVEINSECURECREDENTIAL)
-
- protected:
- ~PasswordsPrivateRemoveInsecureCredentialFunction() override;
-
- // ExtensionFunction overrides.
- ResponseAction Run() override;
-};
-
class PasswordsPrivateMuteInsecureCredentialFunction
: public ExtensionFunction {
public:
@@ -353,6 +306,22 @@ class PasswordsPrivateRecordChangePasswordFlowStartedFunction
ResponseAction Run() override;
};
+class PasswordsPrivateRefreshScriptsIfNecessaryFunction
+ : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("passwordsPrivate.refreshScriptsIfNecessary",
+ PASSWORDSPRIVATE_REFRESHSCRIPTSIFNECESSARY)
+
+ protected:
+ ~PasswordsPrivateRefreshScriptsIfNecessaryFunction() override;
+
+ // ExtensionFunction overrides.
+ ResponseAction Run() override;
+
+ private:
+ void OnRefreshed();
+};
+
class PasswordsPrivateStartPasswordCheckFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("passwordsPrivate.startPasswordCheck",
@@ -393,6 +362,22 @@ class PasswordsPrivateGetPasswordCheckStatusFunction
ResponseAction Run() override;
};
+class PasswordsPrivateStartAutomatedPasswordChangeFunction
+ : public ExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("passwordsPrivate.startAutomatedPasswordChange",
+ PASSWORDSPRIVATE_STARTAUTOMATEDPASSWORDCHANGE)
+
+ protected:
+ ~PasswordsPrivateStartAutomatedPasswordChangeFunction() override;
+
+ // ExtensionFunction overrides.
+ ResponseAction Run() override;
+
+ private:
+ void OnResultReceived(bool success);
+};
+
class PasswordsPrivateIsAccountStoreDefaultFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("passwordsPrivate.isAccountStoreDefault",
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 e7eeb49b55c..f917abed9b2 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
@@ -168,25 +168,12 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
}
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- ChangeSavedPasswordWithOneIncorrectIdFromArrayFails) {
- EXPECT_TRUE(RunPasswordsSubtest(
- "changeSavedPasswordWithOneIncorrectIdFromArrayFails"))
- << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
ChangeSavedPasswordWithEmptyPasswordFails) {
EXPECT_TRUE(RunPasswordsSubtest("changeSavedPasswordWithEmptyPasswordFails"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- ChangeSavedPasswordWithEmptyArrayIdFails) {
- EXPECT_TRUE(RunPasswordsSubtest("changeSavedPasswordWithEmptyArrayIdFails"))
- << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
ChangeSavedPasswordWithNoteSucceeds) {
EXPECT_TRUE(RunPasswordsSubtest("ChangeSavedPasswordWithNoteSucceeds"))
<< message_;
@@ -199,23 +186,11 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
}
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- RemoveAndUndoRemoveSavedPasswordsBatch) {
- EXPECT_TRUE(RunPasswordsSubtest("removeAndUndoRemoveSavedPasswordsBatch"))
- << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
RemoveAndUndoRemovePasswordException) {
EXPECT_TRUE(RunPasswordsSubtest("removeAndUndoRemovePasswordException"))
<< message_;
}
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- RemoveAndUndoRemovePasswordExceptionsBatch) {
- EXPECT_TRUE(RunPasswordsSubtest("removeAndUndoRemovePasswordExceptionsBatch"))
- << message_;
-}
-
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, RequestPlaintextPassword) {
EXPECT_TRUE(RunPasswordsSubtest("requestPlaintextPassword")) << message_;
}
@@ -225,6 +200,15 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, RequestPlaintextPasswordFails) {
EXPECT_TRUE(RunPasswordsSubtest("requestPlaintextPasswordFails")) << message_;
}
+IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, RequestCredentialDetails) {
+ EXPECT_TRUE(RunPasswordsSubtest("requestCredentialDetails")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, RequestCredentialDetailsFails) {
+ ResetPlaintextPassword();
+ EXPECT_TRUE(RunPasswordsSubtest("requestCredentialDetailsFails")) << message_;
+}
+
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetSavedPasswordList) {
EXPECT_TRUE(RunPasswordsSubtest("getSavedPasswordList")) << message_;
}
@@ -272,35 +256,6 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetWeakCredentials) {
EXPECT_TRUE(RunPasswordsSubtest("getWeakCredentials")) << message_;
}
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetPlaintextInsecurePassword) {
- EXPECT_TRUE(RunPasswordsSubtest("getPlaintextInsecurePassword")) << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- GetPlaintextInsecurePasswordFails) {
- ResetPlaintextPassword();
- EXPECT_TRUE(RunPasswordsSubtest("getPlaintextInsecurePasswordFails"))
- << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- ChangeInsecureCredentialWithEmptyPasswordFails) {
- EXPECT_TRUE(
- RunPasswordsSubtest("changeInsecureCredentialWithEmptyPasswordFails"))
- << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, ChangeInsecureCredentialFails) {
- EXPECT_TRUE(RunPasswordsSubtest("changeInsecureCredentialFails")) << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- ChangeInsecureCredentialSucceeds) {
- AddCompromisedCredential(0);
- EXPECT_TRUE(RunPasswordsSubtest("changeInsecureCredentialSucceeds"))
- << message_;
-}
-
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, OptInForAccountStorage) {
SetOptedInForAccountStorage(false);
EXPECT_TRUE(RunPasswordsSubtest("optInForAccountStorage")) << message_;
@@ -311,24 +266,6 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, OptOutForAccountStorage) {
EXPECT_TRUE(RunPasswordsSubtest("optOutForAccountStorage")) << message_;
}
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, RemoveInsecureCredentialFails) {
- EXPECT_TRUE(RunPasswordsSubtest("removeInsecureCredentialFails")) << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- RemoveInsecureCredentialSucceeds) {
- AddCompromisedCredential(0);
- EXPECT_TRUE(RunPasswordsSubtest("removeInsecureCredentialSucceeds"))
- << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
- MuteInsecureCredentialSucceeds) {
- AddCompromisedCredential(0);
- EXPECT_TRUE(RunPasswordsSubtest("muteInsecureCredentialSucceeds"))
- << message_;
-}
-
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, MuteInsecureCredentialFails) {
EXPECT_TRUE(RunPasswordsSubtest("muteInsecureCredentialFails")) << message_;
}
@@ -367,6 +304,10 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
EXPECT_EQ(last_change_flow_url(), "");
}
+IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, RefreshScriptsIfNecessary) {
+ EXPECT_TRUE(RunPasswordsSubtest("refreshScriptsIfNecessary")) << message_;
+}
+
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, StartPasswordCheck) {
set_start_password_check_state(
password_manager::BulkLeakCheckService::State::kRunning);
@@ -393,6 +334,15 @@ IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, GetPasswordCheckStatus) {
EXPECT_TRUE(RunPasswordsSubtest("getPasswordCheckStatus")) << message_;
}
+IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, StartAutomatedPasswordChange) {
+ EXPECT_TRUE(RunPasswordsSubtest("startAutomatedPasswordChange"));
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest,
+ StartAutomatedPasswordChangeWithEmptyUrl) {
+ EXPECT_TRUE(RunPasswordsSubtest("startAutomatedPasswordChangeWithEmptyUrl"));
+}
+
IN_PROC_BROWSER_TEST_F(PasswordsPrivateApiTest, MovePasswordsToAccount) {
EXPECT_TRUE(last_moved_passwords().empty());
EXPECT_TRUE(RunPasswordsSubtest("movePasswordsToAccount")) << 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 6fc2e97c4d3..ef166c70330 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
@@ -12,12 +12,11 @@
#include "base/callback.h"
#include "base/strings/string_piece_forward.h"
-#include "chrome/browser/ui/passwords/settings/password_manager_presenter.h"
-#include "chrome/browser/ui/passwords/settings/password_ui_view.h"
#include "chrome/common/extensions/api/passwords_private.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/password_manager/core/browser/bulk_leak_check_service.h"
#include "components/password_manager/core/browser/ui/export_progress_status.h"
+#include "components/password_manager/core/browser/ui/import_results.h"
#include "components/password_manager/core/browser/ui/insecure_credentials_manager.h"
#include "extensions/browser/extension_function.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -33,14 +32,20 @@ namespace extensions {
// import/export) and to notify listeners when these values have changed.
class PasswordsPrivateDelegate : public KeyedService {
public:
+ using ImportResultsCallback =
+ base::OnceCallback<void(const api::passwords_private::ImportResults&)>;
+
using PlaintextPasswordCallback =
base::OnceCallback<void(absl::optional<std::u16string>)>;
+ using RequestCredentialDetailsCallback = base::OnceCallback<void(
+ absl::optional<api::passwords_private::PasswordUiEntry>)>;
+
+ using RefreshScriptsIfNecessaryCallback = base::OnceClosure;
using StartPasswordCheckCallback =
base::OnceCallback<void(password_manager::BulkLeakCheckService::State)>;
- using PlaintextInsecurePasswordCallback = base::OnceCallback<void(
- absl::optional<api::passwords_private::InsecureCredential>)>;
+ using StartAutomatedPasswordChangeCallback = base::OnceCallback<void(bool)>;
~PasswordsPrivateDelegate() override = default;
@@ -86,17 +91,21 @@ class PasswordsPrivateDelegate : public KeyedService {
// 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.
- virtual bool ChangeSavedPassword(
- const std::vector<int>& ids,
+ // 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;
- // Removes the saved password entries corresponding to the |ids| generated for
- // each entry of the password list. Any invalid id will be ignored.
- virtual void RemoveSavedPasswords(const std::vector<int>& ids) = 0;
+ // Removes the saved password entry corresponding to the |id| in the
+ // specified |from_stores|. Any invalid id will be ignored.
+ virtual void RemoveSavedPassword(
+ int id,
+ api::passwords_private::PasswordStoreSet from_stores) = 0;
- // Removes the password exceptions entries corresponding corresponding to
- // |ids|. Any invalid id will be ignored.
- virtual void RemovePasswordExceptions(const std::vector<int>& ids) = 0;
+ // Removes the password exception entry corresponding to |id|. Any invalid id
+ // will be ignored.
+ virtual void RemovePasswordException(int id) = 0;
// Undoes the last removal of a saved password or exception.
virtual void UndoRemoveSavedPasswordOrException() = 0;
@@ -115,6 +124,20 @@ class PasswordsPrivateDelegate : public KeyedService {
PlaintextPasswordCallback callback,
content::WebContents* web_contents) = 0;
+ // Requests the full PasswordUiEntry (with filled password) with the given id.
+ // Returns the full PasswordUiEntry with |callback|. Returns |absl::nullopt|
+ // if no matching credential with |id| is found.
+ // |id| the id created when going over the list of saved passwords.
+ // |reason| The reason why the full PasswordUiEntry is requested.
+ // |callback| The callback that gets invoked with the PasswordUiEntry if it
+ // could be obtained successfully, or absl::nullopt otherwise.
+ // |web_contents| The web content object used as the UI; will be used to show
+ // an OS-level authentication dialog if necessary.
+ virtual void RequestCredentialDetails(
+ int id,
+ RequestCredentialDetailsCallback callback,
+ content::WebContents* web_contents) = 0;
+
// Moves a list of passwords currently stored on the device to being stored in
// the signed-in, non-syncing Google Account. The result of any password is a
// no-op if any of these is true: |id| is invalid; |id| corresponds to a
@@ -125,7 +148,13 @@ class PasswordsPrivateDelegate : public KeyedService {
// Trigger the password import procedure, allowing the user to select a file
// containing passwords to import.
- virtual void ImportPasswords(content::WebContents* web_contents) = 0;
+ // |to_store|: destination store (Device or Account) for imported passwords.
+ // |results_callback|: Used to communicate the status and summary of the
+ // import process.
+ virtual void ImportPasswords(
+ api::passwords_private::PasswordStoreSet to_store,
+ ImportResultsCallback results_callback,
+ content::WebContents* web_contents) = 0;
// Trigger the password export procedure, allowing the user to save a file
// containing their passwords. |callback| will be called with an error
@@ -155,49 +184,34 @@ class PasswordsPrivateDelegate : public KeyedService {
// Obtains information about compromised credentials. This includes the last
// time a check was run, as well as all compromised credentials that are
// present in the password store.
- virtual std::vector<api::passwords_private::InsecureCredential>
+ virtual std::vector<api::passwords_private::PasswordUiEntry>
GetCompromisedCredentials() = 0;
// Obtains information about weak credentials.
- virtual std::vector<api::passwords_private::InsecureCredential>
+ virtual std::vector<api::passwords_private::PasswordUiEntry>
GetWeakCredentials() = 0;
- // Requests the plaintext password for |credential| due to |reason|. If
- // successful, |callback| gets invoked with the same |credential|, whose
- // |password| field will be set.
- virtual void GetPlaintextInsecurePassword(
- api::passwords_private::InsecureCredential credential,
- api::passwords_private::PlaintextReason reason,
- content::WebContents* web_contents,
- PlaintextInsecurePasswordCallback callback) = 0;
-
- // Attempts to change the stored password of |credential| to |new_password|.
- // Returns whether the change succeeded.
- virtual bool ChangeInsecureCredential(
- const api::passwords_private::InsecureCredential& credential,
- base::StringPiece new_password) = 0;
-
- // Attempts to remove |credential| from the password store. Returns whether
- // the remove succeeded.
- virtual bool RemoveInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) = 0;
-
// Attempts to mute |credential| from the password store. Returns whether
// the mute succeeded.
virtual bool MuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) = 0;
+ const api::passwords_private::PasswordUiEntry& credential) = 0;
// Attempts to unmute |credential| from the password store. Returns whether
// the unmute succeeded.
virtual bool UnmuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) = 0;
+ const api::passwords_private::PasswordUiEntry& credential) = 0;
// Records that a change password flow was started for |credential| and
// whether |is_manual_flow| applies to the flow.
virtual void RecordChangePasswordFlowStarted(
- const api::passwords_private::InsecureCredential& credential,
+ const api::passwords_private::PasswordUiEntry& credential,
bool is_manual_flow) = 0;
+ // Refreshes the cache for automatic password change scripts if that is stale
+ // and runs `callback` once that is complete.
+ virtual void RefreshScriptsIfNecessary(
+ RefreshScriptsIfNecessaryCallback callback) = 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;
@@ -208,6 +222,13 @@ class PasswordsPrivateDelegate : public KeyedService {
virtual api::passwords_private::PasswordCheckStatus
GetPasswordCheckStatus() = 0;
+ // Starts an automated password change flow for `credential` and returns
+ // whether the credential was changed successfully by calling `callback` with
+ // a boolean parameter.
+ virtual void StartAutomatedPasswordChange(
+ const api::passwords_private::PasswordUiEntry& credential,
+ StartAutomatedPasswordChangeCallback callback) = 0;
+
// Returns a pointer to the current instance of InsecureCredentialsManager.
// Needed to get notified when compromised credentials are written out to
// disk, since BulkLeakCheckService does not know about that step.
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 23603d68a95..bb72ab396e3 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
@@ -11,7 +11,6 @@
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/sync_service_factory.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "extensions/browser/extension_system_provider.h"
namespace extensions {
@@ -34,9 +33,7 @@ PasswordsPrivateDelegateFactory*
}
PasswordsPrivateDelegateFactory::PasswordsPrivateDelegateFactory()
- : BrowserContextKeyedServiceFactory(
- "PasswordsPrivateDelegate",
- BrowserContextDependencyManager::GetInstance()) {
+ : ProfileKeyedServiceFactory("PasswordsPrivateDelegate") {
DependsOn(BulkLeakCheckServiceFactory::GetInstance());
DependsOn(PasswordStoreFactory::GetInstance());
DependsOn(SyncServiceFactory::GetInstance());
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 428863cd748..9f1bea53fc4 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
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_EXTENSIONS_API_PASSWORDS_PRIVATE_PASSWORDS_PRIVATE_DELEGATE_FACTORY_H_
#include "base/no_destructor.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
namespace context {
class BrowserContext;
@@ -16,8 +16,7 @@ namespace extensions {
class PasswordsPrivateDelegate;
// Factory for creating PasswordPrivateDelegates.
-class PasswordsPrivateDelegateFactory
- : public BrowserContextKeyedServiceFactory {
+class PasswordsPrivateDelegateFactory : public ProfileKeyedServiceFactory {
public:
static PasswordsPrivateDelegate* GetForBrowserContext(
content::BrowserContext* browser_context,
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 03245145449..0835cea9506 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
@@ -10,44 +10,51 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/check.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
#include "base/notreached.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
+#include "chrome/browser/autofill_assistant/password_change/apc_client.h"
#include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router.h"
#include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h"
#include "chrome/browser/password_manager/account_password_store_factory.h"
#include "chrome/browser/password_manager/chrome_password_manager_client.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/sync/sync_service_factory.h"
-#include "chrome/browser/ui/passwords/ui_utils.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/common/extensions/api/passwords_private.h"
-#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "components/keyed_service/core/service_access_type.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
+#include "components/password_manager/core/browser/move_password_to_account_store_helper.h"
#include "components/password_manager/core/browser/password_form.h"
-#include "components/password_manager/core/browser/password_list_sorter.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_ui_utils.h"
-#include "components/password_manager/core/browser/ui/plaintext_reason.h"
+#include "components/password_manager/core/browser/password_sync_util.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_metrics.h"
+#include "components/sync/driver/sync_service.h"
+#include "components/url_formatter/elide_url.h"
+#include "content/public/browser/navigation_handle.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"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
+#include "url/scheme_host_port.h"
#if BUILDFLAG(IS_WIN)
#include "chrome/browser/password_manager/password_manager_util_win.h"
#endif
#if BUILDFLAG(IS_MAC)
+#include "chrome/browser/device_reauth/chrome_biometric_authenticator_factory.h"
#include "chrome/browser/password_manager/password_manager_util_mac.h"
#endif
@@ -57,6 +64,8 @@
namespace {
+using password_manager::CredentialUIEntry;
+
// The error message returned to the UI when Chrome refuses to start multiple
// exports.
const char kExportInProgress[] = "in-progress";
@@ -107,35 +116,94 @@ password_manager::ReauthPurpose GetReauthPurpose(
return password_manager::ReauthPurpose::VIEW_PASSWORD;
}
-password_manager::PlaintextReason ConvertPlaintextReason(
+password_manager::metrics_util::AccessPasswordInSettingsEvent
+ConvertPlaintextReason(
extensions::api::passwords_private::PlaintextReason reason) {
switch (reason) {
- case extensions::api::passwords_private::PLAINTEXT_REASON_VIEW:
- return password_manager::PlaintextReason::kView;
case extensions::api::passwords_private::PLAINTEXT_REASON_COPY:
- return password_manager::PlaintextReason::kCopy;
+ return password_manager::metrics_util::ACCESS_PASSWORD_COPIED;
+ case extensions::api::passwords_private::PLAINTEXT_REASON_VIEW:
+ return password_manager::metrics_util::ACCESS_PASSWORD_VIEWED;
case extensions::api::passwords_private::PLAINTEXT_REASON_EDIT:
- return password_manager::PlaintextReason::kEdit;
+ return password_manager::metrics_util::ACCESS_PASSWORD_EDITED;
case extensions::api::passwords_private::PLAINTEXT_REASON_NONE:
- break;
+ NOTREACHED();
+ return password_manager::metrics_util::ACCESS_PASSWORD_VIEWED;
}
+}
+base::flat_set<password_manager::PasswordForm::Store>
+ConvertToPasswordFormStores(
+ extensions::api::passwords_private::PasswordStoreSet store) {
+ switch (store) {
+ case extensions::api::passwords_private::
+ PASSWORD_STORE_SET_DEVICE_AND_ACCOUNT:
+ return {password_manager::PasswordForm::Store::kProfileStore,
+ password_manager::PasswordForm::Store::kAccountStore};
+ case extensions::api::passwords_private::PASSWORD_STORE_SET_DEVICE:
+ return {password_manager::PasswordForm::Store::kProfileStore};
+ case extensions::api::passwords_private::PASSWORD_STORE_SET_ACCOUNT:
+ return {password_manager::PasswordForm::Store::kAccountStore};
+ default:
+ break;
+ }
NOTREACHED();
- return password_manager::PlaintextReason::kView;
+ return {};
}
-// Gets all the existing keys in |generator| corresponding to |ids|. If no key
-// is found for an id, it is simply ignored.
-std::vector<std::string> GetSortKeys(
- const extensions::IdGenerator<std::string>& generator,
- const std::vector<int> ids) {
- std::vector<std::string> sort_keys;
- sort_keys.reserve(ids.size());
- for (int id : ids) {
- if (const std::string* sort_key = generator.TryGetKey(id))
- sort_keys.emplace_back(*sort_key);
+extensions::api::passwords_private::PasswordUiEntry
+CreatePasswordUiEntryFromCredentialUiEntry(
+ int id,
+ const CredentialUIEntry& credential) {
+ extensions::api::passwords_private::PasswordUiEntry entry;
+ entry.urls = extensions::CreateUrlCollectionFromCredential(credential);
+ entry.username = base::UTF16ToUTF8(credential.username);
+ // TODO(crbug.com/1345899): Fill the note field after authentication in
+ // OnRequestCredentialDetailsAuthResult
+ entry.note =
+ std::make_unique<std::string>(base::UTF16ToUTF8(credential.note.value));
+ entry.id = id;
+ entry.stored_in = extensions::StoreSetFromCredential(credential);
+ entry.is_android_credential =
+ password_manager::IsValidAndroidFacetURI(credential.signon_realm);
+ if (!credential.federation_origin.opaque()) {
+ std::u16string formatted_origin =
+ url_formatter::FormatOriginForSecurityDisplay(
+ credential.federation_origin,
+ url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);
+
+ entry.federation_text =
+ std::make_unique<std::string>(l10n_util::GetStringFUTF8(
+ IDS_PASSWORDS_VIA_FEDERATION, formatted_origin));
}
- return sort_keys;
+ return entry;
+}
+
+extensions::api::passwords_private::ImportEntry ConvertImportEntry(
+ const password_manager::ImportEntry& entry) {
+ extensions::api::passwords_private::ImportEntry result;
+ result.status =
+ static_cast<extensions::api::passwords_private::ImportEntryStatus>(
+ entry.status);
+ result.url = entry.url;
+ result.username = entry.username;
+ return result;
+}
+
+// Maps password_manager::ImportResults to
+// extensions::api::passwords_private::ImportResults.
+extensions::api::passwords_private::ImportResults ConvertImportResults(
+ const password_manager::ImportResults& results) {
+ extensions::api::passwords_private::ImportResults private_results;
+ private_results.status =
+ static_cast<extensions::api::passwords_private::ImportResultsStatus>(
+ results.status);
+ private_results.number_imported = results.number_imported;
+ private_results.file_name = results.file_name;
+ private_results.failed_imports.reserve(results.failed_imports.size());
+ for (const auto& entry : results.failed_imports)
+ private_results.failed_imports.emplace_back(ConvertImportEntry(entry));
+ return private_results;
}
} // namespace
@@ -144,8 +212,6 @@ namespace extensions {
PasswordsPrivateDelegateImpl::PasswordsPrivateDelegateImpl(Profile* profile)
: profile_(profile),
- password_manager_presenter_(
- std::make_unique<PasswordManagerPresenter>(this)),
saved_passwords_presenter_(PasswordStoreFactory::GetForProfile(
profile,
ServiceAccessType::EXPLICIT_ACCESS),
@@ -153,13 +219,17 @@ PasswordsPrivateDelegateImpl::PasswordsPrivateDelegateImpl(Profile* profile)
profile,
ServiceAccessType::EXPLICIT_ACCESS)),
password_manager_porter_(std::make_unique<PasswordManagerPorter>(
+ profile,
&saved_passwords_presenter_,
base::BindRepeating(
&PasswordsPrivateDelegateImpl::OnPasswordsExportProgress,
base::Unretained(this)))),
password_access_authenticator_(
base::BindRepeating(&PasswordsPrivateDelegateImpl::OsReauthCall,
- base::Unretained(this))),
+ base::Unretained(this)),
+ base::BindRepeating(
+ &PasswordsPrivateDelegateImpl::OsReauthTimeoutCall,
+ base::Unretained(this))),
password_account_storage_settings_watcher_(
std::make_unique<
password_manager::PasswordAccountStorageSettingsWatcher>(
@@ -168,23 +238,18 @@ PasswordsPrivateDelegateImpl::PasswordsPrivateDelegateImpl(Profile* profile)
base::BindRepeating(&PasswordsPrivateDelegateImpl::
OnAccountStorageOptInStateChanged,
base::Unretained(this)))),
- password_check_delegate_(profile, &saved_passwords_presenter_),
+ password_check_delegate_(profile,
+ &saved_passwords_presenter_,
+ &credential_id_generator_),
current_entries_initialized_(false),
- current_exceptions_initialized_(false),
is_initialized_(false),
web_contents_(nullptr) {
- password_manager_presenter_->Initialize();
- password_manager_presenter_->UpdatePasswordLists();
+ saved_passwords_presenter_.AddObserver(this);
saved_passwords_presenter_.Init();
}
-PasswordsPrivateDelegateImpl::~PasswordsPrivateDelegateImpl() {}
-
-void PasswordsPrivateDelegateImpl::SendSavedPasswordsList() {
- PasswordsPrivateEventRouter* router =
- PasswordsPrivateEventRouterFactory::GetForProfile(profile_);
- if (router)
- router->OnSavedPasswordsListChanged(current_entries_);
+PasswordsPrivateDelegateImpl::~PasswordsPrivateDelegateImpl() {
+ saved_passwords_presenter_.RemoveObserver(this);
}
void PasswordsPrivateDelegateImpl::GetSavedPasswordsList(
@@ -195,16 +260,9 @@ void PasswordsPrivateDelegateImpl::GetSavedPasswordsList(
get_saved_passwords_list_callbacks_.push_back(std::move(callback));
}
-void PasswordsPrivateDelegateImpl::SendPasswordExceptionsList() {
- PasswordsPrivateEventRouter* router =
- PasswordsPrivateEventRouterFactory::GetForProfile(profile_);
- if (router)
- router->OnPasswordExceptionsListChanged(current_exceptions_);
-}
-
void PasswordsPrivateDelegateImpl::GetPasswordExceptionsList(
ExceptionEntriesCallback callback) {
- if (current_exceptions_initialized_)
+ if (current_entries_initialized_)
std::move(callback).Run(current_exceptions_);
else
get_password_exception_list_callbacks_.push_back(std::move(callback));
@@ -237,83 +295,94 @@ bool PasswordsPrivateDelegateImpl::AddPassword(
const std::u16string& note,
bool use_account_store,
content::WebContents* web_contents) {
- password_manager::PasswordForm form;
- form.url = password_manager_util::StripAuthAndParams(
+ password_manager::PasswordForm::Store store_to_use =
+ use_account_store ? password_manager::PasswordForm::Store::kAccountStore
+ : password_manager::PasswordForm::Store::kProfileStore;
+ CredentialUIEntry credential;
+ credential.url = password_manager_util::StripAuthAndParams(
password_manager_util::ConstructGURLWithScheme(url));
- form.signon_realm = password_manager::GetSignonRealm(form.url);
- form.username_value = username;
- form.password_value = password;
- form.notes.emplace_back(/*value=*/note, /*date_created=*/base::Time::Now());
- form.in_store = use_account_store
- ? password_manager::PasswordForm::Store::kAccountStore
- : password_manager::PasswordForm::Store::kProfileStore;
- form.type = password_manager::PasswordForm::Type::kManuallyAdded;
- bool success = saved_passwords_presenter_.AddPassword(form);
+ credential.signon_realm = password_manager::GetSignonRealm(credential.url);
+ credential.username = username;
+ credential.password = password;
+ credential.note = password_manager::PasswordNote(
+ /*value=*/note, /*date_created=*/base::Time::Now());
+ credential.stored_in = {store_to_use};
+ bool success = saved_passwords_presenter_.AddCredential(credential);
auto* client = ChromePasswordManagerClient::FromWebContents(web_contents);
DCHECK(client);
// Update the default store to the last used one.
if (success &&
client->GetPasswordFeatureManager()->IsOptedInForAccountStorage()) {
- client->GetPasswordFeatureManager()->SetDefaultPasswordStore(form.in_store);
+ client->GetPasswordFeatureManager()->SetDefaultPasswordStore(store_to_use);
}
return success;
}
-bool PasswordsPrivateDelegateImpl::ChangeSavedPassword(
- const std::vector<int>& ids,
+absl::optional<int> PasswordsPrivateDelegateImpl::ChangeSavedPassword(
+ int id,
const api::passwords_private::ChangeSavedPasswordParams& params) {
- const std::vector<std::string> sort_keys =
- GetSortKeys(password_id_generator_, ids);
-
- DCHECK(!sort_keys.empty());
- if (ids.empty() || sort_keys.size() != ids.size())
- return false;
-
- std::vector<password_manager::PasswordForm> forms_to_change;
-
- for (const auto& key : sort_keys) {
- auto forms_for_key = password_manager_presenter_->GetPasswordsForKey(key);
- if (forms_for_key.empty())
- return false;
- for (const auto& form : forms_for_key)
- forms_to_change.push_back(*form);
- }
+ const CredentialUIEntry* original_credential =
+ credential_id_generator_.TryGetKey(id);
+ if (!original_credential)
+ return absl::nullopt;
- std::u16string username = base::UTF8ToUTF16(params.username);
- std::u16string password = base::UTF8ToUTF16(params.password);
+ CredentialUIEntry updated_credential = *original_credential;
+ updated_credential.username = base::UTF8ToUTF16(params.username);
+ updated_credential.password = base::UTF8ToUTF16(params.password);
if (params.note) {
- return saved_passwords_presenter_.EditSavedPasswords(
- forms_to_change, username, password, base::UTF8ToUTF16(*params.note));
+ updated_credential.note = password_manager::PasswordNote(
+ base::UTF8ToUTF16(*params.note), base::Time::Now());
+ }
+ 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 saved_passwords_presenter_.EditSavedPasswords(forms_to_change,
- username, password);
-}
-void PasswordsPrivateDelegateImpl::RemoveSavedPasswords(
- const std::vector<int>& ids) {
- ExecuteFunction(base::BindOnce(
- &PasswordsPrivateDelegateImpl::RemoveSavedPasswordsInternal,
- base::Unretained(this), ids));
+ return credential_id_generator_.GenerateId(updated_credential);
}
-void PasswordsPrivateDelegateImpl::RemoveSavedPasswordsInternal(
- const std::vector<int>& ids) {
- password_manager_presenter_->RemoveSavedPasswords(
- GetSortKeys(password_id_generator_, ids));
+void PasswordsPrivateDelegateImpl::RemoveSavedPassword(
+ int id,
+ api::passwords_private::PasswordStoreSet from_stores) {
+ ExecuteFunction(
+ base::BindOnce(&PasswordsPrivateDelegateImpl::RemoveEntryInternal,
+ base::Unretained(this), id, from_stores));
}
-void PasswordsPrivateDelegateImpl::RemovePasswordExceptions(
- const std::vector<int>& ids) {
- ExecuteFunction(base::BindOnce(
- &PasswordsPrivateDelegateImpl::RemovePasswordExceptionsInternal,
- base::Unretained(this), ids));
+void PasswordsPrivateDelegateImpl::RemoveEntryInternal(
+ int id,
+ api::passwords_private::PasswordStoreSet from_stores) {
+ const CredentialUIEntry* entry = credential_id_generator_.TryGetKey(id);
+ if (!entry) {
+ return;
+ }
+
+ CredentialUIEntry copy = *entry;
+ copy.stored_in = ConvertToPasswordFormStores(from_stores);
+
+ saved_passwords_presenter_.RemoveCredential(copy);
+
+ if (entry->blocked_by_user) {
+ base::RecordAction(
+ base::UserMetricsAction("PasswordManager_RemovePasswordException"));
+ } else {
+ base::RecordAction(
+ base::UserMetricsAction("PasswordManager_RemoveSavedPassword"));
+ }
}
-void PasswordsPrivateDelegateImpl::RemovePasswordExceptionsInternal(
- const std::vector<int>& ids) {
- password_manager_presenter_->RemovePasswordExceptions(
- GetSortKeys(exception_id_generator_, ids));
+void PasswordsPrivateDelegateImpl::RemovePasswordException(int id) {
+ ExecuteFunction(base::BindOnce(
+ &PasswordsPrivateDelegateImpl::RemoveEntryInternal,
+ base::Unretained(this), id,
+ api::passwords_private::PASSWORD_STORE_SET_DEVICE_AND_ACCOUNT));
}
void PasswordsPrivateDelegateImpl::UndoRemoveSavedPasswordOrException() {
@@ -324,7 +393,7 @@ void PasswordsPrivateDelegateImpl::UndoRemoveSavedPasswordOrException() {
void PasswordsPrivateDelegateImpl::
UndoRemoveSavedPasswordOrExceptionInternal() {
- password_manager_presenter_->UndoRemoveSavedPasswordOrException();
+ saved_passwords_presenter_.UndoLastRemoval();
}
void PasswordsPrivateDelegateImpl::RequestPlaintextPassword(
@@ -345,6 +414,23 @@ void PasswordsPrivateDelegateImpl::RequestPlaintextPassword(
weak_ptr_factory_.GetWeakPtr(), id, reason, std::move(callback)));
}
+void PasswordsPrivateDelegateImpl::RequestCredentialDetails(
+ int id,
+ RequestCredentialDetailsCallback callback,
+ content::WebContents* web_contents) {
+ // Save |web_contents| so that it can be used later when OsReauthCall() is
+ // called. Note: This is safe because the |web_contents| is used before
+ // exiting this method.
+ // TODO(crbug.com/495290): Pass the native window directly to the
+ // reauth-handling code.
+ web_contents_ = web_contents;
+ password_access_authenticator_.EnsureUserIsAuthenticated(
+ GetReauthPurpose(api::passwords_private::PLAINTEXT_REASON_VIEW),
+ base::BindOnce(
+ &PasswordsPrivateDelegateImpl::OnRequestCredentialDetailsAuthResult,
+ weak_ptr_factory_.GetWeakPtr(), id, std::move(callback)));
+}
+
void PasswordsPrivateDelegateImpl::OsReauthCall(
password_manager::ReauthPurpose purpose,
password_manager::PasswordAccessAuthenticator::AuthResultCallback
@@ -355,8 +441,31 @@ void PasswordsPrivateDelegateImpl::OsReauthCall(
web_contents_->GetTopLevelNativeWindow(), purpose);
std::move(callback).Run(result);
#elif BUILDFLAG(IS_MAC)
- bool result = password_manager_util_mac::AuthenticateUser(purpose);
- std::move(callback).Run(result);
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kBiometricAuthenticationInSettings)) {
+ scoped_refptr<device_reauth::BiometricAuthenticator>
+ biometric_authenticator =
+ ChromeBiometricAuthenticatorFactory::GetInstance()
+ ->GetOrCreateBiometricAuthenticator();
+ base::OnceCallback<void()> on_reauth_completed =
+ base::BindOnce(&PasswordsPrivateDelegateImpl::OnReauthCompleted,
+ weak_ptr_factory_.GetWeakPtr());
+
+ biometric_authenticator->AuthenticateWithMessage(
+ device_reauth::BiometricAuthRequester::kPasswordsInSettings,
+ password_manager_util_mac::GetMessageForBiometricLoginPrompt(purpose),
+ std::move(callback).Then(std::move(on_reauth_completed)));
+
+ // If AuthenticateWithMessage is called again(UI isn't blocked so user might
+ // click multiple times on the button), it invalidates the old request which
+ // triggers PasswordsPrivateDelegateImpl::OnReauthCompleted which resets
+ // biometric_authenticator_. Having a local variable solves that problem as
+ // there's a second scoped_refptr for the authenticator object.
+ biometric_authenticator_ = std::move(biometric_authenticator);
+ } else {
+ bool result = password_manager_util_mac::AuthenticateUser(purpose);
+ std::move(callback).Run(result);
+ }
#elif BUILDFLAG(IS_CHROMEOS_ASH)
bool result =
IsOsReauthAllowedAsh(profile_, GetAuthTokenLifetimeForPurpose(purpose));
@@ -368,46 +477,45 @@ void PasswordsPrivateDelegateImpl::OsReauthCall(
#endif
}
-Profile* PasswordsPrivateDelegateImpl::GetProfile() {
- return profile_;
+void PasswordsPrivateDelegateImpl::OsReauthTimeoutCall() {
+ PasswordsPrivateEventRouter* router =
+ PasswordsPrivateEventRouterFactory::GetForProfile(profile_);
+ if (router)
+ router->OnPasswordManagerAuthTimeout();
}
-void PasswordsPrivateDelegateImpl::SetPasswordList(
- const std::vector<std::unique_ptr<password_manager::PasswordForm>>&
- password_list) {
- // Create a list of PasswordUiEntry objects to send to observers.
+void PasswordsPrivateDelegateImpl::SetCredentials(
+ const std::vector<CredentialUIEntry>& credentials) {
+ // Create lists of PasswordUiEntry and ExceptionEntry objects to send to
+ // observers.
current_entries_.clear();
+ current_exceptions_.clear();
- for (const auto& form : password_list) {
- api::passwords_private::PasswordUiEntry entry;
- entry.urls = CreateUrlCollectionFromForm(*form);
- entry.username = base::UTF16ToUTF8(form->username_value);
- const auto& note_itr = base::ranges::find_if(
- form->notes, &std::u16string::empty,
- &password_manager::PasswordNote::unique_display_name);
- entry.password_note =
- note_itr == form->notes.end() ? "" : base::UTF16ToUTF8(note_itr->value);
- entry.id = password_id_generator_.GenerateId(
- password_manager::CreateSortKey(*form));
- entry.frontend_id = password_frontend_id_generator_.GenerateId(
- password_manager::CreateSortKey(*form,
- password_manager::IgnoreStore(true)));
-
- if (!form->federation_origin.opaque()) {
- entry.federation_text =
- std::make_unique<std::string>(l10n_util::GetStringFUTF8(
- IDS_PASSWORDS_VIA_FEDERATION, GetDisplayFederation(*form)));
+ for (const CredentialUIEntry& credential : credentials) {
+ int id = credential_id_generator_.GenerateId(credential);
+ if (credential.blocked_by_user) {
+ api::passwords_private::ExceptionEntry current_exception_entry;
+ current_exception_entry.urls =
+ CreateUrlCollectionFromCredential(credential);
+ current_exception_entry.id = id;
+ current_exceptions_.push_back(std::move(current_exception_entry));
+ } else {
+ current_entries_.push_back(
+ CreatePasswordUiEntryFromCredentialUiEntry(id, credential));
}
-
- entry.from_account_store = form->IsUsingAccountStore();
-
- current_entries_.push_back(std::move(entry));
}
- SendSavedPasswordsList();
+ if (current_entries_initialized_) {
+ DCHECK(get_saved_passwords_list_callbacks_.empty());
+ DCHECK(get_password_exception_list_callbacks_.empty());
+ }
- DCHECK(!current_entries_initialized_ ||
- get_saved_passwords_list_callbacks_.empty());
+ PasswordsPrivateEventRouter* router =
+ PasswordsPrivateEventRouterFactory::GetForProfile(profile_);
+ if (router) {
+ router->OnSavedPasswordsListChanged(current_entries_);
+ router->OnPasswordExceptionsListChanged(current_exceptions_);
+ }
current_entries_initialized_ = true;
InitializeIfNecessary();
@@ -415,36 +523,6 @@ void PasswordsPrivateDelegateImpl::SetPasswordList(
for (auto& callback : get_saved_passwords_list_callbacks_)
std::move(callback).Run(current_entries_);
get_saved_passwords_list_callbacks_.clear();
-}
-
-void PasswordsPrivateDelegateImpl::SetPasswordExceptionList(
- const std::vector<std::unique_ptr<password_manager::PasswordForm>>&
- password_exception_list) {
- // Creates a list of exceptions to send to observers.
- current_exceptions_.clear();
-
- for (const auto& form : password_exception_list) {
- api::passwords_private::ExceptionEntry current_exception_entry;
- current_exception_entry.urls = CreateUrlCollectionFromForm(*form);
- current_exception_entry.id = exception_id_generator_.GenerateId(
- password_manager::CreateSortKey(*form));
- current_exception_entry.frontend_id =
- exception_frontend_id_generator_.GenerateId(
- password_manager::CreateSortKey(
- *form, password_manager::IgnoreStore(true)));
-
- current_exception_entry.from_account_store = form->IsUsingAccountStore();
- current_exceptions_.push_back(std::move(current_exception_entry));
- }
-
- SendPasswordExceptionsList();
-
- DCHECK(!current_entries_initialized_ ||
- get_saved_passwords_list_callbacks_.empty());
-
- current_exceptions_initialized_ = true;
- InitializeIfNecessary();
-
for (auto& callback : get_password_exception_list_callbacks_)
std::move(callback).Run(current_exceptions_);
get_password_exception_list_callbacks_.clear();
@@ -455,18 +533,46 @@ void PasswordsPrivateDelegateImpl::MovePasswordsToAccount(
content::WebContents* web_contents) {
auto* client = ChromePasswordManagerClient::FromWebContents(web_contents);
DCHECK(client);
- std::vector<std::string> sort_keys;
+
+ if (!client->GetPasswordFeatureManager()->IsOptedInForAccountStorage() ||
+ SyncServiceFactory::GetForProfile(profile_)->IsSyncFeatureEnabled()) {
+ return;
+ }
+
+ std::vector<password_manager::PasswordForm> forms_to_move;
for (int id : ids) {
- if (const std::string* sort_key = password_id_generator_.TryGetKey(id))
- sort_keys.push_back(*sort_key);
+ const CredentialUIEntry* entry = credential_id_generator_.TryGetKey(id);
+ if (!entry) {
+ continue;
+ }
+
+ std::vector<password_manager::PasswordForm> corresponding_forms =
+ saved_passwords_presenter_.GetCorrespondingPasswordForms(*entry);
+ if (corresponding_forms.empty()) {
+ continue;
+ }
+
+ // password_manager::MovePasswordsToAccountStore() takes care of moving the
+ // entire equivalence class, so passing the first element is fine.
+ forms_to_move.push_back(std::move(corresponding_forms[0]));
}
- password_manager_presenter_->MovePasswordsToAccountStore(sort_keys, client);
+
+ password_manager::MovePasswordsToAccountStore(
+ forms_to_move, client,
+ password_manager::metrics_util::MoveToAccountStoreTrigger::
+ kExplicitlyTriggeredInSettings);
}
void PasswordsPrivateDelegateImpl::ImportPasswords(
+ api::passwords_private::PasswordStoreSet to_store,
+ ImportResultsCallback results_callback,
content::WebContents* web_contents) {
- password_manager_porter_->set_web_contents(web_contents);
- password_manager_porter_->Load();
+ DCHECK_NE(api::passwords_private::PasswordStoreSet::
+ PASSWORD_STORE_SET_DEVICE_AND_ACCOUNT,
+ to_store);
+ password_manager_porter_->Import(
+ web_contents, *ConvertToPasswordFormStores(to_store).begin(),
+ base::BindOnce(&ConvertImportResults).Then(std::move(results_callback)));
}
void PasswordsPrivateDelegateImpl::ExportPasswords(
@@ -486,7 +592,7 @@ void PasswordsPrivateDelegateImpl::ExportPasswords(
}
void PasswordsPrivateDelegateImpl::CancelExportPasswords() {
- password_manager_porter_->CancelStore();
+ password_manager_porter_->CancelExport();
}
api::passwords_private::ExportProgressStatus
@@ -518,61 +624,38 @@ void PasswordsPrivateDelegateImpl::SetAccountStorageOptIn(
signin_metrics::ReauthAccessPoint::kPasswordSettings, base::DoNothing());
}
-std::vector<api::passwords_private::InsecureCredential>
+std::vector<api::passwords_private::PasswordUiEntry>
PasswordsPrivateDelegateImpl::GetCompromisedCredentials() {
return password_check_delegate_.GetCompromisedCredentials();
}
-std::vector<api::passwords_private::InsecureCredential>
+std::vector<api::passwords_private::PasswordUiEntry>
PasswordsPrivateDelegateImpl::GetWeakCredentials() {
return password_check_delegate_.GetWeakCredentials();
}
-void PasswordsPrivateDelegateImpl::GetPlaintextInsecurePassword(
- api::passwords_private::InsecureCredential credential,
- api::passwords_private::PlaintextReason reason,
- content::WebContents* web_contents,
- PlaintextInsecurePasswordCallback callback) {
- // TODO(crbug.com/495290): Pass the native window directly to the
- // reauth-handling code.
- web_contents_ = web_contents;
- password_access_authenticator_.EnsureUserIsAuthenticated(
- GetReauthPurpose(reason),
- base::BindOnce(&PasswordsPrivateDelegateImpl::
- OnGetPlaintextInsecurePasswordAuthResult,
- weak_ptr_factory_.GetWeakPtr(), std::move(credential),
- reason, std::move(callback)));
-}
-
-bool PasswordsPrivateDelegateImpl::ChangeInsecureCredential(
- const api::passwords_private::InsecureCredential& credential,
- base::StringPiece new_password) {
- return password_check_delegate_.ChangeInsecureCredential(credential,
- new_password);
-}
-
-bool PasswordsPrivateDelegateImpl::RemoveInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) {
- return password_check_delegate_.RemoveInsecureCredential(credential);
-}
-
bool PasswordsPrivateDelegateImpl::MuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) {
+ const api::passwords_private::PasswordUiEntry& credential) {
return password_check_delegate_.MuteInsecureCredential(credential);
}
bool PasswordsPrivateDelegateImpl::UnmuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) {
+ const api::passwords_private::PasswordUiEntry& credential) {
return password_check_delegate_.UnmuteInsecureCredential(credential);
}
void PasswordsPrivateDelegateImpl::RecordChangePasswordFlowStarted(
- const api::passwords_private::InsecureCredential& credential,
+ const api::passwords_private::PasswordUiEntry& credential,
bool is_manual_flow) {
password_check_delegate_.RecordChangePasswordFlowStarted(credential,
is_manual_flow);
}
+void PasswordsPrivateDelegateImpl::RefreshScriptsIfNecessary(
+ RefreshScriptsIfNecessaryCallback callback) {
+ password_check_delegate_.RefreshScriptsIfNecessary(std::move(callback));
+}
+
void PasswordsPrivateDelegateImpl::StartPasswordCheck(
StartPasswordCheckCallback callback) {
password_check_delegate_.StartPasswordCheck(std::move(callback));
@@ -587,6 +670,38 @@ PasswordsPrivateDelegateImpl::GetPasswordCheckStatus() {
return password_check_delegate_.GetPasswordCheckStatus();
}
+void PasswordsPrivateDelegateImpl::StartAutomatedPasswordChange(
+ const api::passwords_private::PasswordUiEntry& credential,
+ StartAutomatedPasswordChangeCallback callback) {
+ if (!credential.change_password_url) {
+ std::move(callback).Run(false);
+ return;
+ }
+
+ GURL url =
+ url::SchemeHostPort(GURL(*credential.change_password_url)).GetURL();
+ if (!url.is_valid()) {
+ std::move(callback).Run(false);
+ return;
+ }
+
+ NavigateParams params(profile_, url,
+ ui::PageTransition::PAGE_TRANSITION_LINK);
+ params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+ base::WeakPtr<content::NavigationHandle> navigation_handle =
+ Navigate(&params);
+
+ if (!navigation_handle) {
+ std::move(callback).Run(false);
+ return;
+ }
+
+ ApcClient* apc_client = ApcClient::GetOrCreateForWebContents(
+ navigation_handle.get()->GetWebContents());
+ apc_client->Start(url, credential.username,
+ /*skip_login=*/false, std::move(callback));
+}
+
password_manager::InsecureCredentialsManager*
PasswordsPrivateDelegateImpl::GetInsecureCredentialsManager() {
return password_check_delegate_.GetInsecureCredentialsManager();
@@ -612,64 +727,63 @@ void PasswordsPrivateDelegateImpl::OnRequestPlaintextPasswordAuthResult(
return;
}
- // Request the password. When it is retrieved, ShowPassword() will be called.
- const std::string* sort_key = password_id_generator_.TryGetKey(id);
- if (!sort_key) {
+ const CredentialUIEntry* entry = credential_id_generator_.TryGetKey(id);
+ if (!entry) {
std::move(callback).Run(absl::nullopt);
return;
}
if (reason == api::passwords_private::PLAINTEXT_REASON_COPY) {
+ ui::ScopedClipboardWriter clipboard_writer(ui::ClipboardBuffer::kCopyPaste);
+ clipboard_writer.WriteText(entry->password);
+ clipboard_writer.MarkAsConfidential();
// In case of copy we don't need to give password back to UI. callback
// will receive either empty string in case of success or null otherwise.
// Copying occurs here so javascript doesn't need plaintext password.
- callback = base::BindOnce(
- [](PlaintextPasswordCallback callback,
- absl::optional<std::u16string> password) {
- if (!password) {
- std::move(callback).Run(absl::nullopt);
- return;
- }
- ui::ScopedClipboardWriter clipboard_writer(
- ui::ClipboardBuffer::kCopyPaste);
- clipboard_writer.WriteText(*password);
- clipboard_writer.MarkAsConfidential();
- std::move(callback).Run(std::u16string());
- },
- std::move(callback));
- }
-
- password_manager_presenter_->RequestPlaintextPassword(
- *sort_key, ConvertPlaintextReason(reason), std::move(callback));
+ std::move(callback).Run(std::u16string());
+ } else {
+ std::move(callback).Run(entry->password);
+ }
+ EmitHistogramsForCredentialAccess(*entry, reason);
}
-void PasswordsPrivateDelegateImpl::OnExportPasswordsAuthResult(
- base::OnceCallback<void(const std::string&)> accepted_callback,
- content::WebContents* web_contents,
+void PasswordsPrivateDelegateImpl::OnRequestCredentialDetailsAuthResult(
+ int id,
+ RequestCredentialDetailsCallback callback,
bool authenticated) {
if (!authenticated) {
- std::move(accepted_callback).Run(kReauthenticationFailed);
+ std::move(callback).Run(absl::nullopt);
return;
}
- password_manager_porter_->set_web_contents(web_contents);
- bool accepted = password_manager_porter_->Store();
- std::move(accepted_callback)
- .Run(accepted ? std::string() : kExportInProgress);
+ const CredentialUIEntry* credential = credential_id_generator_.TryGetKey(id);
+ if (!credential) {
+ std::move(callback).Run(absl::nullopt);
+ return;
+ }
+
+ api::passwords_private::PasswordUiEntry password_ui_entry =
+ CreatePasswordUiEntryFromCredentialUiEntry(id, *credential);
+ password_ui_entry.password =
+ std::make_unique<std::string>(base::UTF16ToUTF8(credential->password));
+ std::move(callback).Run(std::move(password_ui_entry));
+
+ EmitHistogramsForCredentialAccess(
+ *credential, api::passwords_private::PLAINTEXT_REASON_VIEW);
}
-void PasswordsPrivateDelegateImpl::OnGetPlaintextInsecurePasswordAuthResult(
- api::passwords_private::InsecureCredential credential,
- api::passwords_private::PlaintextReason reason,
- PlaintextInsecurePasswordCallback callback,
+void PasswordsPrivateDelegateImpl::OnExportPasswordsAuthResult(
+ base::OnceCallback<void(const std::string&)> accepted_callback,
+ content::WebContents* web_contents,
bool authenticated) {
if (!authenticated) {
- std::move(callback).Run(absl::nullopt);
+ std::move(accepted_callback).Run(kReauthenticationFailed);
return;
}
- std::move(callback).Run(password_check_delegate_.GetPlaintextInsecurePassword(
- std::move(credential)));
+ bool accepted = password_manager_porter_->Export(web_contents);
+ std::move(accepted_callback)
+ .Run(accepted ? std::string() : kExportInProgress);
}
void PasswordsPrivateDelegateImpl::OnAccountStorageOptInStateChanged() {
@@ -683,12 +797,11 @@ void PasswordsPrivateDelegateImpl::OnAccountStorageOptInStateChanged() {
void PasswordsPrivateDelegateImpl::Shutdown() {
password_account_storage_settings_watcher_.reset();
password_manager_porter_.reset();
- password_manager_presenter_.reset();
+ biometric_authenticator_.reset();
}
-IdGenerator<std::string>&
-PasswordsPrivateDelegateImpl::GetPasswordIdGeneratorForTesting() {
- return password_id_generator_;
+void PasswordsPrivateDelegateImpl::OnReauthCompleted() {
+ biometric_authenticator_.reset();
}
void PasswordsPrivateDelegateImpl::ExecuteFunction(base::OnceClosure callback) {
@@ -700,9 +813,13 @@ void PasswordsPrivateDelegateImpl::ExecuteFunction(base::OnceClosure callback) {
pre_initialization_callbacks_.emplace_back(std::move(callback));
}
+void PasswordsPrivateDelegateImpl::OnSavedPasswordsChanged(
+ password_manager::SavedPasswordsPresenter::SavedPasswordsView passwords) {
+ SetCredentials(saved_passwords_presenter_.GetSavedCredentials());
+}
+
void PasswordsPrivateDelegateImpl::InitializeIfNecessary() {
- if (is_initialized_ || !current_entries_initialized_ ||
- !current_exceptions_initialized_)
+ if (is_initialized_ || !current_entries_initialized_)
return;
is_initialized_ = true;
@@ -712,4 +829,24 @@ void PasswordsPrivateDelegateImpl::InitializeIfNecessary() {
pre_initialization_callbacks_.clear();
}
+void PasswordsPrivateDelegateImpl::EmitHistogramsForCredentialAccess(
+ const CredentialUIEntry& entry,
+ api::passwords_private::PlaintextReason reason) {
+ syncer::SyncService* sync_service = nullptr;
+ if (SyncServiceFactory::HasSyncService(profile_)) {
+ sync_service = SyncServiceFactory::GetForProfile(profile_);
+ }
+ if (password_manager::sync_util::IsSyncAccountCredential(
+ entry.url, entry.username, sync_service,
+ IdentityManagerFactory::GetForProfile(profile_))) {
+ base::RecordAction(
+ base::UserMetricsAction("PasswordManager_SyncCredentialShown"));
+ }
+
+ UMA_HISTOGRAM_ENUMERATION(
+ "PasswordManager.AccessPasswordInSettings",
+ ConvertPlaintextReason(reason),
+ password_manager::metrics_util::ACCESS_PASSWORD_COUNT);
+}
+
} // namespace extensions
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 733f5849f81..8c77c897001 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
@@ -9,6 +9,7 @@
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include "base/callback.h"
@@ -19,13 +20,13 @@
#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h"
#include "chrome/browser/extensions/api/passwords_private/passwords_private_utils.h"
#include "chrome/browser/ui/passwords/settings/password_manager_porter.h"
-#include "chrome/browser/ui/passwords/settings/password_manager_presenter.h"
-#include "chrome/browser/ui/passwords/settings/password_ui_view.h"
#include "chrome/common/extensions/api/passwords_private.h"
+#include "components/device_reauth/biometric_authenticator.h"
#include "components/keyed_service/core/keyed_service.h"
#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/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"
#include "extensions/browser/extension_function.h"
@@ -40,8 +41,9 @@ class WebContents;
namespace extensions {
// Concrete PasswordsPrivateDelegate implementation.
-class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
- public PasswordUIView {
+class PasswordsPrivateDelegateImpl
+ : public PasswordsPrivateDelegate,
+ public password_manager::SavedPasswordsPresenter::Observer {
public:
explicit PasswordsPrivateDelegateImpl(Profile* profile);
@@ -63,19 +65,26 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
const std::u16string& note,
bool use_account_store,
content::WebContents* web_contents) override;
- bool ChangeSavedPassword(
- const std::vector<int>& ids,
+ absl::optional<int> ChangeSavedPassword(
+ int id,
const api::passwords_private::ChangeSavedPasswordParams& params) override;
- void RemoveSavedPasswords(const std::vector<int>& ids) override;
- void RemovePasswordExceptions(const std::vector<int>& ids) override;
+ void RemoveSavedPassword(
+ int id,
+ api::passwords_private::PasswordStoreSet from_stores) override;
+ void RemovePasswordException(int id) override;
void UndoRemoveSavedPasswordOrException() override;
void RequestPlaintextPassword(int id,
api::passwords_private::PlaintextReason reason,
PlaintextPasswordCallback callback,
content::WebContents* web_contents) override;
+ void RequestCredentialDetails(int id,
+ RequestCredentialDetailsCallback callback,
+ content::WebContents* web_contents) override;
void MovePasswordsToAccount(const std::vector<int>& ids,
content::WebContents* web_contents) override;
- void ImportPasswords(content::WebContents* web_contents) override;
+ void ImportPasswords(api::passwords_private::PasswordStoreSet to_store,
+ ImportResultsCallback results_callback,
+ content::WebContents* web_contents) override;
void ExportPasswords(
base::OnceCallback<void(const std::string&)> accepted_callback,
content::WebContents* web_contents) override;
@@ -86,48 +95,37 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
// TODO(crbug.com/1102294): Mimic the signature in PasswordFeatureManager.
void SetAccountStorageOptIn(bool opt_in,
content::WebContents* web_contents) override;
- std::vector<api::passwords_private::InsecureCredential>
+ std::vector<api::passwords_private::PasswordUiEntry>
GetCompromisedCredentials() override;
- std::vector<api::passwords_private::InsecureCredential> GetWeakCredentials()
+ std::vector<api::passwords_private::PasswordUiEntry> GetWeakCredentials()
override;
- void GetPlaintextInsecurePassword(
- api::passwords_private::InsecureCredential credential,
- api::passwords_private::PlaintextReason reason,
- content::WebContents* web_contents,
- PlaintextInsecurePasswordCallback callback) override;
- bool ChangeInsecureCredential(
- const api::passwords_private::InsecureCredential& credential,
- base::StringPiece new_password) override;
- bool RemoveInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) override;
bool MuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) override;
+ const api::passwords_private::PasswordUiEntry& credential) override;
bool UnmuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) override;
+ const api::passwords_private::PasswordUiEntry& credential) override;
void RecordChangePasswordFlowStarted(
- const api::passwords_private::InsecureCredential& credential,
+ const api::passwords_private::PasswordUiEntry& credential,
bool is_manual_flow) override;
+ void RefreshScriptsIfNecessary(
+ RefreshScriptsIfNecessaryCallback callback) override;
void StartPasswordCheck(StartPasswordCheckCallback callback) override;
void StopPasswordCheck() override;
api::passwords_private::PasswordCheckStatus GetPasswordCheckStatus() override;
+ void StartAutomatedPasswordChange(
+ const api::passwords_private::PasswordUiEntry& credential,
+ StartAutomatedPasswordChangeCallback callback) override;
password_manager::InsecureCredentialsManager* GetInsecureCredentialsManager()
override;
- // PasswordUIView implementation.
- Profile* GetProfile() override;
- void SetPasswordList(
- const std::vector<std::unique_ptr<password_manager::PasswordForm>>&
- password_list) override;
- void SetPasswordExceptionList(
- const std::vector<std::unique_ptr<password_manager::PasswordForm>>&
- password_exception_list) override;
-
// KeyedService overrides:
void Shutdown() override;
- IdGenerator<std::string>& GetPasswordIdGeneratorForTesting();
-
#if defined(UNIT_TEST)
+ int GetIdForCredential(
+ const password_manager::CredentialUIEntry& credential) {
+ return credential_id_generator_.GenerateId(credential);
+ }
+
// Use this in tests to mock the OS-level reauthentication.
void set_os_reauth_call(
password_manager::PasswordAccessAuthenticator::ReauthCallback
@@ -138,6 +136,11 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
#endif // defined(UNIT_TEST)
private:
+ // password_manager::SavedPasswordsPresenter::Observer implementation.
+ void OnSavedPasswordsChanged(
+ password_manager::SavedPasswordsPresenter::SavedPasswordsView passwords)
+ override;
+
// Called after the lists are fetched. Once both lists have been set, the
// class is considered initialized and any queued functions (which could
// not be executed immediately due to uninitialized data) are invoked.
@@ -147,11 +150,12 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
// has been initialized or by deferring it until initialization has completed.
void ExecuteFunction(base::OnceClosure callback);
- void SendSavedPasswordsList();
- void SendPasswordExceptionsList();
+ void SetCredentials(
+ const std::vector<password_manager::CredentialUIEntry>& credentials);
- void RemoveSavedPasswordsInternal(const std::vector<int>& ids);
- void RemovePasswordExceptionsInternal(const std::vector<int>& ids);
+ void RemoveEntryInternal(
+ int id,
+ api::passwords_private::PasswordStoreSet from_stores);
void UndoRemoveSavedPasswordOrExceptionInternal();
// Callback for when the password list has been written to the destination.
@@ -165,19 +169,18 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
PlaintextPasswordCallback callback,
bool authenticated);
+ // Callback for RequestCredentialDetails() after authentication check.
+ void OnRequestCredentialDetailsAuthResult(
+ int id,
+ RequestCredentialDetailsCallback callback,
+ bool authenticated);
+
// Callback for ExportPasswords() after authentication check.
void OnExportPasswordsAuthResult(
base::OnceCallback<void(const std::string&)> accepted_callback,
content::WebContents* web_contents,
bool authenticated);
- // Callback for GetPlaintextInsecurePassword() after authentication check.
- void OnGetPlaintextInsecurePasswordAuthResult(
- api::passwords_private::InsecureCredential credential,
- api::passwords_private::PlaintextReason reason,
- PlaintextInsecurePasswordCallback callback,
- bool authenticated);
-
void OnAccountStorageOptInStateChanged();
// Decides whether an authentication check is successful. Passes the result
@@ -189,12 +192,20 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
password_manager::PasswordAccessAuthenticator::AuthResultCallback
callback);
+ // Records user action and emits histogram values for retrieving |entry|.
+ void EmitHistogramsForCredentialAccess(
+ const password_manager::CredentialUIEntry& entry,
+ api::passwords_private::PlaintextReason reason);
+
+ // Callback for biometric authentication after authentication check.
+ void OnReauthCompleted();
+
+ // Invokes PasswordsPrivateEventRouter::OnPasswordManagerAuthTimeout().
+ void OsReauthTimeoutCall();
+
// Not owned by this class.
raw_ptr<Profile> profile_;
- // Used to communicate with the password store.
- std::unique_ptr<PasswordManagerPresenter> password_manager_presenter_;
-
// Used to add/edit passwords and to create |password_check_delegate_|.
password_manager::SavedPasswordsPresenter saved_passwords_presenter_;
@@ -214,23 +225,20 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
UiEntries current_entries_;
ExceptionEntries current_exceptions_;
- // Generators that map between sort keys used by |password_manager_presenter_|
- // and ids used by the JavaScript front end.
- IdGenerator<std::string> password_id_generator_;
- IdGenerator<std::string> password_frontend_id_generator_;
- IdGenerator<std::string> exception_id_generator_;
- IdGenerator<std::string> exception_frontend_id_generator_;
+ // An id generator for saved passwords and blocked websites.
+ IdGenerator<password_manager::CredentialUIEntry,
+ int,
+ password_manager::CredentialUIEntry::Less>
+ credential_id_generator_;
- // Whether SetPasswordList and SetPasswordExceptionList have been called, and
- // whether this class has been initialized, meaning both have been called.
+ // Whether SetCredentials has been called, and whether this class has been
+ // initialized.
bool current_entries_initialized_;
- bool current_exceptions_initialized_;
bool is_initialized_;
// Vector of callbacks which are queued up before the password store has been
- // initialized. Once both SetPasswordList() and SetPasswordExceptionList()
- // have been called, this class is considered initialized and can these
- // callbacks are invoked.
+ // initialized. Once SetCredentials() has been called, this class is
+ // considered initialized and can these callbacks are invoked.
std::vector<base::OnceClosure> pre_initialization_callbacks_;
std::vector<UiEntriesCallback> get_saved_passwords_list_callbacks_;
std::vector<ExceptionEntriesCallback> get_password_exception_list_callbacks_;
@@ -239,6 +247,9 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate,
// NativeWindow for the window where the API was called.
raw_ptr<content::WebContents> web_contents_;
+ // Biometric authenticator used to authenticate user on Mac in settings.
+ scoped_refptr<device_reauth::BiometricAuthenticator> biometric_authenticator_;
+
base::WeakPtrFactory<PasswordsPrivateDelegateImpl> weak_ptr_factory_{this};
};
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_browsertest.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_browsertest.cc
new file mode 100644
index 00000000000..ad6469bccb6
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_browsertest.cc
@@ -0,0 +1,79 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h"
+
+#include <memory>
+#include <string>
+
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/autofill_assistant/password_change/apc_client.h"
+#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/ui_features.h"
+#include "chrome/common/extensions/api/passwords_private.h"
+#include "chrome/test/base/chrome_test_utils.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+namespace {
+
+constexpr char kUsername[] = "Bob";
+constexpr char kUrl[] = "https://www.example.com";
+
+class PasswordsPrivateDelegateImplBrowserTest : public InProcessBrowserTest {
+ public:
+ PasswordsPrivateDelegateImplBrowserTest() {
+ // Enable the unified side panel, as this is a prerequisite for the
+ // Automated Password Change flow to be startable.
+ feature_list.InitAndEnableFeature(features::kUnifiedSidePanel);
+ }
+ ~PasswordsPrivateDelegateImplBrowserTest() override = default;
+
+ content::WebContents* web_contents() {
+ return chrome_test_utils::GetActiveWebContents(this);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list;
+};
+
+IN_PROC_BROWSER_TEST_F(PasswordsPrivateDelegateImplBrowserTest,
+ StartAutomatedPasswordChange) {
+ PasswordsPrivateDelegateImpl delegate(browser()->profile());
+
+ const GURL url(kUrl);
+ api::passwords_private::PasswordUiEntry credential;
+ credential.username = kUsername;
+ credential.change_password_url = std::make_unique<std::string>(kUrl);
+ base::MockCallback<
+ PasswordsPrivateDelegate::StartAutomatedPasswordChangeCallback>
+ apc_callback;
+
+ content::TestNavigationObserver navigation_observer(url);
+ navigation_observer.StartWatchingNewWebContents();
+
+ delegate.StartAutomatedPasswordChange(credential, apc_callback.Get());
+ navigation_observer.Wait();
+ EXPECT_EQ(web_contents()->GetLastCommittedURL(), url);
+
+ // The `ApcClient` is running.
+ ApcClient* apc_client = ApcClient::GetOrCreateForWebContents(web_contents());
+ ASSERT_TRUE(apc_client);
+ EXPECT_TRUE(apc_client->IsRunning());
+
+ EXPECT_CALL(apc_callback, Run(false)).Times(1);
+ apc_client->Stop();
+}
+
+} // namespace
+
+} // namespace extensions
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 94807625cbf..7e45c869191 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
@@ -25,6 +25,7 @@
#include "chrome/browser/password_manager/account_password_store_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/sync/sync_service_factory.h"
#include "chrome/common/extensions/api/passwords_private.h"
#include "chrome/test/base/testing_profile.h"
#include "components/password_manager/content/browser/password_manager_log_router_factory.h"
@@ -37,6 +38,7 @@
#include "components/password_manager/core/browser/reauth_purpose.h"
#include "components/password_manager/core/browser/test_password_store.h"
#include "components/signin/public/base/signin_metrics.h"
+#include "components/sync/driver/test_sync_service.h"
#include "content/public/browser/browser_context.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_renderer_host.h"
@@ -48,13 +50,13 @@
using MockReauthCallback = base::MockCallback<
password_manager::PasswordAccessAuthenticator::ReauthCallback>;
-using PasswordFormList =
- std::vector<std::unique_ptr<password_manager::PasswordForm>>;
using password_manager::ReauthPurpose;
using password_manager::TestPasswordStore;
using ::testing::_;
using ::testing::Eq;
+using ::testing::IsNull;
using ::testing::Ne;
+using ::testing::Pointee;
using ::testing::Return;
using ::testing::SizeIs;
using ::testing::StrictMock;
@@ -66,6 +68,8 @@ constexpr char kHistogramName[] = "PasswordManager.AccessPasswordInSettings";
using MockPlaintextPasswordCallback =
base::MockCallback<PasswordsPrivateDelegate::PlaintextPasswordCallback>;
+using MockRequestCredentialDetailsCallback = base::MockCallback<
+ PasswordsPrivateDelegate::RequestCredentialDetailsCallback>;
class MockPasswordManagerClient : public ChromePasswordManagerClient {
public:
@@ -114,6 +118,25 @@ MockPasswordManagerClient::CreateForWebContentsAndGet(
return mock_client;
}
+void SetUpSyncInTransportMode(Profile* profile) {
+ auto* sync_service = static_cast<syncer::TestSyncService*>(
+ SyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+ profile,
+ base::BindRepeating(
+ [](content::BrowserContext*) -> std::unique_ptr<KeyedService> {
+ return std::make_unique<syncer::TestSyncService>();
+ })));
+ CoreAccountInfo account;
+ account.email = "foo@gmail.com";
+ account.gaia = "foo";
+ account.account_id = CoreAccountId::FromGaiaId(account.gaia);
+ sync_service->SetAccountInfo(account);
+ sync_service->SetDisableReasons({});
+ sync_service->SetTransportState(syncer::SyncService::TransportState::ACTIVE);
+ sync_service->SetHasSyncConsent(false);
+ ASSERT_FALSE(sync_service->IsSyncFeatureEnabled());
+}
+
class PasswordEventObserver
: public extensions::TestEventRouter::EventObserver {
public:
@@ -152,7 +175,7 @@ void PasswordEventObserver::OnBroadcastEvent(const extensions::Event& event) {
if (event.event_name != event_name_) {
return;
}
- event_args_ = event.event_args->Clone();
+ event_args_ = base::Value(event.event_args.Clone());
}
std::unique_ptr<KeyedService> BuildPasswordsPrivateEventRouter(
@@ -161,21 +184,25 @@ std::unique_ptr<KeyedService> BuildPasswordsPrivateEventRouter(
PasswordsPrivateEventRouter::Create(context));
}
-password_manager::PasswordForm CreateSampleForm() {
+password_manager::PasswordForm CreateSampleForm(
+ password_manager::PasswordForm::Store store =
+ password_manager::PasswordForm::Store::kProfileStore) {
password_manager::PasswordForm form;
form.signon_realm = "http://abc1.com";
form.url = GURL("http://abc1.com");
form.username_value = u"test@gmail.com";
form.password_value = u"test";
+ form.in_store = store;
return form;
}
MATCHER_P(PasswordUiEntryDataEquals, expected, "") {
return testing::Value(expected.get().urls.link, arg.urls.link) &&
testing::Value(expected.get().username, arg.username) &&
- testing::Value(expected.get().password_note, arg.password_note) &&
- testing::Value(expected.get().from_account_store,
- arg.from_account_store);
+ testing::Value(*expected.get().note, *arg.note) &&
+ testing::Value(expected.get().stored_in, arg.stored_in) &&
+ testing::Value(expected.get().is_android_credential,
+ arg.is_android_credential);
}
} // namespace
@@ -192,7 +219,7 @@ class PasswordsPrivateDelegateImplTest : public testing::Test {
~PasswordsPrivateDelegateImplTest() override;
// Sets up a testing password store and fills it with |forms|.
- void SetUpPasswordStore(std::vector<password_manager::PasswordForm> forms);
+ void SetUpPasswordStores(std::vector<password_manager::PasswordForm> forms);
// Sets up a testing EventRouter with a production
// PasswordsPrivateEventRouter.
@@ -204,7 +231,7 @@ class PasswordsPrivateDelegateImplTest : public testing::Test {
content::BrowserTaskEnvironment task_environment_;
TestingProfile profile_;
raw_ptr<extensions::TestEventRouter> event_router_ = nullptr;
- scoped_refptr<TestPasswordStore> store_ =
+ scoped_refptr<TestPasswordStore> profile_store_ =
CreateAndUseTestPasswordStore(&profile_);
scoped_refptr<TestPasswordStore> account_store_ =
CreateAndUseTestAccountPasswordStore(&profile_);
@@ -217,16 +244,22 @@ class PasswordsPrivateDelegateImplTest : public testing::Test {
PasswordsPrivateDelegateImplTest::PasswordsPrivateDelegateImplTest() {
SetUpRouters();
+ SetUpSyncInTransportMode(&profile_);
}
PasswordsPrivateDelegateImplTest::~PasswordsPrivateDelegateImplTest() {
ui::Clipboard::DestroyClipboardForCurrentThread();
}
-void PasswordsPrivateDelegateImplTest::SetUpPasswordStore(
+void PasswordsPrivateDelegateImplTest::SetUpPasswordStores(
std::vector<password_manager::PasswordForm> forms) {
for (const password_manager::PasswordForm& form : forms) {
- store_->AddLogin(form);
+ if (form.IsUsingAccountStore())
+ account_store_->AddLogin(form);
+ else if (form.IsUsingProfileStore())
+ profile_store_->AddLogin(form);
+ else
+ NOTREACHED() << "Store not set";
}
// Spin the loop to allow PasswordStore tasks being processed.
base::RunLoop().RunUntilIdle();
@@ -248,44 +281,32 @@ TEST_F(PasswordsPrivateDelegateImplTest, GetSavedPasswordsList) {
EXPECT_CALL(callback, Run).Times(0);
delegate.GetSavedPasswordsList(callback.Get());
- PasswordFormList list;
- list.push_back(std::make_unique<password_manager::PasswordForm>());
-
EXPECT_CALL(callback, Run);
- delegate.SetPasswordList(list);
+ SetUpPasswordStores({});
EXPECT_CALL(callback, Run);
delegate.GetSavedPasswordsList(callback.Get());
}
TEST_F(PasswordsPrivateDelegateImplTest,
- PasswordsDuplicatedInStoresHaveSameFrontendId) {
+ PasswordsDuplicatedInStoresAreRepresentedAsSingleEntity) {
PasswordsPrivateDelegateImpl delegate(&profile_);
- auto account_password = std::make_unique<password_manager::PasswordForm>();
- account_password->in_store =
- password_manager::PasswordForm::Store::kAccountStore;
- auto profile_password = std::make_unique<password_manager::PasswordForm>();
- profile_password->in_store =
- password_manager::PasswordForm::Store::kProfileStore;
-
- PasswordFormList list;
- list.push_back(std::move(account_password));
- list.push_back(std::move(profile_password));
+ password_manager::PasswordForm account_password =
+ CreateSampleForm(password_manager::PasswordForm::Store::kAccountStore);
+ password_manager::PasswordForm profile_password =
+ CreateSampleForm(password_manager::PasswordForm::Store::kProfileStore);
- delegate.SetPasswordList(list);
+ SetUpPasswordStores({account_password, profile_password});
base::MockCallback<PasswordsPrivateDelegate::UiEntriesCallback> callback;
- int first_frontend_id, second_frontend_id;
- EXPECT_CALL(callback, Run(SizeIs(2)))
+ EXPECT_CALL(callback, Run(SizeIs(1)))
.WillOnce([&](const PasswordsPrivateDelegate::UiEntries& passwords) {
- first_frontend_id = passwords[0].frontend_id;
- second_frontend_id = passwords[1].frontend_id;
+ EXPECT_EQ(api::passwords_private::PASSWORD_STORE_SET_DEVICE_AND_ACCOUNT,
+ passwords[0].stored_in);
});
delegate.GetSavedPasswordsList(callback.Get());
-
- EXPECT_EQ(first_frontend_id, second_frontend_id);
}
TEST_F(PasswordsPrivateDelegateImplTest, GetPasswordExceptionsList) {
@@ -296,48 +317,34 @@ TEST_F(PasswordsPrivateDelegateImplTest, GetPasswordExceptionsList) {
EXPECT_CALL(callback, Run).Times(0);
delegate.GetPasswordExceptionsList(callback.Get());
- PasswordFormList list;
- list.push_back(std::make_unique<password_manager::PasswordForm>());
-
EXPECT_CALL(callback, Run);
- delegate.SetPasswordExceptionList(list);
+ SetUpPasswordStores({});
EXPECT_CALL(callback, Run);
delegate.GetPasswordExceptionsList(callback.Get());
}
TEST_F(PasswordsPrivateDelegateImplTest,
- ExceptionsDuplicatedInStoresHaveSameFrontendId) {
+ ExceptionsDuplicatedInStoresAreRepresentedAsSingleEntity) {
PasswordsPrivateDelegateImpl delegate(&profile_);
-
- auto account_exception = std::make_unique<password_manager::PasswordForm>();
- account_exception->blocked_by_user = true;
- account_exception->in_store =
+ password_manager::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;
- auto profile_exception = std::make_unique<password_manager::PasswordForm>();
- profile_exception->blocked_by_user = true;
- profile_exception->in_store =
+ password_manager::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;
- PasswordFormList list;
- list.push_back(std::move(account_exception));
- list.push_back(std::move(profile_exception));
-
- delegate.SetPasswordExceptionList(list);
+ SetUpPasswordStores({account_exception, profile_exception});
base::MockCallback<PasswordsPrivateDelegate::ExceptionEntriesCallback>
callback;
- int first_frontend_id, second_frontend_id;
- EXPECT_CALL(callback, Run(SizeIs(2)))
- .WillOnce(
- [&](const PasswordsPrivateDelegate::ExceptionEntries& exceptions) {
- first_frontend_id = exceptions[0].frontend_id;
- second_frontend_id = exceptions[1].frontend_id;
- });
+ EXPECT_CALL(callback, Run(SizeIs(1)));
delegate.GetPasswordExceptionsList(callback.Get());
-
- EXPECT_EQ(first_frontend_id, second_frontend_id);
}
TEST_F(PasswordsPrivateDelegateImplTest, AddPassword) {
@@ -376,13 +383,14 @@ TEST_F(PasswordsPrivateDelegateImplTest, AddPassword) {
api::passwords_private::PasswordUiEntry expected_entry1;
expected_entry1.urls.link = "https://example1.com/";
expected_entry1.username = "username1";
- expected_entry1.password_note = "";
- expected_entry1.from_account_store = true;
+ expected_entry1.note = std::make_unique<std::string>();
+ 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.username = "";
- expected_entry2.password_note = "note";
- expected_entry2.from_account_store = false;
+ expected_entry2.note = std::make_unique<std::string>("note");
+ expected_entry2.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
EXPECT_CALL(callback,
Run(testing::UnorderedElementsAre(
PasswordUiEntryDataEquals(testing::ByRef(expected_entry1)),
@@ -428,7 +436,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, AddPasswordUpdatesDefaultStore) {
TEST_F(PasswordsPrivateDelegateImplTest, ChangeSavedPassword) {
password_manager::PasswordForm sample_form = CreateSampleForm();
- SetUpPasswordStore({sample_form});
+ SetUpPasswordStores({sample_form});
PasswordsPrivateDelegateImpl delegate(&profile_);
// Spin the loop to allow PasswordStore tasks posted on the creation of
@@ -444,13 +452,20 @@ TEST_F(PasswordsPrivateDelegateImplTest, ChangeSavedPassword) {
base::UTF8ToUTF16(passwords[0].username));
});
delegate.GetSavedPasswordsList(callback.Get());
- int sample_form_id = delegate.GetPasswordIdGeneratorForTesting().GenerateId(
- password_manager::CreateSortKey(sample_form));
+ int sample_form_id = delegate.GetIdForCredential(
+ password_manager::CredentialUIEntry(sample_form));
api::passwords_private::ChangeSavedPasswordParams params;
params.password = "new_pass";
params.username = "new_user";
- EXPECT_TRUE(delegate.ChangeSavedPassword({sample_form_id}, params));
+
+ 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.
@@ -460,7 +475,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, ChangeSavedPassword) {
EXPECT_CALL(callback, Run(SizeIs(1)))
.WillOnce([](const PasswordsPrivateDelegate::UiEntries& passwords) {
EXPECT_EQ("new_user", passwords[0].username);
- EXPECT_EQ("", passwords[0].password_note);
+ EXPECT_THAT(passwords[0].note, Pointee(Eq("")));
});
delegate.GetSavedPasswordsList(callback.Get());
}
@@ -472,7 +487,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, ChangeSavedPasswordWithNote) {
/*date_created=*/base::Time::Now(), /*hide_by_default=*/true);
sample_form.notes.emplace_back(u"note with empty display name",
/*date_created=*/base::Time::Now());
- SetUpPasswordStore({sample_form});
+ SetUpPasswordStores({sample_form});
PasswordsPrivateDelegateImpl delegate(&profile_);
// Spin the loop to allow PasswordStore tasks posted on the creation of
@@ -486,18 +501,25 @@ TEST_F(PasswordsPrivateDelegateImplTest, ChangeSavedPasswordWithNote) {
.WillOnce([&](const PasswordsPrivateDelegate::UiEntries& passwords) {
EXPECT_EQ(sample_form.username_value,
base::UTF8ToUTF16(passwords[0].username));
- EXPECT_EQ(sample_form.notes[1].value,
- base::UTF8ToUTF16(passwords[0].password_note));
+ EXPECT_THAT(passwords[0].note,
+ Pointee(Eq(base::UTF16ToUTF8(sample_form.notes[1].value))));
});
delegate.GetSavedPasswordsList(callback.Get());
- int sample_form_id = delegate.GetPasswordIdGeneratorForTesting().GenerateId(
- password_manager::CreateSortKey(sample_form));
+ 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 = std::make_unique<std::string>("new note");
- EXPECT_TRUE(delegate.ChangeSavedPassword({sample_form_id}, params));
+
+ sample_form.password_value = u"new_pass";
+ sample_form.username_value = u"new_user";
+ 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.
@@ -507,16 +529,81 @@ TEST_F(PasswordsPrivateDelegateImplTest, ChangeSavedPasswordWithNote) {
EXPECT_CALL(callback, Run(SizeIs(1)))
.WillOnce([](const PasswordsPrivateDelegate::UiEntries& passwords) {
EXPECT_EQ("new_user", passwords[0].username);
- EXPECT_EQ("new note", passwords[0].password_note);
+ EXPECT_THAT(passwords[0].note, Pointee(Eq("new note")));
});
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});
+
+ PasswordsPrivateDelegateImpl delegate(&profile_);
+ // 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});
+
+ PasswordsPrivateDelegateImpl delegate(&profile_);
+ // 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);
+}
+
// 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();
- SetUpPasswordStore({form});
+ SetUpPasswordStores({form});
PasswordsPrivateDelegateImpl delegate(&profile_);
base::RunLoop().RunUntilIdle();
@@ -589,7 +676,7 @@ TEST_F(PasswordsPrivateDelegateImplTest,
}
TEST_F(PasswordsPrivateDelegateImplTest, TestCopyPasswordCallbackResultFail) {
- SetUpPasswordStore({CreateSampleForm()});
+ SetUpPasswordStores({CreateSampleForm()});
PasswordsPrivateDelegateImpl delegate(&profile_);
base::RunLoop().RunUntilIdle();
@@ -609,7 +696,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, TestCopyPasswordCallbackResultFail) {
delegate.RequestPlaintextPassword(
0, api::passwords_private::PLAINTEXT_REASON_COPY, password_callback.Get(),
nullptr);
- // Clipboard should not be modifiend in case Reauth failed
+ // Clipboard should not be modified in case Reauth failed
std::u16string result;
test_clipboard_->ReadText(ui::ClipboardBuffer::kCopyPaste,
/* data_dst = */ nullptr, &result);
@@ -621,7 +708,7 @@ TEST_F(PasswordsPrivateDelegateImplTest, TestCopyPasswordCallbackResultFail) {
}
TEST_F(PasswordsPrivateDelegateImplTest, TestPassedReauthOnView) {
- SetUpPasswordStore({CreateSampleForm()});
+ SetUpPasswordStores({CreateSampleForm()});
PasswordsPrivateDelegateImpl delegate(&profile_);
// Spin the loop to allow PasswordStore tasks posted on the creation of
@@ -647,8 +734,40 @@ TEST_F(PasswordsPrivateDelegateImplTest, TestPassedReauthOnView) {
1);
}
+TEST_F(PasswordsPrivateDelegateImplTest,
+ TestPassedReauthOnRequestCredentialDetails) {
+ SetUpPasswordStores({CreateSampleForm()});
+
+ PasswordsPrivateDelegateImpl delegate(&profile_);
+ // Spin the loop to allow PasswordStore tasks posted on the creation of
+ // |delegate| to be completed.
+ base::RunLoop().RunUntilIdle();
+
+ MockReauthCallback callback;
+ delegate.set_os_reauth_call(callback.Get());
+
+ EXPECT_CALL(callback, Run(ReauthPurpose::VIEW_PASSWORD, _))
+ .WillOnce(testing::WithArg<1>(
+ [&](password_manager::PasswordAccessAuthenticator::AuthResultCallback
+ callback) { std::move(callback).Run(true); }));
+
+ MockRequestCredentialDetailsCallback password_callback;
+ EXPECT_CALL(password_callback, Run)
+ .WillOnce(
+ [&](absl::optional<api::passwords_private::PasswordUiEntry> entry) {
+ EXPECT_THAT(entry->password, Pointee(Eq("test")));
+ EXPECT_THAT(entry->username, Eq("test@gmail.com"));
+ });
+
+ delegate.RequestCredentialDetails(0, password_callback.Get(), nullptr);
+
+ histogram_tester().ExpectUniqueSample(
+ kHistogramName, password_manager::metrics_util::ACCESS_PASSWORD_VIEWED,
+ 1);
+}
+
TEST_F(PasswordsPrivateDelegateImplTest, TestFailedReauthOnView) {
- SetUpPasswordStore({CreateSampleForm()});
+ SetUpPasswordStores({CreateSampleForm()});
PasswordsPrivateDelegateImpl delegate(&profile_);
// Spin the loop to allow PasswordStore tasks posted on the creation of
@@ -673,10 +792,9 @@ TEST_F(PasswordsPrivateDelegateImplTest, TestFailedReauthOnView) {
histogram_tester().ExpectTotalCount(kHistogramName, 0);
}
-TEST_F(PasswordsPrivateDelegateImplTest, TestReauthOnExport) {
- SetUpPasswordStore({CreateSampleForm()});
- StrictMock<base::MockCallback<base::OnceCallback<void(const std::string&)>>>
- mock_accepted;
+TEST_F(PasswordsPrivateDelegateImplTest,
+ TestFailedReauthOnRequestCredentialDetails) {
+ SetUpPasswordStores({CreateSampleForm()});
PasswordsPrivateDelegateImpl delegate(&profile_);
// Spin the loop to allow PasswordStore tasks posted on the creation of
@@ -686,24 +804,21 @@ TEST_F(PasswordsPrivateDelegateImplTest, TestReauthOnExport) {
MockReauthCallback callback;
delegate.set_os_reauth_call(callback.Get());
- EXPECT_CALL(mock_accepted, Run(std::string())).Times(2);
-
- EXPECT_CALL(callback, Run(ReauthPurpose::EXPORT, _))
+ EXPECT_CALL(callback, Run(ReauthPurpose::VIEW_PASSWORD, _))
.WillOnce(testing::WithArg<1>(
[&](password_manager::PasswordAccessAuthenticator::AuthResultCallback
- callback) { std::move(callback).Run(true); }));
- delegate.ExportPasswords(mock_accepted.Get(), nullptr);
+ callback) { std::move(callback).Run(false); }));
- // Export should ignore previous reauthentication results.
- EXPECT_CALL(callback, Run(ReauthPurpose::EXPORT, _))
- .WillOnce(testing::WithArg<1>(
- [&](password_manager::PasswordAccessAuthenticator::AuthResultCallback
- callback) { std::move(callback).Run(true); }));
- delegate.ExportPasswords(mock_accepted.Get(), nullptr);
+ MockRequestCredentialDetailsCallback password_callback;
+ EXPECT_CALL(password_callback, Run(Eq(absl::nullopt)));
+ delegate.RequestCredentialDetails(0, password_callback.Get(), nullptr);
+
+ // Since Reauth had failed password was not viewed and metric wasn't recorded
+ histogram_tester().ExpectTotalCount(kHistogramName, 0);
}
TEST_F(PasswordsPrivateDelegateImplTest, TestReauthFailedOnExport) {
- SetUpPasswordStore({CreateSampleForm()});
+ SetUpPasswordStores({CreateSampleForm()});
StrictMock<base::MockCallback<base::OnceCallback<void(const std::string&)>>>
mock_accepted;
@@ -724,73 +839,6 @@ TEST_F(PasswordsPrivateDelegateImplTest, TestReauthFailedOnExport) {
delegate.ExportPasswords(mock_accepted.Get(), nullptr);
}
-// Verifies that PasswordsPrivateDelegateImpl::GetPlaintextInsecurePassword
-// fails if the re-auth fails.
-TEST_F(PasswordsPrivateDelegateImplTest,
- TestReauthOnGetPlaintextInsecurePasswordFails) {
- PasswordsPrivateDelegateImpl delegate(&profile_);
-
- MockReauthCallback reauth_callback;
- delegate.set_os_reauth_call(reauth_callback.Get());
-
- base::MockCallback<
- PasswordsPrivateDelegate::PlaintextInsecurePasswordCallback>
- credential_callback;
-
- EXPECT_CALL(reauth_callback, Run(ReauthPurpose::VIEW_PASSWORD, _))
- .WillOnce(testing::WithArg<1>(
- [&](password_manager::PasswordAccessAuthenticator::AuthResultCallback
- callback) { std::move(callback).Run(false); }));
-
- EXPECT_CALL(credential_callback, Run(Eq(absl::nullopt)));
-
- delegate.GetPlaintextInsecurePassword(
- api::passwords_private::InsecureCredential(),
- api::passwords_private::PLAINTEXT_REASON_VIEW, nullptr,
- credential_callback.Get());
-}
-
-// Verifies that PasswordsPrivateDelegateImpl::GetPlaintextInsecurePassword
-// succeeds if the re-auth succeeds and there is a matching compromised
-// credential in the store.
-TEST_F(PasswordsPrivateDelegateImplTest, TestReauthOnGetPlaintextCompPassword) {
- PasswordsPrivateDelegateImpl delegate(&profile_);
-
- password_manager::PasswordForm form = CreateSampleForm();
- form.password_issues = {
- {password_manager::InsecureType::kLeaked,
- password_manager::InsecurityMetadata(base::Time::FromTimeT(1),
- password_manager::IsMuted(false))}};
- store_->AddLogin(form);
- base::RunLoop().RunUntilIdle();
-
- api::passwords_private::InsecureCredential credential =
- std::move(delegate.GetCompromisedCredentials().at(0));
-
- MockReauthCallback reauth_callback;
- delegate.set_os_reauth_call(reauth_callback.Get());
-
- base::MockCallback<
- PasswordsPrivateDelegate::PlaintextInsecurePasswordCallback>
- credential_callback;
-
- absl::optional<api::passwords_private::InsecureCredential> opt_credential;
- EXPECT_CALL(reauth_callback, Run(ReauthPurpose::VIEW_PASSWORD, _))
- .WillOnce(testing::WithArg<1>(
- [&](password_manager::PasswordAccessAuthenticator::AuthResultCallback
- callback) { std::move(callback).Run(true); }));
- EXPECT_CALL(credential_callback, Run).WillOnce(MoveArg(&opt_credential));
-
- delegate.GetPlaintextInsecurePassword(
- std::move(credential), api::passwords_private::PLAINTEXT_REASON_VIEW,
- nullptr, credential_callback.Get());
-
- ASSERT_TRUE(opt_credential.has_value());
- EXPECT_EQ(form.signon_realm, opt_credential->signon_realm);
- EXPECT_EQ(form.username_value, base::UTF8ToUTF16(opt_credential->username));
- EXPECT_EQ(form.password_value, base::UTF8ToUTF16(*opt_credential->password));
-}
-
TEST_F(PasswordsPrivateDelegateImplTest,
GetUrlCollectionValueWithSchemeWhenIpAddress) {
PasswordsPrivateDelegateImpl delegate(&profile_);
@@ -798,7 +846,7 @@ TEST_F(PasswordsPrivateDelegateImplTest,
delegate.GetUrlCollection("127.0.0.1");
EXPECT_TRUE(urls.has_value());
EXPECT_EQ("127.0.0.1", urls.value().shown);
- EXPECT_EQ("http://127.0.0.1/", urls.value().origin);
+ EXPECT_EQ("http://127.0.0.1/", urls.value().signon_realm);
EXPECT_EQ("http://127.0.0.1/", urls.value().link);
}
@@ -809,7 +857,7 @@ TEST_F(PasswordsPrivateDelegateImplTest,
delegate.GetUrlCollection("example.com/login");
EXPECT_TRUE(urls.has_value());
EXPECT_EQ("example.com", urls.value().shown);
- EXPECT_EQ("https://example.com/", urls.value().origin);
+ EXPECT_EQ("https://example.com/", urls.value().signon_realm);
EXPECT_EQ("https://example.com/login", urls.value().link);
}
@@ -821,7 +869,7 @@ TEST_F(PasswordsPrivateDelegateImplTest,
"http://username:password@example.com/login?param=value#ref");
EXPECT_TRUE(urls.has_value());
EXPECT_EQ("example.com", urls.value().shown);
- EXPECT_EQ("http://example.com/", urls.value().origin);
+ EXPECT_EQ("http://example.com/", urls.value().signon_realm);
EXPECT_EQ("http://example.com/login", urls.value().link);
}
@@ -861,4 +909,172 @@ TEST_F(PasswordsPrivateDelegateImplTest, IsAccountStoreDefault) {
EXPECT_FALSE(delegate.IsAccountStoreDefault(web_contents.get()));
}
+TEST_F(PasswordsPrivateDelegateImplTest, TestMovePasswordsToAccountStore) {
+ // This enables uses of TestWebContents.
+ content::RenderViewHostTestEnabler test_render_host_factories;
+ std::unique_ptr<content::WebContents> web_contents =
+ content::WebContentsTester::CreateTestWebContents(&profile_, nullptr);
+ auto* client =
+ MockPasswordManagerClient::CreateForWebContentsAndGet(web_contents.get());
+ ON_CALL(*(client->GetPasswordFeatureManager()), IsOptedInForAccountStorage)
+ .WillByDefault(Return(true));
+
+ PasswordsPrivateDelegateImpl delegate(&profile_);
+
+ password_manager::PasswordForm form1 =
+ CreateSampleForm(password_manager::PasswordForm::Store::kProfileStore);
+ password_manager::PasswordForm form2 = form1;
+ form2.username_value = u"different_username";
+
+ SetUpPasswordStores({form1, form2});
+
+ int first_id =
+ delegate.GetIdForCredential(password_manager::CredentialUIEntry(form1));
+ int second_id =
+ delegate.GetIdForCredential(password_manager::CredentialUIEntry(form2));
+
+ delegate.MovePasswordsToAccount({first_id, second_id}, web_contents.get());
+ base::RunLoop().RunUntilIdle();
+
+ histogram_tester().ExpectUniqueSample(
+ "PasswordManager.AccountStorage.MoveToAccountStoreFlowAccepted",
+ password_manager::metrics_util::MoveToAccountStoreTrigger::
+ kExplicitlyTriggeredInSettings,
+ 2);
+}
+
+TEST_F(PasswordsPrivateDelegateImplTest, AndroidCredential) {
+ PasswordsPrivateDelegateImpl delegate(&profile_);
+
+ 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.note = std::make_unique<std::string>();
+ 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::
+ IMPORT_ENTRY_STATUS_NONE) ==
+ static_cast<int>(password_manager::ImportEntry::Status::NONE),
+ "");
+ static_assert(static_cast<int>(api::passwords_private::ImportEntryStatus::
+ IMPORT_ENTRY_STATUS_UNKNOWN_ERROR) ==
+ static_cast<int>(
+ password_manager::ImportEntry::Status::UNKNOWN_ERROR),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportEntryStatus::
+ IMPORT_ENTRY_STATUS_MISSING_PASSWORD) ==
+ static_cast<int>(
+ password_manager::ImportEntry::Status::MISSING_PASSWORD),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportEntryStatus::
+ IMPORT_ENTRY_STATUS_MISSING_URL) ==
+ static_cast<int>(password_manager::ImportEntry::Status::MISSING_URL),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportEntryStatus::
+ IMPORT_ENTRY_STATUS_INVALID_URL) ==
+ static_cast<int>(password_manager::ImportEntry::Status::INVALID_URL),
+ "");
+ static_assert(static_cast<int>(api::passwords_private::ImportEntryStatus::
+ IMPORT_ENTRY_STATUS_NON_ASCII_URL) ==
+ static_cast<int>(
+ password_manager::ImportEntry::Status::NON_ASCII_URL),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportEntryStatus::
+ IMPORT_ENTRY_STATUS_LONG_URL) ==
+ static_cast<int>(password_manager::ImportEntry::Status::LONG_URL),
+ "");
+ static_assert(static_cast<int>(api::passwords_private::ImportEntryStatus::
+ IMPORT_ENTRY_STATUS_LONG_PASSWORD) ==
+ static_cast<int>(
+ password_manager::ImportEntry::Status::LONG_PASSWORD),
+ "");
+ static_assert(static_cast<int>(api::passwords_private::ImportEntryStatus::
+ IMPORT_ENTRY_STATUS_LONG_USERNAME) ==
+ static_cast<int>(
+ password_manager::ImportEntry::Status::LONG_USERNAME),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportEntryStatus::
+ IMPORT_ENTRY_STATUS_CONFLICT_PROFILE) ==
+ static_cast<int>(
+ password_manager::ImportEntry::Status::CONFLICT_PROFILE),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportEntryStatus::
+ IMPORT_ENTRY_STATUS_CONFLICT_ACCOUNT) ==
+ static_cast<int>(
+ password_manager::ImportEntry::Status::CONFLICT_ACCOUNT),
+ "");
+}
+
+TEST_F(PasswordsPrivateDelegateImplTest, VerifyCastingOfImportResultsStatus) {
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportResultsStatus::
+ IMPORT_RESULTS_STATUS_NONE) ==
+ static_cast<int>(password_manager::ImportResults::Status::NONE),
+ "");
+ static_assert(static_cast<int>(api::passwords_private::ImportResultsStatus::
+ IMPORT_RESULTS_STATUS_UNKNOWN_ERROR) ==
+ static_cast<int>(
+ password_manager::ImportResults::Status::UNKNOWN_ERROR),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportResultsStatus::
+ IMPORT_RESULTS_STATUS_SUCCESS) ==
+ static_cast<int>(password_manager::ImportResults::Status::SUCCESS),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportResultsStatus::
+ IMPORT_RESULTS_STATUS_IO_ERROR) ==
+ static_cast<int>(password_manager::ImportResults::Status::IO_ERROR),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportResultsStatus::
+ IMPORT_RESULTS_STATUS_BAD_FORMAT) ==
+ static_cast<int>(password_manager::ImportResults::Status::BAD_FORMAT),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportResultsStatus::
+ IMPORT_RESULTS_STATUS_DISMISSED) ==
+ static_cast<int>(password_manager::ImportResults::Status::DISMISSED),
+ "");
+ static_assert(static_cast<int>(api::passwords_private::ImportResultsStatus::
+ IMPORT_RESULTS_STATUS_MAX_FILE_SIZE) ==
+ static_cast<int>(
+ password_manager::ImportResults::Status::MAX_FILE_SIZE),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportResultsStatus::
+ IMPORT_RESULTS_STATUS_IMPORT_ALREADY_ACTIVE) ==
+ static_cast<int>(
+ password_manager::ImportResults::Status::IMPORT_ALREADY_ACTIVE),
+ "");
+ static_assert(
+ static_cast<int>(api::passwords_private::ImportResultsStatus::
+ IMPORT_RESULTS_STATUS_NUM_PASSWORDS_EXCEEDED) ==
+ static_cast<int>(
+ password_manager::ImportResults::Status::NUM_PASSWORDS_EXCEEDED),
+ "");
+}
+
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.cc
index e1e6ff3ea2c..0474aa262fc 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.cc
@@ -45,8 +45,7 @@ void PasswordsPrivateEventRouter::SendSavedPasswordListToListeners() {
auto extension_event = std::make_unique<Event>(
events::PASSWORDS_PRIVATE_ON_SAVED_PASSWORDS_LIST_CHANGED,
api::passwords_private::OnSavedPasswordsListChanged::kEventName,
- base::Value(cached_saved_password_parameters_.value())
- .TakeListDeprecated());
+ std::move(cached_saved_password_parameters_).value());
event_router_->BroadcastEvent(std::move(extension_event));
}
@@ -66,8 +65,7 @@ void PasswordsPrivateEventRouter::SendPasswordExceptionListToListeners() {
auto extension_event = std::make_unique<Event>(
events::PASSWORDS_PRIVATE_ON_PASSWORD_EXCEPTIONS_LIST_CHANGED,
api::passwords_private::OnPasswordExceptionsListChanged::kEventName,
- base::Value(cached_password_exception_parameters_.value())
- .TakeListDeprecated());
+ std::move(cached_password_exception_parameters_).value());
event_router_->BroadcastEvent(std::move(extension_event));
}
@@ -78,8 +76,8 @@ void PasswordsPrivateEventRouter::OnPasswordsExportProgress(
params.status = status;
params.folder_name = std::make_unique<std::string>(std::move(folder_name));
- std::vector<base::Value> event_value;
- event_value.push_back(base::Value::FromUniquePtrValue(params.ToValue()));
+ base::Value::List event_value;
+ event_value.Append(base::Value::FromUniquePtrValue(params.ToValue()));
auto extension_event = std::make_unique<Event>(
events::PASSWORDS_PRIVATE_ON_PASSWORDS_FILE_EXPORT_PROGRESS,
@@ -99,7 +97,7 @@ void PasswordsPrivateEventRouter::OnAccountStorageOptInStateChanged(
}
void PasswordsPrivateEventRouter::OnCompromisedCredentialsChanged(
- std::vector<api::passwords_private::InsecureCredential>
+ std::vector<api::passwords_private::PasswordUiEntry>
compromised_credentials) {
auto extension_event = std::make_unique<Event>(
events::PASSWORDS_PRIVATE_ON_COMPROMISED_CREDENTIALS_INFO_CHANGED,
@@ -110,7 +108,7 @@ void PasswordsPrivateEventRouter::OnCompromisedCredentialsChanged(
}
void PasswordsPrivateEventRouter::OnWeakCredentialsChanged(
- std::vector<api::passwords_private::InsecureCredential> weak_credentials) {
+ std::vector<api::passwords_private::PasswordUiEntry> weak_credentials) {
auto extension_event = std::make_unique<Event>(
events::PASSWORDS_PRIVATE_ON_WEAK_CREDENTIALS_CHANGED,
api::passwords_private::OnWeakCredentialsChanged::kEventName,
@@ -128,6 +126,13 @@ void PasswordsPrivateEventRouter::OnPasswordCheckStatusChanged(
event_router_->BroadcastEvent(std::move(extension_event));
}
+void PasswordsPrivateEventRouter::OnPasswordManagerAuthTimeout() {
+ event_router_->BroadcastEvent(std::make_unique<Event>(
+ events::PASSWORDS_PRIVATE_ON_PASSWORD_MANAGER_AUTH_TIMEOUT,
+ api::passwords_private::OnPasswordManagerAuthTimeout::kEventName,
+ api::passwords_private::OnPasswordManagerAuthTimeout::Create()));
+}
+
PasswordsPrivateEventRouter* PasswordsPrivateEventRouter::Create(
content::BrowserContext* context) {
return new PasswordsPrivateEventRouter(context);
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.h b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.h
index ccfff3d319a..9225745675d 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.h
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router.h
@@ -66,18 +66,21 @@ class PasswordsPrivateEventRouter : public KeyedService {
// Notifies listeners about a change to the information about compromised
// credentials.
void OnCompromisedCredentialsChanged(
- std::vector<api::passwords_private::InsecureCredential>
+ std::vector<api::passwords_private::PasswordUiEntry>
compromised_credentials);
// Notifies listeners about a change to the information about weak
// credentials.
void OnWeakCredentialsChanged(
- std::vector<api::passwords_private::InsecureCredential> weak_credentials);
+ std::vector<api::passwords_private::PasswordUiEntry> weak_credentials);
// Notifies listeners about a change to the status of the password check.
void OnPasswordCheckStatusChanged(
const api::passwords_private::PasswordCheckStatus& status);
+ // Notifies listeners about the timeout for password manager access.
+ void OnPasswordManagerAuthTimeout();
+
protected:
explicit PasswordsPrivateEventRouter(content::BrowserContext* context);
@@ -91,9 +94,8 @@ class PasswordsPrivateEventRouter : public KeyedService {
// Cached parameters which are saved so that when new listeners are added, the
// most up-to-date lists can be sent to them immediately.
- absl::optional<std::vector<base::Value>> cached_saved_password_parameters_;
- absl::optional<std::vector<base::Value>>
- cached_password_exception_parameters_;
+ absl::optional<base::Value::List> cached_saved_password_parameters_;
+ absl::optional<base::Value::List> cached_password_exception_parameters_;
};
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.cc
index 80dd51be6e4..7b5541d6573 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.cc
@@ -6,7 +6,6 @@
#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h"
#include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/extension_system_provider.h"
#include "extensions/browser/extensions_browser_client.h"
@@ -28,9 +27,9 @@ PasswordsPrivateEventRouterFactory::GetInstance() {
}
PasswordsPrivateEventRouterFactory::PasswordsPrivateEventRouterFactory()
- : BrowserContextKeyedServiceFactory(
+ : ProfileKeyedServiceFactory(
"PasswordsPrivateEventRouter",
- BrowserContextDependencyManager::GetInstance()) {
+ ProfileSelections::BuildRedirectedInIncognito()) {
DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
DependsOn(PasswordsPrivateDelegateFactory::GetInstance());
}
@@ -44,12 +43,6 @@ KeyedService* PasswordsPrivateEventRouterFactory::BuildServiceInstanceFor(
return PasswordsPrivateEventRouter::Create(context);
}
-content::BrowserContext*
-PasswordsPrivateEventRouterFactory::GetBrowserContextToUse(
- content::BrowserContext* context) const {
- return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
-}
-
bool PasswordsPrivateEventRouterFactory::
ServiceIsCreatedWithBrowserContext() const {
return true;
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h
index 8a28211631e..f1aac153d43 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h
@@ -6,7 +6,7 @@
#define CHROME_BROWSER_EXTENSIONS_API_PASSWORDS_PRIVATE_PASSWORDS_PRIVATE_EVENT_ROUTER_FACTORY_H_
#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
namespace extensions {
@@ -15,8 +15,7 @@ class PasswordsPrivateEventRouter;
// This is a factory class used by the BrowserContextDependencyManager
// to instantiate the passwordsPrivate event router per profile (since the
// extension event router is per profile).
-class PasswordsPrivateEventRouterFactory
- : public BrowserContextKeyedServiceFactory {
+class PasswordsPrivateEventRouterFactory : public ProfileKeyedServiceFactory {
public:
PasswordsPrivateEventRouterFactory(
const PasswordsPrivateEventRouterFactory&) = delete;
@@ -33,8 +32,6 @@ class PasswordsPrivateEventRouterFactory
protected:
// BrowserContextKeyedServiceFactory overrides:
- content::BrowserContext* GetBrowserContextToUse(
- content::BrowserContext* context) const override;
bool ServiceIsCreatedWithBrowserContext() const override;
bool ServiceIsNULLWhileTesting() const override;
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils.cc
index ca14da0a05d..b611ea8e7e8 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils.cc
@@ -9,18 +9,24 @@
#include "components/password_manager/core/browser/password_form.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/browser/password_ui_utils.h"
+#include "components/password_manager/core/browser/ui/credential_ui_entry.h"
#include "url/gurl.h"
namespace extensions {
-api::passwords_private::UrlCollection CreateUrlCollectionFromForm(
- const password_manager::PasswordForm& form) {
+namespace {
+
+using password_manager::CredentialUIEntry;
+using Store = password_manager::PasswordForm::Store;
+
+} // namespace
+
+api::passwords_private::UrlCollection CreateUrlCollectionFromCredential(
+ const CredentialUIEntry& credential) {
api::passwords_private::UrlCollection urls;
- GURL link_url;
- std::tie(urls.shown, link_url) =
- password_manager::GetShownOriginAndLinkUrl(form);
- urls.origin = form.signon_realm;
- urls.link = link_url.spec();
+ urls.shown = GetShownOrigin(credential);
+ urls.link = GetShownUrl(credential).spec();
+ urls.signon_realm = credential.signon_realm;
return urls;
}
@@ -28,9 +34,26 @@ api::passwords_private::UrlCollection CreateUrlCollectionFromGURL(
const GURL& url) {
api::passwords_private::UrlCollection urls;
urls.shown = password_manager::GetShownOrigin(url::Origin::Create(url));
- urls.origin = password_manager_util::GetSignonRealm(url);
+ urls.signon_realm = password_manager_util::GetSignonRealm(url);
urls.link = url.spec();
return urls;
}
+extensions::api::passwords_private::PasswordStoreSet StoreSetFromCredential(
+ const CredentialUIEntry& credential) {
+ if (credential.stored_in.contains(Store::kAccountStore) &&
+ credential.stored_in.contains(Store::kProfileStore)) {
+ return extensions::api::passwords_private::
+ PASSWORD_STORE_SET_DEVICE_AND_ACCOUNT;
+ }
+ if (credential.stored_in.contains(Store::kAccountStore)) {
+ return extensions::api::passwords_private::PASSWORD_STORE_SET_ACCOUNT;
+ }
+ if (credential.stored_in.contains(Store::kProfileStore)) {
+ return extensions::api::passwords_private::PASSWORD_STORE_SET_DEVICE;
+ }
+ NOTREACHED();
+ return extensions::api::passwords_private::PASSWORD_STORE_SET_DEVICE;
+}
+
} // 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 2086ccd5fe7..b7f9d78b0a8 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,22 +7,25 @@
#include <functional>
#include <map>
+#include <string>
#include "base/containers/flat_map.h"
#include "chrome/common/extensions/api/passwords_private.h"
#include "url/gurl.h"
+class Profile;
+
namespace password_manager {
-struct PasswordForm;
+struct CredentialUIEntry;
} // namespace password_manager
namespace extensions {
-// Obtains a collection of URLs from the passed in |form|. This includes an
-// origin URL used for internal logic, a human friendly string shown to the user
-// as well as a URL that is linked to.
-api::passwords_private::UrlCollection CreateUrlCollectionFromForm(
- const password_manager::PasswordForm& form);
+// Obtains a collection of URLs from the passed in |credential|. This includes
+// an origin URL used for internal logic, a human friendly string shown to the
+// user as well as a URL that is linked to.
+api::passwords_private::UrlCollection CreateUrlCollectionFromCredential(
+ const password_manager::CredentialUIEntry& credential);
// Obtains a collection of URLs from the passed in |url|. This includes an
// origin URL used for internal logic, a human friendly string shown to the user
@@ -30,14 +33,18 @@ api::passwords_private::UrlCollection CreateUrlCollectionFromForm(
api::passwords_private::UrlCollection CreateUrlCollectionFromGURL(
const GURL& url);
+// Returns PasswordStoreSet for |credential|.
+extensions::api::passwords_private::PasswordStoreSet StoreSetFromCredential(
+ const password_manager::CredentialUIEntry& credential);
+
// This class is an id generator for an arbitrary key type. It is used by both
// PasswordManagerPresenter and PasswordCheckDelegate to create ids send to the
// UI. It is similar to base::IDMap, but has the following important
// differences:
// - IdGenerator owns a copy of the key data, so that clients don't need to
// worry about dangling pointers.
-// - Repeated calls to GenerateId with the same |key| are no-ops, and return the
-// same ids.
+// - Repeated calls to GenerateId with the same |key| return the same ids and
+// replace the |key|.
template <typename KeyT,
typename IdT = int32_t,
typename KeyCompare = std::less<>>
@@ -50,6 +57,7 @@ class IdGenerator {
// a == b.
IdT GenerateId(const KeyT& key) {
auto result = key_cache_.emplace(key, next_id_);
+ IdT id_for_key = result.first->second;
if (result.second) {
// In case we haven't seen |key| before, add a pointer to the inserted key
// and the corresponding id to the |id_cache_|. This insertion should
@@ -58,9 +66,15 @@ class IdGenerator {
&result.first->first);
DCHECK_EQ(&result.first->first, iter->second);
++next_id_;
+ } else {
+ // Refresh the |key| in the caches, as the |result.first->first| may
+ // compare the same due to |KeyCompare|.
+ key_cache_.erase(result.first);
+ auto new_result = key_cache_.emplace(key, id_for_key);
+ id_cache_[id_for_key] = &new_result.first->first;
}
- return result.first->second;
+ return id_for_key;
}
// This method tries to return the key corresponding to |id|. In case |id| was
diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils_unittest.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils_unittest.cc
index 44a0a6b286f..312d47a72d6 100644
--- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_utils_unittest.cc
@@ -5,20 +5,33 @@
#include "chrome/browser/extensions/api/passwords_private/passwords_private_utils.h"
#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/ui/credential_ui_entry.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace extensions {
+namespace {
+
+using password_manager::CredentialUIEntry;
+
+struct StringFirstLetterCmp {
+ bool operator()(const std::string& lhs, const std::string& rhs) const {
+ return lhs.empty() ? !rhs.empty() : lhs[0] < rhs[0];
+ }
+};
+
+} // namespace
+
TEST(CreateUrlCollectionFromFormTest, UrlsFromHtmlForm) {
password_manager::PasswordForm html_form;
html_form.url = GURL("http://example.com/LoginAuth");
html_form.signon_realm = html_form.url.DeprecatedGetOriginAsURL().spec();
api::passwords_private::UrlCollection html_urls =
- CreateUrlCollectionFromForm(html_form);
- EXPECT_EQ(html_urls.origin, "http://example.com/");
+ CreateUrlCollectionFromCredential(CredentialUIEntry(html_form));
+ EXPECT_EQ(html_urls.signon_realm, "http://example.com/");
EXPECT_EQ(html_urls.shown, "example.com");
EXPECT_EQ(html_urls.link, "http://example.com/LoginAuth");
}
@@ -31,8 +44,8 @@ TEST(CreateUrlCollectionFromFormTest, UrlsFromFederatedForm) {
url::Origin::Create(GURL("https://google.com/"));
api::passwords_private::UrlCollection federated_urls =
- CreateUrlCollectionFromForm(federated_form);
- EXPECT_EQ(federated_urls.origin, "federation://example.com/google.com");
+ CreateUrlCollectionFromCredential(CredentialUIEntry(federated_form));
+ EXPECT_EQ(federated_urls.signon_realm, "federation://example.com/google.com");
EXPECT_EQ(federated_urls.shown, "example.com");
EXPECT_EQ(federated_urls.link, "https://example.com/");
}
@@ -43,8 +56,8 @@ TEST(CreateUrlCollectionFromFormTest, UrlsFromAndroidFormWithoutDisplayName) {
android_form.app_display_name.clear();
api::passwords_private::UrlCollection android_urls =
- CreateUrlCollectionFromForm(android_form);
- EXPECT_EQ("android://example@com.example.android", android_urls.origin);
+ CreateUrlCollectionFromCredential(CredentialUIEntry(android_form));
+ EXPECT_EQ("android://example@com.example.android", android_urls.signon_realm);
EXPECT_EQ("android.example.com", android_urls.shown);
EXPECT_EQ("https://play.google.com/store/apps/details?id=com.example.android",
android_urls.link);
@@ -56,8 +69,8 @@ TEST(CreateUrlCollectionFromFormTest, UrlsFromAndroidFormWithAppName) {
android_form.app_display_name = "Example Android App";
api::passwords_private::UrlCollection android_urls =
- CreateUrlCollectionFromForm(android_form);
- EXPECT_EQ(android_urls.origin, "android://hash@com.example.android");
+ CreateUrlCollectionFromCredential(CredentialUIEntry(android_form));
+ EXPECT_EQ(android_urls.signon_realm, "android://hash@com.example.android");
EXPECT_EQ("Example Android App", android_urls.shown);
EXPECT_EQ("https://play.google.com/store/apps/details?id=com.example.android",
android_urls.link);
@@ -68,7 +81,7 @@ TEST(CreateUrlCollectionFromGURLTest, UrlsFromGURL) {
api::passwords_private::UrlCollection urls = CreateUrlCollectionFromGURL(url);
EXPECT_EQ(urls.shown, "example.com");
- EXPECT_EQ(urls.origin, "https://example.com/");
+ EXPECT_EQ(urls.signon_realm, "https://example.com/");
EXPECT_EQ(urls.link, "https://example.com/login");
}
@@ -94,6 +107,20 @@ TEST(IdGeneratorTest, GenerateIds) {
EXPECT_THAT(id_generator.TryGetKey(bar_id), Pointee(Eq("bar")));
EXPECT_THAT(id_generator.TryGetKey(baz_id), Pointee(Eq("baz")));
+
+ // Check that due to clashing |KeyCompare|, new |key|s invalidate existing
+ // |key|.
+ IdGenerator<std::string, int32_t, StringFirstLetterCmp>
+ clashing_id_generator_;
+ int crab_id = clashing_id_generator_.GenerateId("crab");
+
+ EXPECT_THAT(clashing_id_generator_.TryGetKey(crab_id), Pointee(Eq("crab")));
+
+ int chromium_id = clashing_id_generator_.GenerateId("chromium");
+
+ EXPECT_EQ(crab_id, chromium_id);
+ EXPECT_THAT(clashing_id_generator_.TryGetKey(chromium_id),
+ Pointee(Eq("chromium")));
}
} // namespace extensions
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 5ec8dfb19c5..3c2e66d7244 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
@@ -13,6 +13,7 @@
#include "chrome/browser/extensions/api/passwords_private/passwords_private_event_router_factory.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/base/l10n/time_format.h"
+#include "url/gurl.h"
namespace extensions {
@@ -25,21 +26,20 @@ 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.origin = "http://" + entry.urls.shown + "/login";
- entry.urls.link = entry.urls.origin;
+ entry.urls.signon_realm = "http://" + entry.urls.shown + "/login";
+ entry.urls.link = entry.urls.signon_realm;
entry.username = "testName" + base::NumberToString(id);
entry.id = id;
- entry.frontend_id = id;
+ entry.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
return entry;
}
api::passwords_private::ExceptionEntry CreateException(int id) {
api::passwords_private::ExceptionEntry exception;
exception.urls.shown = "exception" + base::NumberToString(id) + ".com";
- exception.urls.origin = "http://" + exception.urls.shown + "/login";
- exception.urls.link = exception.urls.origin;
+ exception.urls.signon_realm = "http://" + exception.urls.shown + "/login";
+ exception.urls.link = exception.urls.signon_realm;
exception.id = id;
- exception.frontend_id = id;
return exception;
}
} // namespace
@@ -88,66 +88,56 @@ bool TestPasswordsPrivateDelegate::AddPassword(
return !url.empty() && !password.empty();
}
-bool TestPasswordsPrivateDelegate::ChangeSavedPassword(
- const std::vector<int>& ids,
+absl::optional<int> TestPasswordsPrivateDelegate::ChangeSavedPassword(
+ const int id,
const api::passwords_private::ChangeSavedPasswordParams& params) {
- for (int id : ids) {
- if (static_cast<size_t>(id) >= current_entries_.size()) {
- return false;
- }
+ if (static_cast<size_t>(id) >= current_entries_.size()) {
+ return absl::nullopt;
}
- return !params.password.empty() && !ids.empty();
+
+ if (params.password.empty())
+ return absl::nullopt;
+
+ return id;
}
-void TestPasswordsPrivateDelegate::RemoveSavedPasswords(
- const std::vector<int>& ids) {
+void TestPasswordsPrivateDelegate::RemoveSavedPassword(
+ int id,
+ api::passwords_private::PasswordStoreSet from_stores) {
if (current_entries_.empty())
return;
- // Since this is just mock data, remove the first |ids.size()| elements
- // regardless of the data contained.
- auto first_remaining = (ids.size() <= current_entries_.size())
- ? current_entries_.begin() + ids.size()
- : current_entries_.end();
- last_deleted_entries_batch_.assign(
- std::make_move_iterator(current_entries_.begin()),
- std::make_move_iterator(first_remaining));
- current_entries_.erase(current_entries_.begin(), first_remaining);
+ // Since this is just mock data, remove the first element regardless of the
+ // data contained. One case where this logic is especially false is when the
+ // password is stored in both stores and |store| only specifies one of them
+ // (in that case the number of entries shouldn't change).
+ last_deleted_entry_ = std::move(current_entries_[0]);
+ current_entries_.erase(current_entries_.begin());
SendSavedPasswordsList();
}
-void TestPasswordsPrivateDelegate::RemovePasswordExceptions(
- const std::vector<int>& ids) {
+void TestPasswordsPrivateDelegate::RemovePasswordException(int id) {
if (current_exceptions_.empty())
return;
- // Since this is just mock data, remove the first |ids.size()| elements
- // regardless of the data contained.
- auto first_remaining = (ids.size() <= current_exceptions_.size())
- ? current_exceptions_.begin() + ids.size()
- : current_exceptions_.end();
- last_deleted_exceptions_batch_.assign(
- std::make_move_iterator(current_exceptions_.begin()),
- std::make_move_iterator(first_remaining));
- current_exceptions_.erase(current_exceptions_.begin(), first_remaining);
+ // Since this is just mock data, remove the first element regardless of the
+ // data contained.
+ last_deleted_exception_ = std::move(current_exceptions_[0]);
+ current_exceptions_.erase(current_exceptions_.begin());
SendPasswordExceptionsList();
}
// Simplified version of undo logic, only use for testing.
void TestPasswordsPrivateDelegate::UndoRemoveSavedPasswordOrException() {
- if (!last_deleted_entries_batch_.empty()) {
- current_entries_.insert(
- current_entries_.begin(),
- std::make_move_iterator(last_deleted_entries_batch_.begin()),
- std::make_move_iterator(last_deleted_entries_batch_.end()));
- last_deleted_entries_batch_.clear();
+ if (last_deleted_entry_.has_value()) {
+ current_entries_.insert(current_entries_.begin(),
+ std::move(last_deleted_entry_.value()));
+ last_deleted_entry_ = absl::nullopt;
SendSavedPasswordsList();
- } else if (!last_deleted_exceptions_batch_.empty()) {
- current_exceptions_.insert(
- current_exceptions_.begin(),
- std::make_move_iterator(last_deleted_exceptions_batch_.begin()),
- std::make_move_iterator(last_deleted_exceptions_batch_.end()));
- last_deleted_exceptions_batch_.clear();
+ } else if (last_deleted_exception_.has_value()) {
+ current_exceptions_.insert(current_exceptions_.begin(),
+ std::move(last_deleted_exception_.value()));
+ last_deleted_exception_ = absl::nullopt;
SendPasswordExceptionsList();
}
}
@@ -161,6 +151,20 @@ void TestPasswordsPrivateDelegate::RequestPlaintextPassword(
std::move(callback).Run(plaintext_password_);
}
+void TestPasswordsPrivateDelegate::RequestCredentialDetails(
+ int id,
+ RequestCredentialDetailsCallback callback,
+ content::WebContents* web_contents) {
+ api::passwords_private::PasswordUiEntry entry = CreateEntry(42);
+ if (plaintext_password_.has_value()) {
+ entry.password = std::make_unique<std::string>(
+ base::UTF16ToUTF8(plaintext_password_.value()));
+ std::move(callback).Run(std::move(entry));
+ } else {
+ std::move(callback).Run(std::move(absl::nullopt));
+ }
+}
+
void TestPasswordsPrivateDelegate::MovePasswordsToAccount(
const std::vector<int>& ids,
content::WebContents* web_contents) {
@@ -168,10 +172,16 @@ void TestPasswordsPrivateDelegate::MovePasswordsToAccount(
}
void TestPasswordsPrivateDelegate::ImportPasswords(
+ api::passwords_private::PasswordStoreSet to_store,
+ ImportResultsCallback results_callback,
content::WebContents* web_contents) {
- // The testing of password importing itself should be handled via
- // |PasswordManagerPorter|.
import_passwords_triggered_ = true;
+
+ import_results_.status = api::passwords_private::ImportResultsStatus::
+ IMPORT_RESULTS_STATUS_SUCCESS;
+ import_results_.file_name = "test.csv";
+ import_results_.number_imported = 42;
+ std::move(results_callback).Run(import_results_);
}
void TestPasswordsPrivateDelegate::ExportPasswords(
@@ -205,12 +215,13 @@ void TestPasswordsPrivateDelegate::SetAccountStorageOptIn(
is_opted_in_for_account_storage_ = opt_in;
}
-std::vector<api::passwords_private::InsecureCredential>
+std::vector<api::passwords_private::PasswordUiEntry>
TestPasswordsPrivateDelegate::GetCompromisedCredentials() {
- api::passwords_private::InsecureCredential credential;
+ api::passwords_private::PasswordUiEntry credential;
credential.username = "alice";
- credential.formatted_origin = "example.com";
- credential.detailed_origin = "https://example.com";
+ credential.urls.shown = "example.com";
+ credential.urls.link = "https://example.com";
+ credential.urls.signon_realm = "https://example.com";
credential.is_android_credential = false;
credential.change_password_url =
std::make_unique<std::string>("https://example.com/change-password");
@@ -223,80 +234,53 @@ TestPasswordsPrivateDelegate::GetCompromisedCredentials() {
TimeFormat::FORMAT_ELAPSED, TimeFormat::LENGTH_LONG, base::Days(3)));
credential.compromised_info->compromise_type =
api::passwords_private::COMPROMISE_TYPE_LEAKED;
- std::vector<api::passwords_private::InsecureCredential> credentials;
+ credential.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
+ std::vector<api::passwords_private::PasswordUiEntry> credentials;
credentials.push_back(std::move(credential));
return credentials;
}
-std::vector<api::passwords_private::InsecureCredential>
+std::vector<api::passwords_private::PasswordUiEntry>
TestPasswordsPrivateDelegate::GetWeakCredentials() {
- api::passwords_private::InsecureCredential credential;
+ api::passwords_private::PasswordUiEntry credential;
credential.username = "bob";
- credential.formatted_origin = "example.com";
- credential.detailed_origin = "https://example.com";
+ credential.urls.shown = "example.com";
+ credential.urls.link = "https://example.com";
credential.is_android_credential = false;
credential.change_password_url =
std::make_unique<std::string>("https://example.com/change-password");
- std::vector<api::passwords_private::InsecureCredential> credentials;
+ credential.stored_in = api::passwords_private::PASSWORD_STORE_SET_DEVICE;
+ std::vector<api::passwords_private::PasswordUiEntry> credentials;
credentials.push_back(std::move(credential));
return credentials;
}
-void TestPasswordsPrivateDelegate::GetPlaintextInsecurePassword(
- api::passwords_private::InsecureCredential credential,
- api::passwords_private::PlaintextReason reason,
- content::WebContents* web_contents,
- PlaintextInsecurePasswordCallback callback) {
- // Return a mocked password value.
- if (!plaintext_password_) {
- std::move(callback).Run(absl::nullopt);
- return;
- }
-
- credential.password =
- std::make_unique<std::string>(base::UTF16ToUTF8(*plaintext_password_));
- std::move(callback).Run(std::move(credential));
-}
-
-// Fake implementation of ChangeInsecureCredential. This succeeds if the
-// delegate knows of a insecure credential with the same id.
-bool TestPasswordsPrivateDelegate::ChangeInsecureCredential(
- const api::passwords_private::InsecureCredential& credential,
- base::StringPiece new_password) {
- return IsCredentialPresentInInsecureCredentialsList(credential);
-}
-
-// Fake implementation of RemoveInsecureCredential. This succeeds if the
-// delegate knows of a insecure credential with the same id.
-bool TestPasswordsPrivateDelegate::RemoveInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) {
- return base::EraseIf(insecure_credentials_,
- [&credential](const auto& insecure_credential) {
- return insecure_credential.id == credential.id;
- }) != 0;
-}
-
// Fake implementation of MuteInsecureCredential. This succeeds if the
// delegate knows of a insecure credential with the same id.
bool TestPasswordsPrivateDelegate::MuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) {
+ const api::passwords_private::PasswordUiEntry& credential) {
return IsCredentialPresentInInsecureCredentialsList(credential);
}
// Fake implementation of UnmuteInsecureCredential. This succeeds if the
// delegate knows of a insecure credential with the same id.
bool TestPasswordsPrivateDelegate::UnmuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) {
+ const api::passwords_private::PasswordUiEntry& credential) {
return IsCredentialPresentInInsecureCredentialsList(credential);
}
void TestPasswordsPrivateDelegate::RecordChangePasswordFlowStarted(
- const api::passwords_private::InsecureCredential& credential,
+ const api::passwords_private::PasswordUiEntry& credential,
bool is_manual_flow) {
last_change_flow_url_ =
credential.change_password_url ? *credential.change_password_url : "";
}
+void TestPasswordsPrivateDelegate::RefreshScriptsIfNecessary(
+ RefreshScriptsIfNecessaryCallback callback) {
+ std::move(callback).Run();
+}
+
void TestPasswordsPrivateDelegate::StartPasswordCheck(
StartPasswordCheckCallback callback) {
start_password_check_triggered_ = true;
@@ -307,6 +291,13 @@ void TestPasswordsPrivateDelegate::StopPasswordCheck() {
stop_password_check_triggered_ = true;
}
+void TestPasswordsPrivateDelegate::StartAutomatedPasswordChange(
+ const api::passwords_private::PasswordUiEntry& credential,
+ StartAutomatedPasswordChangeCallback callback) {
+ std::move(callback).Run(credential.change_password_url &&
+ GURL(*credential.change_password_url).is_valid());
+}
+
api::passwords_private::PasswordCheckStatus
TestPasswordsPrivateDelegate::GetPasswordCheckStatus() {
api::passwords_private::PasswordCheckStatus status;
@@ -338,7 +329,7 @@ void TestPasswordsPrivateDelegate::SetIsAccountStoreDefault(bool is_default) {
}
void TestPasswordsPrivateDelegate::AddCompromisedCredential(int id) {
- api::passwords_private::InsecureCredential cred;
+ api::passwords_private::PasswordUiEntry cred;
cred.id = id;
insecure_credentials_.push_back(std::move(cred));
}
@@ -358,7 +349,7 @@ void TestPasswordsPrivateDelegate::SendPasswordExceptionsList() {
}
bool TestPasswordsPrivateDelegate::IsCredentialPresentInInsecureCredentialsList(
- const api::passwords_private::InsecureCredential& credential) {
+ const api::passwords_private::PasswordUiEntry& credential) {
return std::any_of(insecure_credentials_.begin(), insecure_credentials_.end(),
[&credential](const auto& insecure_credential) {
return insecure_credential.id == credential.id;
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 4f1b84ae8dc..cd657c8b62c 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
@@ -24,14 +24,15 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
// PasswordsPrivateDelegate implementation.
void GetSavedPasswordsList(UiEntriesCallback callback) override;
void GetPasswordExceptionsList(ExceptionEntriesCallback callback) override;
- // Fake implementation of GetUrlCollection. This returns value if |url| is
+ // Fake implementation of `GetUrlCollection`. This returns a value if `url` is
// not empty.
absl::optional<api::passwords_private::UrlCollection> GetUrlCollection(
const std::string& url) override;
- // Fake implementation. This returns value set by SetIsAccountStoreDefault.
+ // Fake implementation. This returns the value set by
+ // `SetIsAccountStoreDefault`.
bool IsAccountStoreDefault(content::WebContents* web_contents) override;
- // Fake implementation of AddPassword. This returns true if |url| and
- // |password| aren't empty.
+ // Fake implementation of AddPassword. This returns true if `url` and
+ // `password` aren't empty.
bool AddPassword(const std::string& url,
const std::u16string& username,
const std::u16string& password,
@@ -39,22 +40,28 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
bool use_account_store,
content::WebContents* web_contents) override;
// Fake implementation of ChangeSavedPassword. This succeeds if the current
- // list of entries has each of the ids, vector of ids isn't empty and if the
- // new password isn't empty.
- bool ChangeSavedPassword(
- const std::vector<int>& ids,
+ // 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;
- void RemoveSavedPasswords(const std::vector<int>& id) override;
- void RemovePasswordExceptions(const std::vector<int>& ids) override;
+ void RemoveSavedPassword(
+ int id,
+ api::passwords_private::PasswordStoreSet from_store) override;
+ void RemovePasswordException(int id) override;
// Simplified version of undo logic, only use for testing.
void UndoRemoveSavedPasswordOrException() override;
void RequestPlaintextPassword(int id,
api::passwords_private::PlaintextReason reason,
PlaintextPasswordCallback callback,
content::WebContents* web_contents) override;
+ void RequestCredentialDetails(int id,
+ RequestCredentialDetailsCallback callback,
+ content::WebContents* web_contents) override;
void MovePasswordsToAccount(const std::vector<int>& ids,
content::WebContents* web_contents) override;
- void ImportPasswords(content::WebContents* web_contents) override;
+ void ImportPasswords(api::passwords_private::PasswordStoreSet to_store,
+ ImportResultsCallback results_callback,
+ content::WebContents* web_contents) override;
void ExportPasswords(base::OnceCallback<void(const std::string&)> callback,
content::WebContents* web_contents) override;
void CancelExportPasswords() override;
@@ -63,40 +70,33 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
bool IsOptedInForAccountStorage() override;
void SetAccountStorageOptIn(bool opt_in,
content::WebContents* web_contents) override;
- std::vector<api::passwords_private::InsecureCredential>
+ std::vector<api::passwords_private::PasswordUiEntry>
GetCompromisedCredentials() override;
- std::vector<api::passwords_private::InsecureCredential> GetWeakCredentials()
+ std::vector<api::passwords_private::PasswordUiEntry> GetWeakCredentials()
override;
- void GetPlaintextInsecurePassword(
- api::passwords_private::InsecureCredential credential,
- api::passwords_private::PlaintextReason reason,
- content::WebContents* web_contents,
- PlaintextInsecurePasswordCallback callback) override;
- // Fake implementation of ChangeInsecureCredential. This succeeds if the
- // delegate knows of a insecure credential with the same id.
- bool ChangeInsecureCredential(
- const api::passwords_private::InsecureCredential& credential,
- base::StringPiece new_password) override;
- // Fake implementation of RemoveInsecureCredential. This succeeds if the
- // delegate knows of a insecure credential with the same id.
- bool RemoveInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) override;
- // Fake implementation of MuteInsecureCredential. This succeeds if the
+ // Fake implementation of `MuteInsecureCredential`. This succeeds if the
// delegate knows of a insecure credential with the same id.
bool MuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) override;
- // Fake implementation of UnmuteInsecureCredential. This succeeds if the
+ const api::passwords_private::PasswordUiEntry& credential) override;
+ // Fake implementation of `UnmuteInsecureCredential`. This succeeds if the
// delegate knows of a insecure credential with the same id.
bool UnmuteInsecureCredential(
- const api::passwords_private::InsecureCredential& credential) override;
- // Fake implementation of RecordChangePasswordFlowStarted. Sets the url
- // returned by |last_change_flow_url()|.
+ 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::InsecureCredential& credential,
+ const api::passwords_private::PasswordUiEntry& credential,
bool is_manual_flow) override;
+ // Fake implementation of `RefreshScriptsIfNecessary` that directly calls
+ // `callback`.
+ void RefreshScriptsIfNecessary(
+ RefreshScriptsIfNecessaryCallback callback) override;
void StartPasswordCheck(StartPasswordCheckCallback callback) override;
void StopPasswordCheck() override;
api::passwords_private::PasswordCheckStatus GetPasswordCheckStatus() override;
+ void StartAutomatedPasswordChange(
+ const api::passwords_private::PasswordUiEntry& credential,
+ StartAutomatedPasswordChangeCallback callback) override;
password_manager::InsecureCredentialsManager* GetInsecureCredentialsManager()
override;
@@ -133,7 +133,7 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
void SendSavedPasswordsList();
void SendPasswordExceptionsList();
bool IsCredentialPresentInInsecureCredentialsList(
- const api::passwords_private::InsecureCredential& credential);
+ const api::passwords_private::PasswordUiEntry& credential);
// The current list of entries/exceptions. Cached here so that when new
// observers are added, this delegate can send the current lists without
// having to request them from |password_manager_presenter_| again.
@@ -141,17 +141,18 @@ class TestPasswordsPrivateDelegate : public PasswordsPrivateDelegate {
std::vector<api::passwords_private::ExceptionEntry> current_exceptions_;
// Simplified version of an undo manager that only allows undoing and redoing
- // the very last deletion. When the batches are *empty*, this means there is
+ // the very last deletion. When the entries are nullopt, this means there is
// no previous deletion to undo.
- std::vector<api::passwords_private::PasswordUiEntry>
- last_deleted_entries_batch_;
- std::vector<api::passwords_private::ExceptionEntry>
- last_deleted_exceptions_batch_;
+ absl::optional<api::passwords_private::PasswordUiEntry> last_deleted_entry_;
+ absl::optional<api::passwords_private::ExceptionEntry>
+ last_deleted_exception_;
absl::optional<std::u16string> plaintext_password_ = u"plaintext";
+ api::passwords_private::ImportResults import_results_;
+
// List of insecure credentials.
- std::vector<api::passwords_private::InsecureCredential> insecure_credentials_;
+ std::vector<api::passwords_private::PasswordUiEntry> insecure_credentials_;
raw_ptr<Profile> profile_ = nullptr;
bool is_opted_in_for_account_storage_ = false;
diff --git a/chromium/chrome/browser/extensions/api/permissions/permissions_apitest.cc b/chromium/chrome/browser/extensions/api/permissions/permissions_apitest.cc
index cc5cdc6f999..c6d0a373a82 100644
--- a/chromium/chrome/browser/extensions/api/permissions/permissions_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/permissions/permissions_apitest.cc
@@ -100,8 +100,9 @@ IN_PROC_BROWSER_TEST_P(PermissionsApiTestWithContextType,
<< message_;
}
-// TODO(crbug/1065399): Flaky on ChromeOS and Linux non-dbg builds.
-#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(NDEBUG)
+// TODO(crbug/1065399): Flaky on ChromeOS, Linux, and Mac non-dbg builds.
+#if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)) && \
+ defined(NDEBUG)
#define MAYBE_FaviconPermission DISABLED_FaviconPermission
#else
#define MAYBE_FaviconPermission FaviconPermission
diff --git a/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc b/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc
index 2fe215dc36f..5d11cff5064 100644
--- a/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc
+++ b/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc
@@ -243,17 +243,20 @@ class PlatformKeysTest : public PlatformKeysTestBase {
}
void SetupTestCACerts() {
- net::TestRootCerts* root_certs = net::TestRootCerts::GetInstance();
// "root.pem" is the issuer of the "l1_leaf.pem" and (transitively)
// "l1_leaf.pem" certs which are loaded on the JS side. Generated by
// create_test_certs.sh .
- root_certs->AddFromFile(extension_path().AppendASCII("root.pem"));
+ scoped_refptr<net::X509Certificate> root =
+ net::ImportCertFromFile(extension_path().AppendASCII("root.pem"));
+ ASSERT_TRUE(root);
+ scoped_test_root_.Reset({root});
}
const bool key_permission_policy_;
const UserClientCertSlot user_client_cert_slot_;
crypto::ScopedTestNSSDB user_private_slot_db_;
const ContextType context_type_;
+ net::ScopedTestRoot scoped_test_root_;
};
class TestSelectDelegate
diff --git a/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc b/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
index ef2c1885407..6e73b965f26 100644
--- a/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
+++ b/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.cc
@@ -14,7 +14,7 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/cloud/test/policy_builder.h"
#include "components/policy/policy_constants.h"
@@ -100,11 +100,11 @@ void PlatformKeysTestBase::SetUpCommandLine(base::CommandLine* command_line) {
void PlatformKeysTestBase::SetUpInProcessBrowserTestFixture() {
extensions::MixinBasedExtensionApiTest::SetUpInProcessBrowserTestFixture();
- chromeos::SessionManagerClient::InitializeFakeInMemory();
+ ash::SessionManagerClient::InitializeFakeInMemory();
policy::AffiliationTestHelper affiliation_helper =
policy::AffiliationTestHelper::CreateForCloud(
- chromeos::FakeSessionManagerClient::Get());
+ ash::FakeSessionManagerClient::Get());
if (enrollment_status() == EnrollmentStatus::ENROLLED) {
std::set<std::string> device_affiliation_ids;
diff --git a/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h b/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h
index eeac4c42433..594b882474a 100644
--- a/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h
+++ b/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_test_base.h
@@ -7,10 +7,10 @@
#include <memory>
-#include "ash/components/tpm/stub_install_attributes.h"
#include "chrome/browser/ash/login/test/cryptohome_mixin.h"
#include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h"
#include "chrome/browser/extensions/mixin_based_extension_apitest.h"
+#include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
#include "components/account_id/account_id.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "google_apis/gaia/fake_gaia.h"
diff --git a/chromium/chrome/browser/extensions/api/preference/preference_api.cc b/chromium/chrome/browser/extensions/api/preference/preference_api.cc
index 30a4ccdc3d0..81b405f26ac 100644
--- a/chromium/chrome/browser/extensions/api/preference/preference_api.cc
+++ b/chromium/chrome/browser/extensions/api/preference/preference_api.cc
@@ -58,7 +58,7 @@
#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/chromeos/extensions/controlled_pref_mapping.h"
-#include "chromeos/startup/browser_init_params.h"
+#include "chromeos/startup/browser_params_proxy.h"
#endif
using extensions::mojom::APIPermissionID;
@@ -467,9 +467,9 @@ PreferenceEventRouter::PreferenceEventRouter(Profile* profile)
constexpr char kExtensionControlledPrefObserversCapability[] =
"crbug/1334985";
bool ash_supports_crosapi_observers =
- chromeos::BrowserInitParams::Get()->ash_capabilities.has_value() &&
+ chromeos::BrowserParamsProxy::Get()->AshCapabilities().has_value() &&
base::Contains(
- chromeos::BrowserInitParams::Get()->ash_capabilities.value(),
+ chromeos::BrowserParamsProxy::Get()->AshCapabilities().value(),
kExtensionControlledPrefObserversCapability);
#endif
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 9742fb20d39..fa0f7f36609 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
@@ -16,7 +16,7 @@
#include "chromeos/crosapi/mojom/prefs.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#include "chromeos/lacros/lacros_test_helper.h"
-#include "chromeos/startup/browser_init_params.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"
@@ -105,9 +105,9 @@ class ExtensionPreferenceApiLacrosBrowserTest
// writing to the ash standalone browser prefstore.
constexpr char kExtensionControlledPrefObserversCapability[] =
"crbug/1334964";
- return chromeos::BrowserInitParams::Get()->ash_capabilities.has_value() &&
+ return chromeos::BrowserParamsProxy::Get()->AshCapabilities().has_value() &&
base::Contains(
- chromeos::BrowserInitParams::Get()->ash_capabilities.value(),
+ chromeos::BrowserParamsProxy::Get()->AshCapabilities().value(),
kExtensionControlledPrefObserversCapability);
}
diff --git a/chromium/chrome/browser/extensions/api/preference/preference_helpers.cc b/chromium/chrome/browser/extensions/api/preference/preference_helpers.cc
index 2e311fc1d2c..de1be982bfc 100644
--- a/chromium/chrome/browser/extensions/api/preference/preference_helpers.cc
+++ b/chromium/chrome/browser/extensions/api/preference/preference_helpers.cc
@@ -151,10 +151,10 @@ void DispatchEventToExtensionsImpl(Profile* profile,
}
}
- base::Value args_copy = args->Clone();
- auto event = std::make_unique<Event>(
- histogram_value, event_name,
- std::move(args_copy).TakeListDeprecated(), restrict_to_profile);
+ base::Value::List args_copy = args->GetList().Clone();
+ auto event =
+ std::make_unique<Event>(histogram_value, event_name,
+ std::move(args_copy), restrict_to_profile);
router->DispatchEventToExtension(extension->id(), std::move(event));
}
}
diff --git a/chromium/chrome/browser/extensions/api/printing/print_job_submitter.cc b/chromium/chrome/browser/extensions/api/printing/print_job_submitter.cc
index 3a05db933bf..01133ce9d4a 100644
--- a/chromium/chrome/browser/extensions/api/printing/print_job_submitter.cc
+++ b/chromium/chrome/browser/extensions/api/printing/print_job_submitter.cc
@@ -77,11 +77,11 @@ bool IsUserConfirmationRequired(content::BrowserContext* browser_context,
const std::string& extension_id) {
if (g_skip_confirmation_dialog_for_testing)
return false;
- const base::Value* list =
+ const base::Value::List& list =
Profile::FromBrowserContext(browser_context)
->GetPrefs()
- ->GetList(prefs::kPrintingAPIExtensionsAllowlist);
- return !base::Contains(list->GetList(), base::Value(extension_id));
+ ->GetValueList(prefs::kPrintingAPIExtensionsAllowlist);
+ return !base::Contains(list, base::Value(extension_id));
}
} // namespace
diff --git a/chromium/chrome/browser/extensions/api/printing/print_job_submitter.h b/chromium/chrome/browser/extensions/api/printing/print_job_submitter.h
index 0e65c1d7fdd..dd8174e3cf9 100644
--- a/chromium/chrome/browser/extensions/api/printing/print_job_submitter.h
+++ b/chromium/chrome/browser/extensions/api/printing/print_job_submitter.h
@@ -10,6 +10,7 @@
#include "base/auto_reset.h"
#include "base/callback.h"
+#include "base/memory/raw_ptr.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
@@ -117,14 +118,14 @@ class PrintJobSubmitter : public printing::PrintJob::Observer {
void FireErrorCallback(const std::string& error);
gfx::NativeWindow native_window_;
- content::BrowserContext* const browser_context_;
+ const raw_ptr<content::BrowserContext> browser_context_;
// Tracks whether |native_window_| got destroyed.
std::unique_ptr<NativeWindowTracker> native_window_tracker_;
// These objects are owned by PrintingAPIHandler.
- PrintJobController* const print_job_controller_;
- mojo::Remote<printing::mojom::PdfFlattener>* const pdf_flattener_;
+ const raw_ptr<PrintJobController> print_job_controller_;
+ const raw_ptr<mojo::Remote<printing::mojom::PdfFlattener>> pdf_flattener_;
// TODO(crbug.com/996785): Consider tracking extension being unloaded instead
// of storing scoped_refptr.
@@ -139,7 +140,7 @@ class PrintJobSubmitter : public printing::PrintJob::Observer {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
const int local_printer_version_;
#endif
- crosapi::mojom::LocalPrinter* const local_printer_;
+ const raw_ptr<crosapi::mojom::LocalPrinter> local_printer_;
SubmitJobCallback callback_;
base::WeakPtrFactory<PrintJobSubmitter> weak_ptr_factory_{this};
};
diff --git a/chromium/chrome/browser/extensions/api/printing/printing_api_handler.h b/chromium/chrome/browser/extensions/api/printing/printing_api_handler.h
index 1d23385941a..614f51b92dd 100644
--- a/chromium/chrome/browser/extensions/api/printing/printing_api_handler.h
+++ b/chromium/chrome/browser/extensions/api/printing/printing_api_handler.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "build/chromeos_buildflags.h"
#include "chrome/common/extensions/api/printing.h"
@@ -156,9 +157,9 @@ class PrintingAPIHandler : public BrowserContextKeyedAPI,
static const bool kServiceIsNULLWhileTesting = true;
static const char* service_name() { return "PrintingAPIHandler"; }
- content::BrowserContext* const browser_context_;
- EventRouter* const event_router_;
- ExtensionRegistry* const extension_registry_;
+ const raw_ptr<content::BrowserContext> browser_context_;
+ const raw_ptr<EventRouter> event_router_;
+ const raw_ptr<ExtensionRegistry> extension_registry_;
std::unique_ptr<PrintJobController> print_job_controller_;
std::unique_ptr<chromeos::CupsWrapper> cups_wrapper_;
@@ -169,7 +170,7 @@ class PrintingAPIHandler : public BrowserContextKeyedAPI,
// This is needed to cancel print jobs.
base::flat_map<std::string, PrintJobInfo> print_jobs_;
- crosapi::mojom::LocalPrinter* local_printer_;
+ raw_ptr<crosapi::mojom::LocalPrinter> local_printer_;
#if BUILDFLAG(IS_CHROMEOS_LACROS)
int local_printer_version_ = 0;
#endif
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 ba3fe06c8cd..451da3c7cef 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
@@ -10,6 +10,7 @@
#include <vector>
#include "base/containers/span.h"
+#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/values_test_util.h"
#include "base/values.h"
@@ -82,7 +83,7 @@ class PrintingEventObserver : public TestEventRouter::EventObserver {
const Event& event) override {
if (event.event_name == event_name_) {
extension_id_ = extension_id;
- event_args_ = event.event_args->Clone();
+ event_args_ = base::Value(event.event_args.Clone());
}
}
@@ -92,7 +93,7 @@ class PrintingEventObserver : public TestEventRouter::EventObserver {
private:
// Event router this class should observe.
- TestEventRouter* const event_router_;
+ const raw_ptr<TestEventRouter> event_router_;
// The name of the observed event.
const std::string event_name_;
@@ -190,8 +191,8 @@ std::unique_ptr<api::printing::SubmitJob::Params> ConstructSubmitJobParams(
request.job.content_type = content_type;
request.document_blob_uuid = std::move(document_blob_uuid);
- std::vector<base::Value> args;
- args.emplace_back(base::Value::FromUniquePtrValue(request.ToValue()));
+ base::Value::List args;
+ args.Append(base::Value::FromUniquePtrValue(request.ToValue()));
return api::printing::SubmitJob::Params::Create(args);
}
@@ -430,10 +431,10 @@ class PrintingAPIHandlerUnittest : public testing::Test {
protected:
content::BrowserTaskEnvironment task_environment_;
- TestingProfile* testing_profile_;
- TestEventRouter* event_router_ = nullptr;
- FakePrintJobController* print_job_controller_;
- chromeos::TestCupsWrapper* cups_wrapper_;
+ raw_ptr<TestingProfile> testing_profile_;
+ raw_ptr<TestEventRouter> event_router_ = nullptr;
+ raw_ptr<FakePrintJobController> print_job_controller_;
+ raw_ptr<chromeos::TestCupsWrapper> cups_wrapper_;
std::unique_ptr<PrintingAPIHandler> printing_api_handler_;
scoped_refptr<const Extension> extension_;
absl::optional<api::printing::SubmitJobStatus> submit_job_status_;
diff --git a/chromium/chrome/browser/extensions/api/processes/processes_api.cc b/chromium/chrome/browser/extensions/api/processes/processes_api.cc
index 3dcc62771b6..2fbbbb63181 100644
--- a/chromium/chrome/browser/extensions/api/processes/processes_api.cc
+++ b/chromium/chrome/browser/extensions/api/processes/processes_api.cc
@@ -338,10 +338,9 @@ void ProcessesEventRouter::OnTaskUnresponsive(task_manager::TaskId id) {
api::processes::OnUnresponsive::Create(process));
}
-void ProcessesEventRouter::DispatchEvent(
- events::HistogramValue histogram_value,
- const std::string& event_name,
- std::vector<base::Value> event_args) const {
+void ProcessesEventRouter::DispatchEvent(events::HistogramValue histogram_value,
+ const std::string& event_name,
+ base::Value::List event_args) const {
EventRouter* event_router = EventRouter::Get(browser_context_);
if (event_router) {
std::unique_ptr<Event> event(
diff --git a/chromium/chrome/browser/extensions/api/processes/processes_api.h b/chromium/chrome/browser/extensions/api/processes/processes_api.h
index 32096ed78a7..a1052d82f6b 100644
--- a/chromium/chrome/browser/extensions/api/processes/processes_api.h
+++ b/chromium/chrome/browser/extensions/api/processes/processes_api.h
@@ -49,7 +49,7 @@ class ProcessesEventRouter : public task_manager::TaskManagerObserver {
void DispatchEvent(events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> event_args) const;
+ base::Value::List event_args) const;
// Determines whether there is a registered listener for the specified event.
// It helps to avoid collecting data if no one is interested in it.
diff --git a/chromium/chrome/browser/extensions/api/proxy/proxy_apitest.cc b/chromium/chrome/browser/extensions/api/proxy/proxy_apitest.cc
index 419d67415a3..599925fdc10 100644
--- a/chromium/chrome/browser/extensions/api/proxy/proxy_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/proxy/proxy_apitest.cc
@@ -46,8 +46,10 @@ class ProxySettingsApiTest : public ExtensionApiTest {
ASSERT_TRUE(pref != NULL);
EXPECT_TRUE(pref->IsExtensionControlled());
+ // TODO(https://crbug.com/1348219) This should call
+ // `PrefService::GetValueDict`.
ProxyConfigDictionary dict(
- pref_service->GetDictionary(proxy_config::prefs::kProxy)->Clone());
+ pref_service->GetValue(proxy_config::prefs::kProxy).Clone());
ProxyPrefs::ProxyMode mode;
ASSERT_TRUE(dict.GetMode(&mode));
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 09eeb775849..6a5d1e4f94b 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
@@ -9,7 +9,7 @@
#include <utility>
#include "ash/components/login/auth/extended_authenticator.h"
-#include "ash/components/login/auth/user_context.h"
+#include "ash/components/login/auth/public/user_context.h"
#include "ash/constants/ash_pref_names.h"
#include "base/bind.h"
#include "base/containers/contains.h"
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 267607de5f3..b35c33f2ff1 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
@@ -8,7 +8,6 @@
#include <memory>
-#include "ash/components/cryptohome/system_salt_getter.h"
#include "ash/components/login/auth/fake_extended_authenticator.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
@@ -43,8 +42,9 @@
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/dbus/userdataauth/fake_cryptohome_misc_client.h"
-#include "chromeos/dbus/userdataauth/fake_userdataauth_client.h"
+#include "chromeos/ash/components/cryptohome/system_salt_getter.h"
+#include "chromeos/ash/components/dbus/userdataauth/fake_cryptohome_misc_client.h"
+#include "chromeos/ash/components/dbus/userdataauth/fake_userdataauth_client.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/testing_pref_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
@@ -179,7 +179,7 @@ class QuickUnlockPrivateUnitTest
ash::UserDataAuthClient::InitializeFake();
if (std::get<0>(param) == TestType::kCryptohome) {
auto* fake_userdataauth_client_testapi =
- chromeos::FakeUserDataAuthClient::TestApi::Get();
+ ash::FakeUserDataAuthClient::TestApi::Get();
fake_userdataauth_client_testapi->set_supports_low_entropy_credentials(
true);
fake_userdataauth_client_testapi->set_enable_auth_check(true);
@@ -682,7 +682,7 @@ TEST_P(QuickUnlockPrivateUnitTest, GetAuthTokenValid) {
EXPECT_EQ(token_info->token,
quick_unlock_storage->GetAuthToken()->Identifier());
EXPECT_EQ(token_info->lifetime_seconds,
- ash::quick_unlock::AuthToken::kTokenExpirationSeconds);
+ ash::quick_unlock::AuthToken::kTokenExpiration.InSeconds());
}
// Verifies that GetAuthTokenValid fails when an invalid password is provided.
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 23cbbdd757f..9f9dece59e0 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
@@ -7,7 +7,7 @@
#include <utility>
#include "ash/components/login/auth/extended_authenticator.h"
-#include "ash/components/login/auth/user_context.h"
+#include "ash/components/login/auth/public/user_context.h"
#include "base/bind.h"
#include "chrome/browser/ash/login/quick_unlock/auth_token.h"
#include "chrome/browser/ash/login/quick_unlock/fingerprint_storage.h"
@@ -76,7 +76,7 @@ void QuickUnlockPrivateGetAuthTokenHelper::OnAuthSuccess(
ash::quick_unlock::QuickUnlockFactory::GetForProfile(profile_);
quick_unlock_storage->MarkStrongAuth();
token_info->token = quick_unlock_storage->CreateAuthToken(user_context);
- token_info->lifetime_seconds = AuthToken::kTokenExpirationSeconds;
+ token_info->lifetime_seconds = AuthToken::kTokenExpiration.InSeconds();
// The user has successfully authenticated, so we should reset pin/fingerprint
// attempt counts.
diff --git a/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.h b/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.h
index a43dbfa7d40..eff1def469c 100644
--- a/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.h
+++ b/chromium/chrome/browser/extensions/api/quick_unlock_private/quick_unlock_private_ash_utils.h
@@ -9,6 +9,7 @@
#include "ash/components/login/auth/auth_status_consumer.h"
#include "base/callback.h"
+#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "content/public/browser/browser_thread.h"
@@ -79,7 +80,7 @@ class QuickUnlockPrivateGetAuthTokenHelper
void OnAuthFailure(const ash::AuthFailure& error) override;
void OnAuthSuccess(const ash::UserContext& user_context) override;
- Profile* profile_;
+ raw_ptr<Profile> profile_;
ResultCallback callback_;
};
diff --git a/chromium/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h b/chromium/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h
index a1d9757b869..3f9bd5a9e8e 100644
--- a/chromium/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h
+++ b/chromium/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.h
@@ -77,7 +77,9 @@ class ChromeRuntimeAPIDelegate : public extensions::RuntimeAPIDelegate,
void CallUpdateCallbacks(const std::string& extension_id,
const UpdateCheckResult& result);
- raw_ptr<content::BrowserContext> browser_context_;
+ // TODO(crbug.com/1298696): unit_tests breaks with MTECheckedPtr
+ // enabled. Triage.
+ raw_ptr<content::BrowserContext, DegradeToNoOpWhenMTE> browser_context_;
content::NotificationRegistrar registrar_;
diff --git a/chromium/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate_unittest.cc b/chromium/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate_unittest.cc
index a46c51f9652..65b38a1954f 100644
--- a/chromium/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate_unittest.cc
@@ -104,16 +104,19 @@ class DownloaderTestDelegate : public ExtensionDownloaderTestDelegate {
updates_[id] = std::move(args);
}
- void StartUpdateCheck(
- ExtensionDownloader* downloader,
- ExtensionDownloaderDelegate* delegate,
- std::unique_ptr<ManifestFetchData> fetch_data) override {
+ void StartUpdateCheck(ExtensionDownloader* downloader,
+ ExtensionDownloaderDelegate* delegate,
+ std::vector<ExtensionDownloaderTask> tasks) override {
+ std::set<int> request_ids;
+ for (const ExtensionDownloaderTask& task : tasks)
+ request_ids.insert(task.request_id);
// Instead of immediately firing callbacks to the delegate in matching
// cases below, we instead post a task since the delegate typically isn't
// expecting a synchronous reply (the real code has to go do at least one
// network request before getting a response, so this is is a reasonable
// expectation by delegates).
- for (const std::string& id : fetch_data->GetExtensionIds()) {
+ for (const ExtensionDownloaderTask& task : tasks) {
+ const ExtensionId& id = task.id;
auto no_update = no_updates_.find(id);
if (no_update != no_updates_.end()) {
no_updates_.erase(no_update);
@@ -123,8 +126,7 @@ class DownloaderTestDelegate : public ExtensionDownloaderTestDelegate {
&ExtensionDownloaderDelegate::OnExtensionDownloadFailed,
base::Unretained(delegate), id,
ExtensionDownloaderDelegate::Error::NO_UPDATE_AVAILABLE,
- ExtensionDownloaderDelegate::PingResult(),
- fetch_data->request_ids(),
+ ExtensionDownloaderDelegate::PingResult(), request_ids,
ExtensionDownloaderDelegate::FailureData()));
continue;
}
@@ -140,8 +142,7 @@ class DownloaderTestDelegate : public ExtensionDownloaderTestDelegate {
&ExtensionDownloaderDelegate::OnExtensionDownloadFinished,
base::Unretained(delegate), crx_info,
false /* file_ownership_passed */, GURL(),
- ExtensionDownloaderDelegate::PingResult(),
- fetch_data->request_ids(),
+ ExtensionDownloaderDelegate::PingResult(), request_ids,
ExtensionDownloaderDelegate::InstallCallback()));
continue;
}
diff --git a/chromium/chrome/browser/extensions/api/runtime/runtime_apitest.cc b/chromium/chrome/browser/extensions/api/runtime/runtime_apitest.cc
index c2ef475804d..b18741fd0e7 100644
--- a/chromium/chrome/browser/extensions/api/runtime/runtime_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/runtime/runtime_apitest.cc
@@ -498,7 +498,11 @@ IN_PROC_BROWSER_TEST_P(BackgroundPageOnlyRuntimeApiTest,
}
{
- content::DOMMessageQueue message_queue;
+ ExtensionHost* host = ProcessManager::Get(browser()->profile())
+ ->GetBackgroundHostForExtension(extension->id());
+ ASSERT_TRUE(host);
+ content::DOMMessageQueue message_queue(host->host_contents());
+
static constexpr char kScript[] = R"(
const foundWindows = chrome.extension.getViews({type: 'tab'});
domAutomationController.send(foundWindows.length);
diff --git a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
index 8ee19900fb5..b63799126eb 100644
--- a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
+++ b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
@@ -21,6 +21,8 @@
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/enterprise/connectors/connectors_service.h"
+#include "chrome/browser/enterprise/connectors/reporting/realtime_reporting_client_factory.h"
+#include "chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
@@ -56,23 +58,12 @@
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#else
-#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "components/enterprise/browser/controller/browser_dm_token_storage.h"
#include "components/enterprise/browser/controller/chrome_browser_cloud_management_controller.h"
#endif
namespace {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-const char kActiveDirectoryPolicyClientDescription[] = "an Active Directory";
-const char kPolicyClientDescription[] = "any";
-const char kUserPolicyClientDescription[] = "a user";
-#else
-const char kChromeBrowserCloudManagementClientDescription[] =
- "a machine-level user";
-#endif
-const char kProfilePolicyClientDescription[] = "a profile-level user";
-
const char16_t kMaskedUsername[] = u"*****";
void AddAnalysisConnectorVerdictToEvent(
@@ -105,11 +96,6 @@ std::string MalwareRuleToThreatType(const std::string& rule_name) {
}
}
-bool IsClientValid(const std::string& dm_token,
- policy::CloudPolicyClient* client) {
- return client && client->dm_token() == dm_token;
-}
-
std::string DangerTypeToThreatType(download::DownloadDangerType danger_type) {
switch (danger_type) {
case download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
@@ -224,7 +210,9 @@ const char
const char SafeBrowsingPrivateEventRouter::kKeyUserJustification[] =
"userJustification";
-// All new event names should be added to the kAllEvents array below!
+// All new event names should be added to the array
+// `enterprise_connectors::ReportingServiceSettings::kAllReportingEvents` in
+// `chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h`
const char SafeBrowsingPrivateEventRouter::kKeyPasswordReuseEvent[] =
"passwordReuseEvent";
const char SafeBrowsingPrivateEventRouter::kKeyPasswordChangedEvent[] =
@@ -240,17 +228,6 @@ const char SafeBrowsingPrivateEventRouter::kKeyUnscannedFileEvent[] =
const char SafeBrowsingPrivateEventRouter::kKeyLoginEvent[] = "loginEvent";
const char SafeBrowsingPrivateEventRouter::kKeyPasswordBreachEvent[] =
"passwordBreachEvent";
-// All new event names should be added to this array!
-const char* SafeBrowsingPrivateEventRouter::kAllEvents[8] = {
- SafeBrowsingPrivateEventRouter::kKeyPasswordReuseEvent,
- SafeBrowsingPrivateEventRouter::kKeyPasswordChangedEvent,
- SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent,
- SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent,
- SafeBrowsingPrivateEventRouter::kKeySensitiveDataEvent,
- SafeBrowsingPrivateEventRouter::kKeyUnscannedFileEvent,
- SafeBrowsingPrivateEventRouter::kKeyLoginEvent,
- SafeBrowsingPrivateEventRouter::kKeyPasswordBreachEvent,
-};
const char SafeBrowsingPrivateEventRouter::kKeyUnscannedReason[] =
"unscannedReason";
@@ -268,14 +245,12 @@ SafeBrowsingPrivateEventRouter::SafeBrowsingPrivateEventRouter(
event_router_ = EventRouter::Get(context_);
identity_manager_ = IdentityManagerFactory::GetForProfile(
Profile::FromBrowserContext(context_));
+ reporting_client_ =
+ enterprise_connectors::RealtimeReportingClientFactory::GetForProfile(
+ context);
}
-SafeBrowsingPrivateEventRouter::~SafeBrowsingPrivateEventRouter() {
- if (browser_client_)
- browser_client_->RemoveObserver(this);
- if (profile_client_)
- profile_client_->RemoveObserver(this);
-}
+SafeBrowsingPrivateEventRouter::~SafeBrowsingPrivateEventRouter() = default;
// static
std::string SafeBrowsingPrivateEventRouter::GetBaseName(
@@ -301,8 +276,8 @@ void SafeBrowsingPrivateEventRouter::OnPolicySpecifiedPasswordReuseDetected(
// |event_router_| can be null in tests.
if (event_router_) {
- std::vector<base::Value> event_value;
- event_value.push_back(base::Value::FromUniquePtrValue(params.ToValue()));
+ base::Value::List event_value;
+ event_value.Append(base::Value::FromUniquePtrValue(params.ToValue()));
auto extension_event = std::make_unique<Event>(
events::
@@ -314,7 +289,7 @@ void SafeBrowsingPrivateEventRouter::OnPolicySpecifiedPasswordReuseDetected(
}
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value() ||
settings->enabled_event_names.count(kKeyPasswordReuseEvent) == 0) {
return;
@@ -330,16 +305,16 @@ void SafeBrowsingPrivateEventRouter::OnPolicySpecifiedPasswordReuseDetected(
warning_shown ? safe_browsing::EventResult::WARNED
: safe_browsing::EventResult::ALLOWED));
- ReportRealtimeEvent(kKeyPasswordReuseEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(
+ kKeyPasswordReuseEvent, std::move(settings.value()), std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnPolicySpecifiedPasswordChanged(
const std::string& user_name) {
// |event_router_| can be null in tests.
if (event_router_) {
- std::vector<base::Value> event_value;
- event_value.push_back(base::Value(user_name));
+ base::Value::List event_value;
+ event_value.Append(user_name);
auto extension_event = std::make_unique<Event>(
events::SAFE_BROWSING_PRIVATE_ON_POLICY_SPECIFIED_PASSWORD_CHANGED,
api::safe_browsing_private::OnPolicySpecifiedPasswordChanged::
@@ -349,7 +324,7 @@ void SafeBrowsingPrivateEventRouter::OnPolicySpecifiedPasswordChanged(
}
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value() ||
settings->enabled_event_names.count(kKeyPasswordChangedEvent) == 0) {
return;
@@ -359,8 +334,8 @@ void SafeBrowsingPrivateEventRouter::OnPolicySpecifiedPasswordChanged(
event.Set(kKeyUserName, user_name);
event.Set(kKeyProfileUserName, GetProfileUserName());
- ReportRealtimeEvent(kKeyPasswordChangedEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(
+ kKeyPasswordChangedEvent, std::move(settings.value()), std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnDangerousDownloadOpened(
@@ -379,8 +354,8 @@ void SafeBrowsingPrivateEventRouter::OnDangerousDownloadOpened(
// |event_router_| can be null in tests.
if (event_router_) {
- std::vector<base::Value> event_value;
- event_value.push_back(base::Value::FromUniquePtrValue(params.ToValue()));
+ base::Value::List event_value;
+ event_value.Append(base::Value::FromUniquePtrValue(params.ToValue()));
auto extension_event = std::make_unique<Event>(
events::SAFE_BROWSING_PRIVATE_ON_DANGEROUS_DOWNLOAD_OPENED,
@@ -390,7 +365,7 @@ void SafeBrowsingPrivateEventRouter::OnDangerousDownloadOpened(
}
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value() ||
settings->enabled_event_names.count(kKeyDangerousDownloadEvent) == 0) {
return;
@@ -417,8 +392,9 @@ void SafeBrowsingPrivateEventRouter::OnDangerousDownloadOpened(
event.Set(kKeyScanId, scan_id);
}
- ReportRealtimeEvent(kKeyDangerousDownloadEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(kKeyDangerousDownloadEvent,
+ std::move(settings.value()),
+ std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnSecurityInterstitialShown(
@@ -436,8 +412,8 @@ void SafeBrowsingPrivateEventRouter::OnSecurityInterstitialShown(
// |event_router_| can be null in tests.
if (event_router_) {
- std::vector<base::Value> event_value;
- event_value.push_back(base::Value::FromUniquePtrValue(params.ToValue()));
+ base::Value::List event_value;
+ event_value.Append(base::Value::FromUniquePtrValue(params.ToValue()));
auto extension_event = std::make_unique<Event>(
events::SAFE_BROWSING_PRIVATE_ON_SECURITY_INTERSTITIAL_SHOWN,
@@ -447,7 +423,7 @@ void SafeBrowsingPrivateEventRouter::OnSecurityInterstitialShown(
}
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value() ||
settings->enabled_event_names.count(kKeyInterstitialEvent) == 0) {
return;
@@ -466,8 +442,8 @@ void SafeBrowsingPrivateEventRouter::OnSecurityInterstitialShown(
event.Set(kKeyClickedThrough, false);
event.Set(kKeyEventResult, safe_browsing::EventResultToString(event_result));
- ReportRealtimeEvent(kKeyInterstitialEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(
+ kKeyInterstitialEvent, std::move(settings.value()), std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnSecurityInterstitialProceeded(
@@ -485,8 +461,8 @@ void SafeBrowsingPrivateEventRouter::OnSecurityInterstitialProceeded(
// |event_router_| can be null in tests.
if (event_router_) {
- std::vector<base::Value> event_value;
- event_value.push_back(base::Value::FromUniquePtrValue(params.ToValue()));
+ base::Value::List event_value;
+ event_value.Append(base::Value::FromUniquePtrValue(params.ToValue()));
auto extension_event = std::make_unique<Event>(
events::SAFE_BROWSING_PRIVATE_ON_SECURITY_INTERSTITIAL_PROCEEDED,
@@ -496,7 +472,7 @@ void SafeBrowsingPrivateEventRouter::OnSecurityInterstitialProceeded(
}
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value() ||
settings->enabled_event_names.count(kKeyInterstitialEvent) == 0) {
return;
@@ -511,8 +487,8 @@ void SafeBrowsingPrivateEventRouter::OnSecurityInterstitialProceeded(
event.Set(kKeyEventResult, safe_browsing::EventResultToString(
safe_browsing::EventResult::BYPASSED));
- ReportRealtimeEvent(kKeyInterstitialEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(
+ kKeyInterstitialEvent, std::move(settings.value()), std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnAnalysisConnectorResult(
@@ -553,7 +529,7 @@ void SafeBrowsingPrivateEventRouter::OnDangerousDeepScanningResult(
const std::string& evidence_locker_filepath,
const std::string& scan_id) {
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value() ||
settings->enabled_event_names.count(kKeyDangerousDownloadEvent) == 0) {
return;
@@ -590,8 +566,9 @@ void SafeBrowsingPrivateEventRouter::OnDangerousDeepScanningResult(
event.Set(kKeyScanId, scan_id);
}
- ReportRealtimeEvent(kKeyDangerousDownloadEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(kKeyDangerousDownloadEvent,
+ std::move(settings.value()),
+ std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnSensitiveDataEvent(
@@ -605,7 +582,7 @@ void SafeBrowsingPrivateEventRouter::OnSensitiveDataEvent(
const int64_t content_size,
safe_browsing::EventResult event_result) {
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value() ||
settings->enabled_event_names.count(kKeySensitiveDataEvent) == 0) {
return;
@@ -633,8 +610,8 @@ void SafeBrowsingPrivateEventRouter::OnSensitiveDataEvent(
AddAnalysisConnectorVerdictToEvent(result, event);
- ReportRealtimeEvent(kKeySensitiveDataEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(
+ kKeySensitiveDataEvent, std::move(settings.value()), std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnAnalysisConnectorWarningBypassed(
@@ -649,7 +626,7 @@ void SafeBrowsingPrivateEventRouter::OnAnalysisConnectorWarningBypassed(
const int64_t content_size,
absl::optional<std::u16string> user_justification) {
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value() ||
settings->enabled_event_names.count(kKeySensitiveDataEvent) == 0) {
return;
@@ -680,8 +657,8 @@ void SafeBrowsingPrivateEventRouter::OnAnalysisConnectorWarningBypassed(
AddAnalysisConnectorVerdictToEvent(result, event);
- ReportRealtimeEvent(kKeySensitiveDataEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(
+ kKeySensitiveDataEvent, std::move(settings.value()), std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnUnscannedFileEvent(
@@ -695,7 +672,7 @@ void SafeBrowsingPrivateEventRouter::OnUnscannedFileEvent(
const int64_t content_size,
safe_browsing::EventResult event_result) {
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value() ||
settings->enabled_event_names.count(kKeyUnscannedFileEvent) == 0) {
return;
@@ -718,8 +695,8 @@ void SafeBrowsingPrivateEventRouter::OnUnscannedFileEvent(
event.Set(kKeyClickedThrough,
event_result == safe_browsing::EventResult::BYPASSED);
- ReportRealtimeEvent(kKeyUnscannedFileEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(
+ kKeyUnscannedFileEvent, std::move(settings.value()), std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnDangerousDownloadEvent(
@@ -746,7 +723,7 @@ void SafeBrowsingPrivateEventRouter::OnDangerousDownloadEvent(
const int64_t content_size,
safe_browsing::EventResult event_result) {
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value() ||
settings->enabled_event_names.count(kKeyDangerousDownloadEvent) == 0) {
return;
@@ -774,8 +751,9 @@ void SafeBrowsingPrivateEventRouter::OnDangerousDownloadEvent(
event.Set(kKeyScanId, scan_id);
}
- ReportRealtimeEvent(kKeyDangerousDownloadEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(kKeyDangerousDownloadEvent,
+ std::move(settings.value()),
+ std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnDangerousDownloadWarningBypassed(
@@ -800,7 +778,7 @@ void SafeBrowsingPrivateEventRouter::OnDangerousDownloadWarningBypassed(
const std::string& scan_id,
const int64_t content_size) {
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value() ||
settings->enabled_event_names.count(kKeyDangerousDownloadEvent) == 0) {
return;
@@ -828,8 +806,9 @@ void SafeBrowsingPrivateEventRouter::OnDangerousDownloadWarningBypassed(
event.Set(kKeyScanId, scan_id);
}
- ReportRealtimeEvent(kKeyDangerousDownloadEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(kKeyDangerousDownloadEvent,
+ std::move(settings.value()),
+ std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnLoginEvent(
@@ -838,7 +817,7 @@ void SafeBrowsingPrivateEventRouter::OnLoginEvent(
const url::Origin& federated_origin,
const std::u16string& username) {
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value()) {
return;
}
@@ -858,15 +837,15 @@ void SafeBrowsingPrivateEventRouter::OnLoginEvent(
event.Set(kKeyProfileUserName, GetProfileUserName());
event.Set(kKeyLoginUserName, MaskUsername(username));
- ReportRealtimeEvent(kKeyLoginEvent, std::move(settings.value()),
- std::move(event));
+ reporting_client_->ReportRealtimeEvent(
+ kKeyLoginEvent, std::move(settings.value()), std::move(event));
}
void SafeBrowsingPrivateEventRouter::OnPasswordBreach(
const std::string& trigger,
const std::vector<std::pair<GURL, std::u16string>>& identities) {
absl::optional<enterprise_connectors::ReportingSettings> settings =
- GetReportingSettings();
+ reporting_client_->GetReportingSettings();
if (!settings.has_value()) {
return;
}
@@ -887,7 +866,7 @@ void SafeBrowsingPrivateEventRouter::OnPasswordBreach(
base::Value::Dict identity;
identity.Set(kKeyPasswordBreachIdentitiesUrl, i.first.spec());
- identity.Set(kKeyPasswordBreachIdentitiesUsername, i.second);
+ identity.Set(kKeyPasswordBreachIdentitiesUsername, MaskUsername(i.second));
identities_list.Append(std::move(identity));
}
@@ -900,40 +879,8 @@ void SafeBrowsingPrivateEventRouter::OnPasswordBreach(
event.Set(kKeyPasswordBreachIdentities, std::move(identities_list));
event.Set(kKeyProfileUserName, GetProfileUserName());
- ReportRealtimeEvent(kKeyPasswordBreachEvent, std::move(settings.value()),
- std::move(event));
-}
-
-// static
-bool SafeBrowsingPrivateEventRouter::ShouldInitRealtimeReportingClient() {
- if (!base::FeatureList::IsEnabled(kRealtimeReportingFeature) &&
- !base::FeatureList::IsEnabled(
- enterprise_connectors::kEnterpriseConnectorsEnabled)) {
- DVLOG(2) << "Safe browsing real-time reporting is not enabled.";
- return false;
- }
-
- return true;
-}
-
-void SafeBrowsingPrivateEventRouter::SetBrowserCloudPolicyClientForTesting(
- policy::CloudPolicyClient* client) {
- if (client == nullptr && browser_client_)
- browser_client_->RemoveObserver(this);
-
- browser_client_ = client;
- if (browser_client_)
- browser_client_->AddObserver(this);
-}
-
-void SafeBrowsingPrivateEventRouter::SetProfileCloudPolicyClientForTesting(
- policy::CloudPolicyClient* client) {
- if (client == nullptr && profile_client_)
- profile_client_->RemoveObserver(this);
-
- profile_client_ = client;
- if (profile_client_)
- profile_client_->AddObserver(this);
+ reporting_client_->ReportRealtimeEvent(
+ kKeyPasswordBreachEvent, std::move(settings.value()), std::move(event));
}
void SafeBrowsingPrivateEventRouter::SetIdentityManagerForTesting(
@@ -941,291 +888,8 @@ void SafeBrowsingPrivateEventRouter::SetIdentityManagerForTesting(
identity_manager_ = identity_manager;
}
-void SafeBrowsingPrivateEventRouter::InitRealtimeReportingClient(
- const enterprise_connectors::ReportingSettings& settings) {
- // If the corresponding client is already initialized, do nothing.
- if ((settings.per_profile &&
- IsClientValid(settings.dm_token, profile_client_)) ||
- (!settings.per_profile &&
- IsClientValid(settings.dm_token, browser_client_))) {
- DVLOG(2) << "Safe browsing real-time event reporting already initialized.";
- return;
- }
-
- if (!ShouldInitRealtimeReportingClient())
- return;
-
- // |identity_manager_| may be null in tests. If there is no identity
- // manager don't enable the real-time reporting API since the router won't
- // be able to fill in all the info needed for the reports.
- if (!identity_manager_) {
- DVLOG(2) << "Safe browsing real-time event requires an identity manager.";
- return;
- }
-
- policy::CloudPolicyClient* client = nullptr;
- std::string policy_client_desc;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- std::pair<std::string, policy::CloudPolicyClient*> desc_and_client =
- InitBrowserReportingClient(settings.dm_token);
-#else
- std::pair<std::string, policy::CloudPolicyClient*> desc_and_client =
- settings.per_profile ? InitProfileReportingClient(settings.dm_token)
- : InitBrowserReportingClient(settings.dm_token);
-#endif
- if (!desc_and_client.second)
- return;
- policy_client_desc = std::move(desc_and_client.first);
- client = std::move(desc_and_client.second);
-
- OnCloudPolicyClientAvailable(policy_client_desc, client);
-}
-
-std::pair<std::string, policy::CloudPolicyClient*>
-SafeBrowsingPrivateEventRouter::InitBrowserReportingClient(
- const std::string& dm_token) {
- // |device_management_service| may be null in tests. If there is no device
- // management service don't enable the real-time reporting API since the
- // router won't be able to create the reporting server client below.
- policy::DeviceManagementService* device_management_service =
- g_browser_process->browser_policy_connector()
- ->device_management_service();
- std::string policy_client_desc;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- policy_client_desc = kPolicyClientDescription;
-#else
- policy_client_desc = kChromeBrowserCloudManagementClientDescription;
-#endif
- if (!device_management_service) {
- DVLOG(2) << "Safe browsing real-time event requires a device management "
- "service.";
- return {policy_client_desc, nullptr};
- }
-
- policy::CloudPolicyClient* client = nullptr;
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- const user_manager::User* user = GetChromeOSUser();
- if (user) {
- Profile* profile = ash::ProfileHelper::Get()->GetProfileByUser(user);
- // If primary user profile is not finalized, use the current profile.
- if (!profile)
- profile = Profile::FromBrowserContext(context_);
- DCHECK(profile);
- if (user->IsActiveDirectoryUser()) {
- // TODO(crbug.com/1012048): Handle AD, likely through crbug.com/1012170.
- policy_client_desc = kActiveDirectoryPolicyClientDescription;
- } else {
- policy_client_desc = kUserPolicyClientDescription;
- policy::UserCloudPolicyManagerAsh* policy_manager =
- profile->GetUserCloudPolicyManagerAsh();
- if (policy_manager)
- client = policy_manager->core()->client();
- }
- } else {
- LOG(ERROR) << "Could not determine who the user is.";
- }
-#else
- std::string client_id =
- policy::BrowserDMTokenStorage::Get()->RetrieveClientId();
-#if BUILDFLAG(IS_CHROMEOS_LACROS)
- Profile* main_profile = enterprise_connectors::GetMainProfileLacros();
- if (main_profile) {
- // Prefer the user client id if available.
- client_id = reporting::GetUserClientId(main_profile).value_or(client_id);
- }
-#endif
-
- // Make sure DeviceManagementService has been initialized.
- device_management_service->ScheduleInitialization(0);
-
- browser_private_client_ = std::make_unique<policy::CloudPolicyClient>(
- device_management_service, g_browser_process->shared_url_loader_factory(),
- policy::CloudPolicyClient::DeviceDMTokenCallback());
- client = browser_private_client_.get();
-
- // TODO(crbug.com/1069049): when we decide to add the extra URL parameters to
- // the uploaded reports, do the following:
- // client->add_connector_url_params(base::FeatureList::IsEnabled(
- // enterprise_connectors::kEnterpriseConnectorsEnabled));
- if (!client->is_registered()) {
- client->SetupRegistration(
- dm_token, client_id,
- /*user_affiliation_ids=*/std::vector<std::string>());
- }
-#endif
-
- return {policy_client_desc, client};
-}
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
-std::pair<std::string, policy::CloudPolicyClient*>
-SafeBrowsingPrivateEventRouter::InitProfileReportingClient(
- const std::string& dm_token) {
- policy::UserCloudPolicyManager* policy_manager =
- Profile::FromBrowserContext(context_)->GetUserCloudPolicyManager();
- if (!policy_manager || !policy_manager->core() ||
- !policy_manager->core()->client()) {
- return {kProfilePolicyClientDescription, nullptr};
- }
-
- profile_private_client_ = std::make_unique<policy::CloudPolicyClient>(
- policy_manager->core()->client()->service(),
- g_browser_process->shared_url_loader_factory(),
- policy::CloudPolicyClient::DeviceDMTokenCallback());
- policy::CloudPolicyClient* client = profile_private_client_.get();
-
- // TODO(crbug.com/1069049): when we decide to add the extra URL parameters to
- // the uploaded reports, do the following:
- // client->add_connector_url_params(base::FeatureList::IsEnabled(
- // enterprise_connectors::kEnterpriseConnectorsEnabled));
-
- client->SetupRegistration(dm_token,
- policy_manager->core()->client()->client_id(),
- /*user_affiliation_ids*/ {});
-
- return {kProfilePolicyClientDescription, client};
-}
-#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
-
-void SafeBrowsingPrivateEventRouter::OnCloudPolicyClientAvailable(
- const std::string& policy_client_desc,
- policy::CloudPolicyClient* client) {
- if (policy_client_desc == kProfilePolicyClientDescription)
- profile_client_ = client;
- else
- browser_client_ = client;
-
- if (client == nullptr) {
- LOG(ERROR) << "Could not obtain " << policy_client_desc
- << " for safe browsing real-time event reporting.";
- return;
- }
-
- client->AddObserver(this);
-
- VLOG(1) << "Ready for safe browsing real-time event reporting.";
-}
-
-absl::optional<enterprise_connectors::ReportingSettings>
-SafeBrowsingPrivateEventRouter::GetReportingSettings() {
- return enterprise_connectors::ConnectorsServiceFactory::GetForBrowserContext(
- context_)
- ->GetReportingSettings(
- enterprise_connectors::ReportingConnector::SECURITY_EVENT);
-}
-
-void SafeBrowsingPrivateEventRouter::ReportRealtimeEvent(
- const std::string& name,
- const enterprise_connectors::ReportingSettings& settings,
- base::Value::Dict event) {
- if (rejected_dm_token_timers_.contains(settings.dm_token)) {
- return;
- }
-
-#ifndef NDEBUG
- // Make sure that the event is included in the kAllEvents array.
- bool found = false;
- for (const char* known_event_name :
- extensions::SafeBrowsingPrivateEventRouter::kAllEvents) {
- if (name == known_event_name) {
- found = true;
- break;
- }
- }
- DCHECK(found);
-#endif
-
- // Make sure real-time reporting is initialized.
- InitRealtimeReportingClient(settings);
- if ((settings.per_profile && !profile_client_) ||
- (!settings.per_profile && !browser_client_)) {
- return;
- }
-
- // Format the current time (UTC) in RFC3339 format.
- base::Time::Exploded now_exploded;
- base::Time::Now().UTCExplode(&now_exploded);
- std::string now_str = base::StringPrintf(
- "%d-%02d-%02dT%02d:%02d:%02d.%03dZ", now_exploded.year,
- now_exploded.month, now_exploded.day_of_month, now_exploded.hour,
- now_exploded.minute, now_exploded.second, now_exploded.millisecond);
-
- policy::CloudPolicyClient* client =
- settings.per_profile ? profile_client_.get() : browser_client_.get();
- base::Value::Dict wrapper;
- wrapper.Set("time", now_str);
- wrapper.Set(name, std::move(event));
-
- auto upload_callback = base::BindOnce(
- [](base::Value::Dict wrapper, bool per_profile, std::string dm_token,
- bool uploaded) {
- // Show the report on chrome://safe-browsing, if appropriate.
- wrapper.Set("uploaded_successfully", uploaded);
- wrapper.Set(per_profile ? "profile_dm_token" : "browser_dm_token",
- std::move(dm_token));
- safe_browsing::WebUIInfoSingleton::GetInstance()->AddToReportingEvents(
- std::move(wrapper));
- },
- wrapper.Clone(), settings.per_profile, client->dm_token());
-
- base::Value::List event_list;
- event_list.Append(std::move(wrapper));
-
- Profile* profile = Profile::FromBrowserContext(context_);
-
- client->UploadSecurityEventReport(
- context_,
- enterprise_connectors::IncludeDeviceInfo(profile, settings.per_profile),
- policy::RealtimeReportingJobConfiguration::BuildReport(
- std::move(event_list),
- reporting::GetContext(Profile::FromBrowserContext(context_))),
- std::move(upload_callback));
-}
-
std::string SafeBrowsingPrivateEventRouter::GetProfileUserName() const {
return safe_browsing::GetProfileEmail(identity_manager_);
}
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-// static
-const user_manager::User* SafeBrowsingPrivateEventRouter::GetChromeOSUser() {
- return user_manager::UserManager::IsInitialized()
- ? user_manager::UserManager::Get()->GetPrimaryUser()
- : nullptr;
-}
-
-#endif
-
-void SafeBrowsingPrivateEventRouter::RemoveDmTokenFromRejectedSet(
- const std::string& dm_token) {
- rejected_dm_token_timers_.erase(dm_token);
-}
-
-void SafeBrowsingPrivateEventRouter::OnClientError(
- policy::CloudPolicyClient* client) {
- base::Value::Dict error_value;
- error_value.Set("error",
- "An event got an error status and hasn't been reported");
- error_value.Set("status", client->status());
- safe_browsing::WebUIInfoSingleton::GetInstance()->AddToReportingEvents(
- error_value);
-
- // This is the status set when the server returned 403, which is what the
- // reporting server returns when the customer is not allowed to report events.
- if (client->status() == policy::DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED) {
- // This could happen if a second event was fired before the first one
- // returned an error.
- if (!rejected_dm_token_timers_.contains(client->dm_token())) {
- rejected_dm_token_timers_[client->dm_token()] =
- std::make_unique<base::OneShotTimer>();
- rejected_dm_token_timers_[client->dm_token()]->Start(
- FROM_HERE, base::Hours(24),
- base::BindOnce(
- &SafeBrowsingPrivateEventRouter::RemoveDmTokenFromRejectedSet,
- weak_ptr_factory_.GetWeakPtr(), client->dm_token()));
- }
- }
-}
-
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h
index 129bf100328..75311fa0759 100644
--- a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h
+++ b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h
@@ -15,6 +15,7 @@
#include "base/values.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/enterprise/connectors/common.h"
+#include "chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
#include "components/download/public/common/download_danger_type.h"
#include "components/keyed_service/core/keyed_service.h"
@@ -35,30 +36,16 @@ class IdentityManager;
class GURL;
-namespace policy {
-class DeviceManagementService;
-}
-
namespace safe_browsing {
enum class DeepScanAccessPoint;
}
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-
-namespace user_manager {
-class User;
-}
-
-#endif
-
namespace extensions {
// An event router that observes Safe Browsing events and notifies listeners.
// The router also uploads events to the chrome reporting server side API if
// the kRealtimeReportingFeature feature is enabled.
-class SafeBrowsingPrivateEventRouter
- : public KeyedService,
- public policy::CloudPolicyClient::Observer {
+class SafeBrowsingPrivateEventRouter : public KeyedService {
public:
// Feature that controls whether real-time reports are sent.
static const base::Feature kRealtimeReportingFeature;
@@ -102,7 +89,6 @@ class SafeBrowsingPrivateEventRouter
static const char kKeyUnscannedFileEvent[];
static const char kKeyLoginEvent[];
static const char kKeyPasswordBreachEvent[];
- static const char* kAllEvents[8];
static const char kKeyUnscannedReason[];
@@ -245,80 +231,9 @@ class SafeBrowsingPrivateEventRouter
const std::string& trigger,
const std::vector<std::pair<GURL, std::u16string>>& identities);
- // Returns true if enterprise real-time reporting should be initialized,
- // checking both the feature flag. This function is public so that it can
- // called in tests.
- static bool ShouldInitRealtimeReportingClient();
-
- void SetBrowserCloudPolicyClientForTesting(policy::CloudPolicyClient* client);
- void SetProfileCloudPolicyClientForTesting(policy::CloudPolicyClient* client);
-
void SetIdentityManagerForTesting(signin::IdentityManager* identity_manager);
- // policy::CloudPolicyClient::Observer:
- void OnClientError(policy::CloudPolicyClient* client) override;
- void OnPolicyFetched(policy::CloudPolicyClient* client) override {}
- void OnRegistrationStateChanged(policy::CloudPolicyClient* client) override {}
-
- protected:
- // Report safe browsing event through real-time reporting channel, if enabled.
- // Declared as virtual for tests. Declared as protected to be called directly
- // by tests.
- virtual void ReportRealtimeEvent(
- const std::string&,
- const enterprise_connectors::ReportingSettings& settings,
- base::Value::Dict event);
-
private:
- // Initialize a real-time report client if needed. This client is used only
- // if real-time reporting is enabled, the machine is properly reigistered
- // with CBCM and the appropriate policies are enabled.
- void InitRealtimeReportingClient(
- const enterprise_connectors::ReportingSettings& settings);
-
- // Sub-methods called by InitRealtimeReportingClient to make appropriate
- // verifications and initialize the corresponding client. Returns a policy
- // client description and a client, which can be nullptr if it can't be
- // initialized.
- std::pair<std::string, policy::CloudPolicyClient*> InitBrowserReportingClient(
- const std::string& dm_token);
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
- std::pair<std::string, policy::CloudPolicyClient*> InitProfileReportingClient(
- const std::string& dm_token);
-#endif
-
- // Determines if the real-time reporting feature is enabled.
- // Obtain settings to apply to a reporting event from ConnectorsService.
- // absl::nullopt represents that reporting should not be done.
- absl::optional<enterprise_connectors::ReportingSettings>
- GetReportingSettings();
-
- // Called whenever the real-time reporting policy changes.
- void RealtimeReportingPrefChanged(const std::string& pref);
-
- // Create a privately owned cloud policy client for events routing.
- void CreatePrivateCloudPolicyClient(
- const std::string& policy_client_desc,
- policy::DeviceManagementService* device_management_service,
- const std::string& client_id,
- const std::string& dm_token);
-
- // Handle the availability of a cloud policy client.
- void OnCloudPolicyClientAvailable(const std::string& policy_client_desc,
- policy::CloudPolicyClient* client);
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-
- // Return the Chrome OS user who is subject to reporting, or nullptr if
- // the user cannot be deterined.
- static const user_manager::User* GetChromeOSUser();
-
-#endif
-
- // Determines if real-time reporting is available based on platform and user.
- static bool IsRealtimeReportingAvailable();
-
// Removes any path information and returns just the basename.
static std::string GetBaseName(const std::string& filename);
@@ -353,17 +268,11 @@ class SafeBrowsingPrivateEventRouter
const int64_t content_size,
safe_browsing::EventResult event_result);
- void RemoveDmTokenFromRejectedSet(const std::string& dm_token);
-
raw_ptr<content::BrowserContext> context_;
raw_ptr<signin::IdentityManager> identity_manager_ = nullptr;
raw_ptr<EventRouter> event_router_ = nullptr;
-
- // The cloud policy clients used to upload browser events and profile events
- // to the cloud. These clients are never used to fetch policies. These
- // pointers are not owned by the class.
- raw_ptr<policy::CloudPolicyClient> browser_client_ = nullptr;
- raw_ptr<policy::CloudPolicyClient> profile_client_ = nullptr;
+ raw_ptr<enterprise_connectors::RealtimeReportingClient> reporting_client_ =
+ nullptr;
// The private clients are used on platforms where we cannot just get a
// client and we create our own (used through the above client pointers).
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 50b4be9464f..17f527b585c 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
@@ -5,7 +5,9 @@
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
#include "chrome/browser/enterprise/connectors/connectors_service.h"
+#include "chrome/browser/enterprise/connectors/reporting/realtime_reporting_client_factory.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_context.h"
@@ -35,6 +37,8 @@ SafeBrowsingPrivateEventRouterFactory::SafeBrowsingPrivateEventRouterFactory()
DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
DependsOn(IdentityManagerFactory::GetInstance());
DependsOn(enterprise_connectors::ConnectorsServiceFactory::GetInstance());
+ DependsOn(
+ enterprise_connectors::RealtimeReportingClientFactory::GetInstance());
}
SafeBrowsingPrivateEventRouterFactory::
@@ -48,7 +52,11 @@ KeyedService* SafeBrowsingPrivateEventRouterFactory::BuildServiceInstanceFor(
content::BrowserContext*
SafeBrowsingPrivateEventRouterFactory::GetBrowserContextToUse(
content::BrowserContext* context) const {
- return ExtensionsBrowserClient::Get()->GetOriginalContext(context);
+ Profile* profile = Profile::FromBrowserContext(context);
+ if (!profile || profile->IsSystemProfile()) {
+ return nullptr;
+ }
+ return chrome::GetBrowserContextOwnInstanceInIncognito(context);
}
bool SafeBrowsingPrivateEventRouterFactory::ServiceIsCreatedWithBrowserContext()
diff --git a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc
index 4e78881b143..58992a4b6db 100644
--- a/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_unittest.cc
@@ -22,10 +22,13 @@
#include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/enterprise/connectors/connectors_prefs.h"
#include "chrome/browser/enterprise/connectors/connectors_service.h"
+#include "chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.h"
+#include "chrome/browser/enterprise/connectors/reporting/realtime_reporting_client_factory.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
#include "chrome/browser/policy/dm_token_utils.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_test_utils.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
+#include "chrome/browser/safe_browsing/test_extension_event_observer.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/api/safe_browsing_private.h"
#include "chrome/test/base/testing_browser_process.h"
@@ -45,11 +48,11 @@
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "ash/components/tpm/stub_install_attributes.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/ash/login/users/scoped_test_user_manager.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
+#include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
#include "components/account_id/account_id.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user.h"
@@ -96,7 +99,7 @@ class SafeBrowsingEventObserver : public TestEventRouter::EventObserver {
// extensions::TestEventRouter::EventObserver:
void OnBroadcastEvent(const extensions::Event& event) override {
if (event.event_name == event_name_) {
- event_args_ = event.event_args->Clone();
+ event_args_ = base::Value(event.event_args.Clone());
}
}
@@ -108,12 +111,6 @@ class SafeBrowsingEventObserver : public TestEventRouter::EventObserver {
base::Value event_args_;
};
-std::unique_ptr<KeyedService> BuildSafeBrowsingPrivateEventRouter(
- content::BrowserContext* context) {
- return std::unique_ptr<KeyedService>(
- new SafeBrowsingPrivateEventRouter(context));
-}
-
class SafeBrowsingPrivateEventRouterTestBase : public testing::Test {
public:
SafeBrowsingPrivateEventRouterTestBase()
@@ -250,7 +247,8 @@ class SafeBrowsingPrivateEventRouterTestBase : public testing::Test {
// Set a mock cloud policy client in the router.
client_ = std::make_unique<policy::MockCloudPolicyClient>();
client_->SetDMToken("fake-token");
- SafeBrowsingPrivateEventRouterFactory::GetForProfile(profile_)
+ enterprise_connectors::RealtimeReportingClientFactory::GetForProfile(
+ profile_)
->SetBrowserCloudPolicyClientForTesting(client_.get());
}
@@ -270,7 +268,13 @@ class SafeBrowsingPrivateEventRouterTestBase : public testing::Test {
std::map<std::string, std::vector<std::string>>()) {
event_router_ = extensions::CreateAndUseTestEventRouter(profile_);
SafeBrowsingPrivateEventRouterFactory::GetInstance()->SetTestingFactory(
- profile_, base::BindRepeating(&BuildSafeBrowsingPrivateEventRouter));
+ profile_, base::BindRepeating(
+ &safe_browsing::BuildSafeBrowsingPrivateEventRouter));
+
+ enterprise_connectors::RealtimeReportingClientFactory::GetInstance()
+ ->SetTestingFactory(
+ profile_,
+ base::BindRepeating(&safe_browsing::BuildRealtimeReportingClient));
SetReportingPolicy(realtime_reporting_enable, authorized,
enabled_event_names, enabled_opt_in_events);
@@ -869,8 +873,8 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnPasswordBreach) {
validator.ExpectPasswordBreachEvent(
"SAFETY_CHECK",
{
- {"https://first.example.com/", u"first_user_name"},
- {"https://second.example.com/", u"second_user_name"},
+ {"https://first.example.com/", u"*****"},
+ {"https://second.example.com/", u"*****@gmail.com"},
},
profile_->GetProfileUserName());
@@ -878,7 +882,7 @@ TEST_F(SafeBrowsingPrivateEventRouterTest, TestOnPasswordBreach) {
"SAFETY_CHECK",
{
{GURL("https://first.example.com"), u"first_user_name"},
- {GURL("https://second.example.com"), u"second_user_name"},
+ {GURL("https://second.example.com"), u"second_user_name@gmail.com"},
});
}
@@ -930,7 +934,7 @@ TEST_F(SafeBrowsingPrivateEventRouterTest,
validator.ExpectPasswordBreachEvent(
"SAFETY_CHECK",
{
- {"https://secondexample.com/", u"second_user_name"},
+ {"https://secondexample.com/", u"*****"},
},
profile_->GetProfileUserName());
@@ -1371,13 +1375,6 @@ class SafeBrowsingIsRealtimeReportingEnabledTest
#endif
};
-TEST_P(SafeBrowsingIsRealtimeReportingEnabledTest,
- ShouldInitRealtimeReportingClient) {
- EXPECT_EQ(
- should_init(),
- SafeBrowsingPrivateEventRouter::ShouldInitRealtimeReportingClient());
-}
-
TEST_P(SafeBrowsingIsRealtimeReportingEnabledTest, CheckRealtimeReport) {
// In production, the router won't actually be authorized unless it was
// initialized. The second argument to SetUpRouters() takes this into
diff --git a/chromium/chrome/browser/extensions/api/scripting/scripting_api.cc b/chromium/chrome/browser/extensions/api/scripting/scripting_api.cc
index 08ba9873de3..23d0a104053 100644
--- a/chromium/chrome/browser/extensions/api/scripting/scripting_api.cc
+++ b/chromium/chrome/browser/extensions/api/scripting/scripting_api.cc
@@ -682,10 +682,12 @@ bool ScriptingExecuteScriptFunction::Execute(
: mojom::RunLocation::kDocumentIdle;
script_executor->ExecuteScript(
mojom::HostID(mojom::HostID::HostType::kExtensions, extension()->id()),
- mojom::CodeInjection::NewJs(
- mojom::JSInjection::New(std::move(sources), execution_world,
- /*wants_result=*/true, user_gesture(),
- /*wait_for_promise=*/true)),
+ mojom::CodeInjection::NewJs(mojom::JSInjection::New(
+ std::move(sources), execution_world,
+ blink::mojom::WantResultOption::kWantResult,
+ user_gesture() ? blink::mojom::UserActivationOption::kActivate
+ : blink::mojom::UserActivationOption::kDoNotActivate,
+ blink::mojom::PromiseResultOption::kAwait)),
frame_scope, frame_ids, ScriptExecutor::MATCH_ABOUT_BLANK, run_location,
ScriptExecutor::DEFAULT_PROCESS,
/* webview_src */ GURL(),
diff --git a/chromium/chrome/browser/extensions/api/scripting/scripting_apitest.cc b/chromium/chrome/browser/extensions/api/scripting/scripting_apitest.cc
index de64164f94f..3fb3235f3f8 100644
--- a/chromium/chrome/browser/extensions/api/scripting/scripting_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/scripting/scripting_apitest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "build/build_config.h"
#include "chrome/browser/extensions/api/scripting/scripting_api.h"
#include "base/test/bind.h"
@@ -16,6 +17,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/prerender_test_util.h"
#include "content/public/test/test_navigation_observer.h"
#include "extensions/browser/background_script_executor.h"
#include "extensions/browser/disable_reason.h"
@@ -508,4 +510,23 @@ IN_PROC_BROWSER_TEST_F(PersistentScriptingAPITest,
EXPECT_TRUE(result_catcher_.GetNextResult()) << result_catcher_.message();
}
+class ScriptingAPIPrerenderingTest : public ScriptingAPITest {
+ protected:
+ ScriptingAPIPrerenderingTest() = default;
+ ~ScriptingAPIPrerenderingTest() override = default;
+
+ private:
+ content::test::ScopedPrerenderFeatureList scoped_feature_list_;
+};
+
+// TODO(crbug.com/1351648): disabled on Mac due to flakiness.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_Basic DISABLED_Basic
+#else // BUILDFLAG(IS_MAC)
+#define MAYBE_Basic Basic
+#endif // BUILDFLAG(IS_MAC)
+IN_PROC_BROWSER_TEST_F(ScriptingAPIPrerenderingTest, MAYBE_Basic) {
+ ASSERT_TRUE(RunExtensionTest("scripting/prerendering")) << message_;
+}
+
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/sessions/sessions_api.cc b/chromium/chrome/browser/extensions/api/sessions/sessions_api.cc
index 2279fd5040d..cbf6bc88458 100644
--- a/chromium/chrome/browser/extensions/api/sessions/sessions_api.cc
+++ b/chromium/chrome/browser/extensions/api/sessions/sessions_api.cc
@@ -641,7 +641,7 @@ void SessionsEventRouter::TabRestoreServiceChanged(
sessions::TabRestoreService* service) {
EventRouter::Get(profile_)->BroadcastEvent(std::make_unique<Event>(
events::SESSIONS_ON_CHANGED, api::sessions::OnChanged::kEventName,
- std::vector<base::Value>()));
+ base::Value::List()));
}
void SessionsEventRouter::TabRestoreServiceDestroyed(
diff --git a/chromium/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chromium/chrome/browser/extensions/api/sessions/sessions_apitest.cc
index c2ee2f9b252..1b210e522b9 100644
--- a/chromium/chrome/browser/extensions/api/sessions/sessions_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/sessions/sessions_apitest.cc
@@ -24,6 +24,7 @@
#include "chrome/browser/extensions/extension_function_test_utils.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/session_sync_service_factory.h"
+#include "chrome/browser/ui/tabs/tab_enums.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
@@ -39,7 +40,7 @@
#include "components/sync/protocol/model_type_state.pb.h"
#include "components/sync/protocol/session_specifics.pb.h"
#include "components/sync/protocol/sync_enums.pb.h"
-#include "components/sync/test/engine/mock_model_type_worker.h"
+#include "components/sync/test/mock_model_type_worker.h"
#include "components/sync_sessions/session_store.h"
#include "components/sync_sessions/session_sync_service.h"
#include "content/public/test/browser_test.h"
@@ -77,7 +78,7 @@ void BuildWindowSpecifics(int window_id,
sync_pb::SessionWindow* window = header->add_window();
window->set_window_id(window_id);
window->set_selected_tab_index(0);
- window->set_browser_type(sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
+ window->set_browser_type(sync_pb::SyncEnums_BrowserType_TYPE_TABBED);
for (auto iter = tab_list.cbegin(); iter != tab_list.cend(); ++iter) {
window->add_tab(*iter);
}
@@ -103,36 +104,29 @@ void BuildTabSpecifics(const std::string& tag,
navigation->set_page_transition(sync_pb::SyncEnums_PageTransition_TYPED);
}
-testing::AssertionResult CheckSessionModels(const base::ListValue& devices,
+testing::AssertionResult CheckSessionModels(const base::Value::List& devices,
size_t num_sessions) {
- EXPECT_EQ(5u, devices.GetListDeprecated().size());
- for (size_t i = 0; i < devices.GetListDeprecated().size(); ++i) {
- const base::Value& device_value = devices.GetListDeprecated()[i];
+ EXPECT_EQ(5u, devices.size());
+ for (size_t i = 0; i < devices.size(); ++i) {
+ const base::Value& device_value = devices[i];
EXPECT_TRUE(device_value.is_dict());
const base::Value::Dict device = utils::ToDictionary(device_value);
EXPECT_EQ(kSessionTags[i], api_test_utils::GetString(device, "info"));
EXPECT_EQ(kSessionTags[i], api_test_utils::GetString(device, "deviceName"));
- const std::unique_ptr<base::ListValue> sessions =
+ const base::Value::List sessions =
api_test_utils::GetList(device, "sessions");
- EXPECT_EQ(num_sessions, sessions->GetListDeprecated().size());
+ EXPECT_EQ(num_sessions, sessions.size());
// Because this test is hurried, really there are only ever 0 or 1
// sessions, and if 1, that will be a Window. Grab it.
if (num_sessions == 0)
continue;
- const base::Value::Dict session =
- utils::ToDictionary(sessions->GetListDeprecated()[0]);
+ const base::Value::Dict session = utils::ToDictionary(sessions[0]);
const base::Value::Dict window = api_test_utils::GetDict(session, "window");
// Only the tabs are interesting.
- const std::unique_ptr<base::ListValue> tabs =
- api_test_utils::GetList(window, "tabs");
- if (!tabs) {
- return testing::AssertionFailure()
- << "window dictionary does not contain a tabs list entry";
- }
- EXPECT_EQ(std::size(kTabIDs), tabs->GetListDeprecated().size());
- for (size_t j = 0; j < tabs->GetListDeprecated().size(); ++j) {
- const base::Value::Dict tab =
- utils::ToDictionary(tabs->GetListDeprecated()[j]);
+ const base::Value::List tabs = api_test_utils::GetList(window, "tabs");
+ EXPECT_EQ(std::size(kTabIDs), tabs.size());
+ for (size_t j = 0; j < tabs.size(); ++j) {
+ const base::Value::Dict tab = utils::ToDictionary(tabs[j]);
EXPECT_FALSE(tab.contains("id")); // sessions API does not give tab IDs
EXPECT_EQ(static_cast<int>(j), api_test_utils::GetInteger(tab, "index"));
EXPECT_EQ(0, api_test_utils::GetInteger(tab, "windowId"));
@@ -277,33 +271,29 @@ void ExtensionSessionsTest::CreateSessionModels() {
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetDevices) {
CreateSessionModels();
- std::unique_ptr<base::ListValue> result(
+ base::Value::List result(
utils::ToList(utils::RunFunctionAndReturnSingleResult(
CreateFunction<SessionsGetDevicesFunction>(true).get(),
"[{\"maxResults\": 0}]", browser())));
- ASSERT_TRUE(result);
- EXPECT_TRUE(CheckSessionModels(*result, 0u));
+ EXPECT_TRUE(CheckSessionModels(result, 0u));
}
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetDevicesMaxResults) {
CreateSessionModels();
- std::unique_ptr<base::ListValue> result(
+ base::Value::List result(
utils::ToList(utils::RunFunctionAndReturnSingleResult(
CreateFunction<SessionsGetDevicesFunction>(true).get(), "[]",
browser())));
- ASSERT_TRUE(result);
- EXPECT_TRUE(CheckSessionModels(*result, 1u));
+ EXPECT_TRUE(CheckSessionModels(result, 1u));
}
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetDevicesListEmpty) {
- std::unique_ptr<base::ListValue> result(
+ base::Value::List devices(
utils::ToList(utils::RunFunctionAndReturnSingleResult(
CreateFunction<SessionsGetDevicesFunction>(true).get(), "[]",
browser())));
- ASSERT_TRUE(result);
- base::ListValue* devices = result.get();
- EXPECT_EQ(0u, devices->GetListDeprecated().size());
+ EXPECT_TRUE(devices.empty());
}
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, RestoreForeignSessionWindow) {
@@ -314,18 +304,16 @@ IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, RestoreForeignSessionWindow) {
CreateFunction<SessionsRestoreFunction>(true).get(), "[\"tag3.3\"]",
browser(), api_test_utils::INCLUDE_INCOGNITO));
- std::unique_ptr<base::ListValue> result(
+ base::Value::List windows(
utils::ToList(utils::RunFunctionAndReturnSingleResult(
CreateFunction<WindowsGetAllFunction>(true).get(), "[]", browser())));
- ASSERT_TRUE(result);
- base::ListValue* windows = result.get();
- EXPECT_EQ(2u, windows->GetListDeprecated().size());
+ EXPECT_EQ(2u, windows.size());
const base::Value::Dict restored_window =
api_test_utils::GetDict(restored_window_session, "window");
base::Value::Dict window;
int restored_id = api_test_utils::GetInteger(restored_window, "id");
- for (base::Value& window_value : windows->GetListDeprecated()) {
+ for (base::Value& window_value : windows) {
window = utils::ToDictionary(std::move(window_value));
if (api_test_utils::GetInteger(window, "id") == restored_id)
break;
@@ -375,13 +363,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, RestoreNonEditableTabstrip) {
}
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetRecentlyClosedIncognito) {
- std::unique_ptr<base::ListValue> result(
+ base::Value::List sessions(
utils::ToList(utils::RunFunctionAndReturnSingleResult(
CreateFunction<SessionsGetRecentlyClosedFunction>(true).get(), "[]",
CreateIncognitoBrowser())));
- ASSERT_TRUE(result);
- base::ListValue* sessions = result.get();
- EXPECT_EQ(0u, sessions->GetListDeprecated().size());
+ EXPECT_TRUE(sessions.empty());
}
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetRecentlyClosedMaxResults) {
@@ -396,7 +382,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetRecentlyClosedMaxResults) {
content::WebContentsDestroyedWatcher destroyed_watcher(
browser()->tab_strip_model()->GetWebContentsAt(tab_index));
browser()->tab_strip_model()->CloseWebContentsAt(
- tab_index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
+ tab_index, TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB);
destroyed_watcher.Wait();
}
diff --git a/chromium/chrome/browser/extensions/api/settings_private/OWNERS b/chromium/chrome/browser/extensions/api/settings_private/OWNERS
index 2dbba8f0aab..443a569fed9 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/OWNERS
+++ b/chromium/chrome/browser/extensions/api/settings_private/OWNERS
@@ -1,3 +1 @@
-michaelpg@chromium.org
-
file://chrome/browser/resources/settings/OWNERS
diff --git a/chromium/chrome/browser/extensions/api/settings_private/generated_prefs.cc b/chromium/chrome/browser/extensions/api/settings_private/generated_prefs.cc
index ba6944df9ab..f9704d6f06b 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/generated_prefs.cc
+++ b/chromium/chrome/browser/extensions/api/settings_private/generated_prefs.cc
@@ -12,7 +12,6 @@
#include "chrome/browser/extensions/api/settings_private/generated_pref.h"
#include "chrome/browser/extensions/api/settings_private/prefs_util_enums.h"
#include "chrome/browser/password_manager/generated_password_leak_detection_pref.h"
-#include "chrome/browser/privacy_sandbox/generated_floc_pref.h"
#include "chrome/browser/safe_browsing/generated_safe_browsing_pref.h"
#include "chrome/common/extensions/api/settings_private.h"
#include "components/content_settings/core/common/pref_names.h"
@@ -104,7 +103,6 @@ void GeneratedPrefs::CreatePrefs() {
std::make_unique<safe_browsing::GeneratedSafeBrowsingPref>(profile_);
prefs_[content_settings::kGeneratedNotificationPref] =
std::make_unique<content_settings::GeneratedNotificationPref>(profile_);
- prefs_[kGeneratedFlocPref] = std::make_unique<GeneratedFlocPref>(profile_);
}
} // namespace settings_private
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 9d578203162..4e2acc72898 100644
--- a/chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -21,7 +21,6 @@
#include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
#include "chrome/browser/password_manager/generated_password_leak_detection_pref.h"
#include "chrome/browser/prefs/session_startup_pref.h"
-#include "chrome/browser/privacy_sandbox/generated_floc_pref.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/safe_browsing/generated_safe_browsing_pref.h"
#include "chrome/common/chrome_features.h"
@@ -76,8 +75,8 @@
#include "chrome/browser/ash/system/timezone_util.h"
#include "chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_method_short.h"
#include "chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.h"
+#include "chromeos/ash/services/assistant/public/cpp/assistant_prefs.h"
#include "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h"
-#include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
#include "components/account_manager_core/pref_names.h"
#include "ui/chromeos/events/pref_names.h"
#endif
@@ -183,6 +182,8 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[bookmarks::prefs::kShowBookmarkBar] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
+ (*s_allowlist)[::prefs::kSidePanelHorizontalAlignment] =
+ settings_api::PrefType::PREF_TYPE_BOOLEAN;
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
@@ -296,8 +297,6 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[::prefs::kPrivacySandboxPageViewed] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
- (*s_allowlist)[::kGeneratedFlocPref] =
- settings_api::PrefType::PREF_TYPE_BOOLEAN;
// Security page
(*s_allowlist)[::kGeneratedPasswordLeakDetectionPref] =
@@ -554,7 +553,7 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[crostini::prefs::kCrostiniSharedUsbDevices] =
settings_api::PrefType::PREF_TYPE_LIST;
- (*s_allowlist)[crostini::prefs::kCrostiniContainers] =
+ (*s_allowlist)[guest_os::prefs::kGuestOsContainers] =
settings_api::PrefType::PREF_TYPE_LIST;
(*s_allowlist)[crostini::prefs::kCrostiniPortForwarding] =
settings_api::PrefType::PREF_TYPE_LIST;
@@ -588,24 +587,23 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::PREF_TYPE_NUMBER;
// Google Assistant.
- (*s_allowlist)[chromeos::assistant::prefs::kAssistantConsentStatus] =
+ (*s_allowlist)[ash::assistant::prefs::kAssistantConsentStatus] =
settings_api::PrefType::PREF_TYPE_NUMBER;
- (*s_allowlist)[chromeos::assistant::prefs::kAssistantDisabledByPolicy] =
+ (*s_allowlist)[ash::assistant::prefs::kAssistantDisabledByPolicy] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
- (*s_allowlist)[chromeos::assistant::prefs::kAssistantEnabled] =
+ (*s_allowlist)[ash::assistant::prefs::kAssistantEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
- (*s_allowlist)[chromeos::assistant::prefs::kAssistantContextEnabled] =
+ (*s_allowlist)[ash::assistant::prefs::kAssistantContextEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
- (*s_allowlist)[chromeos::assistant::prefs::kAssistantHotwordAlwaysOn] =
+ (*s_allowlist)[ash::assistant::prefs::kAssistantHotwordAlwaysOn] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
- (*s_allowlist)[chromeos::assistant::prefs::kAssistantHotwordEnabled] =
+ (*s_allowlist)[ash::assistant::prefs::kAssistantHotwordEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
- (*s_allowlist)
- [chromeos::assistant::prefs::kAssistantVoiceMatchEnabledDuringOobe] =
- settings_api::PrefType::PREF_TYPE_BOOLEAN;
- (*s_allowlist)[chromeos::assistant::prefs::kAssistantLaunchWithMicOpen] =
+ (*s_allowlist)[ash::assistant::prefs::kAssistantVoiceMatchEnabledDuringOobe] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
- (*s_allowlist)[chromeos::assistant::prefs::kAssistantNotificationEnabled] =
+ (*s_allowlist)[ash::assistant::prefs::kAssistantLaunchWithMicOpen] =
+ settings_api::PrefType::PREF_TYPE_BOOLEAN;
+ (*s_allowlist)[ash::assistant::prefs::kAssistantNotificationEnabled] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
// Quick Answers.
@@ -798,7 +796,8 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[ash::prefs::kUserCameraAllowed] =
settings_api::PrefType::PREF_TYPE_BOOLEAN;
-
+ (*s_allowlist)[ash::prefs::kUserMicrophoneAllowed] =
+ settings_api::PrefType::PREF_TYPE_BOOLEAN;
#else
// System settings.
(*s_allowlist)[::prefs::kBackgroundModeEnabled] =
@@ -826,8 +825,6 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetAllowlistedKeys() {
#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
- (*s_allowlist)[::prefs::kSettingsShowOSBanner] =
- settings_api::PrefType::PREF_TYPE_BOOLEAN;
(*s_allowlist)[::prefs::kPrintingAPIExtensionsAllowlist] =
settings_api::PrefType::PREF_TYPE_LIST;
#endif
@@ -1258,7 +1255,7 @@ bool PrefsUtil::IsPrefPrimaryUserControlled(const std::string& pref_name) {
bool PrefsUtil::IsHotwordDisabledForChildUser(const std::string& pref_name) {
const std::string& hotwordEnabledPref =
- chromeos::assistant::prefs::kAssistantHotwordEnabled;
+ ash::assistant::prefs::kAssistantHotwordEnabled;
if (!profile_->IsChild() || pref_name != hotwordEnabledPref)
return false;
diff --git a/chromium/chrome/browser/extensions/api/shared_storage/shared_storage_private_api_ash.cc b/chromium/chrome/browser/extensions/api/shared_storage/shared_storage_private_api_ash.cc
index 7db25c1220d..e5c52402a0f 100644
--- a/chromium/chrome/browser/extensions/api/shared_storage/shared_storage_private_api_ash.cc
+++ b/chromium/chrome/browser/extensions/api/shared_storage/shared_storage_private_api_ash.cc
@@ -31,7 +31,8 @@ SharedStoragePrivateGetFunction::~SharedStoragePrivateGetFunction() = default;
ExtensionFunction::ResponseAction SharedStoragePrivateGetFunction::Run() {
PrefService* prefs =
Profile::FromBrowserContext(browser_context())->GetPrefs();
- return RespondNow(OneArgument(prefs->Get(prefs::kSharedStorage)->Clone()));
+ return RespondNow(
+ OneArgument(prefs->GetValue(prefs::kSharedStorage).Clone()));
}
SharedStoragePrivateSetFunction::SharedStoragePrivateSetFunction() = default;
diff --git a/chromium/chrome/browser/extensions/api/shared_storage/shared_storage_private_apitest.cc b/chromium/chrome/browser/extensions/api/shared_storage/shared_storage_private_apitest.cc
index b92e8cee82e..4a3ea98a08e 100644
--- a/chromium/chrome/browser/extensions/api/shared_storage/shared_storage_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/shared_storage/shared_storage_private_apitest.cc
@@ -9,7 +9,7 @@
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "base/containers/contains.h"
-#include "chromeos/startup/browser_init_params.h"
+#include "chromeos/startup/browser_params_proxy.h"
#endif // BUILDFLAG(IS_CHROMEOS_LACROS)
namespace extensions {
@@ -18,7 +18,7 @@ using SharedStoragePrivateApiTest = ExtensionApiTest;
IN_PROC_BROWSER_TEST_F(SharedStoragePrivateApiTest, Test) {
#if BUILDFLAG(IS_CHROMEOS_LACROS)
- auto capabilities = chromeos::BrowserInitParams::Get()->ash_capabilities;
+ auto capabilities = chromeos::BrowserParamsProxy::Get()->AshCapabilities();
if (!capabilities || !base::Contains(*capabilities, "b/231890240")) {
LOG(WARNING) << "Unsupported ash version for shared storage.";
return;
diff --git a/chromium/chrome/browser/extensions/api/side_panel/side_panel_api.cc b/chromium/chrome/browser/extensions/api/side_panel/side_panel_api.cc
new file mode 100644
index 00000000000..055f84c15f0
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/side_panel/side_panel_api.cc
@@ -0,0 +1,59 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/side_panel/side_panel_api.h"
+
+#include <memory>
+
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/api/side_panel/side_panel_service.h"
+#include "chrome/common/extensions/api/side_panel.h"
+#include "extensions/common/extension_features.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace extensions {
+namespace {
+
+bool IsSidePanelApiAvailable() {
+ return base::FeatureList::IsEnabled(
+ extensions_features::kExtensionSidePanelIntegration);
+}
+
+} // namespace
+
+SidePanelApiFunction::SidePanelApiFunction() = default;
+SidePanelApiFunction::~SidePanelApiFunction() = default;
+SidePanelService* SidePanelApiFunction::GetService() {
+ return extensions::SidePanelService::Get(browser_context());
+}
+
+ExtensionFunction::ResponseAction SidePanelApiFunction::Run() {
+ if (!IsSidePanelApiAvailable())
+ return RespondNow(Error("API Unavailable"));
+ return RunFunction();
+}
+
+ExtensionFunction::ResponseAction SidePanelGetOptionsFunction::RunFunction() {
+ std::unique_ptr<api::side_panel::GetOptions::Params> params(
+ api::side_panel::GetOptions::Params::Create(args()));
+ EXTENSION_FUNCTION_VALIDATE(params);
+ auto tab_id = params->options.tab_id
+ ? absl::optional<int>(*(params->options.tab_id))
+ : absl::nullopt;
+ const api::side_panel::PanelOptions& options =
+ GetService()->GetOptions(*extension(), tab_id);
+ return RespondNow(OneArgument(std::move(*options.ToValue())));
+}
+
+ExtensionFunction::ResponseAction SidePanelSetOptionsFunction::RunFunction() {
+ std::unique_ptr<api::side_panel::SetOptions::Params> params(
+ api::side_panel::SetOptions::Params::Create(args()));
+ EXTENSION_FUNCTION_VALIDATE(params);
+ // TODO(crbug.com/1328645): Validate the relative extension path exists.
+ GetService()->SetOptions(*extension(), std::move(params->options));
+ return RespondNow(NoArguments());
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/side_panel/side_panel_api.h b/chromium/chrome/browser/extensions/api/side_panel/side_panel_api.h
new file mode 100644
index 00000000000..604ac1520ac
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/side_panel/side_panel_api.h
@@ -0,0 +1,53 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_SIDE_PANEL_SIDE_PANEL_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_SIDE_PANEL_SIDE_PANEL_API_H_
+
+#include "extensions/browser/extension_function.h"
+#include "extensions/browser/extension_function_histogram_value.h"
+
+namespace extensions {
+
+class SidePanelService;
+
+class SidePanelApiFunction : public ExtensionFunction {
+ protected:
+ SidePanelApiFunction();
+ ~SidePanelApiFunction() override;
+ ResponseAction Run() override;
+
+ virtual ResponseAction RunFunction() = 0;
+ SidePanelService* GetService();
+};
+
+class SidePanelGetOptionsFunction : public SidePanelApiFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("sidePanel.getOptions", SIDEPANEL_GETOPTIONS)
+ SidePanelGetOptionsFunction() = default;
+ SidePanelGetOptionsFunction(const SidePanelGetOptionsFunction&) = delete;
+ SidePanelGetOptionsFunction& operator=(const SidePanelGetOptionsFunction&) =
+ delete;
+
+ private:
+ ~SidePanelGetOptionsFunction() override = default;
+ ResponseAction RunFunction() override;
+};
+
+class SidePanelSetOptionsFunction : public SidePanelApiFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("sidePanel.setOptions", SIDEPANEL_SETOPTIONS)
+ SidePanelSetOptionsFunction() = default;
+ SidePanelSetOptionsFunction(const SidePanelSetOptionsFunction&) = delete;
+ SidePanelSetOptionsFunction& operator=(const SidePanelSetOptionsFunction&) =
+ delete;
+
+ private:
+ ~SidePanelSetOptionsFunction() override = default;
+ ResponseAction RunFunction() override;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_SIDE_PANEL_SIDE_PANEL_API_H_
diff --git a/chromium/chrome/browser/extensions/api/side_panel/side_panel_apitest.cc b/chromium/chrome/browser/extensions/api/side_panel/side_panel_apitest.cc
new file mode 100644
index 00000000000..8331fbc5545
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/side_panel/side_panel_apitest.cc
@@ -0,0 +1,41 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/scoped_feature_list.h"
+#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"
+
+namespace extensions {
+
+class SidePanelApiTest : public ExtensionApiTest {
+ public:
+ SidePanelApiTest() {
+ feature_list_.InitAndEnableFeature(
+ extensions_features::kExtensionSidePanelIntegration);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+ ScopedCurrentChannel current_channel_{version_info::Channel::CANARY};
+};
+
+// Verify normal chrome.sidePanel functionality.
+IN_PROC_BROWSER_TEST_F(SidePanelApiTest, Extension) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ ASSERT_TRUE(RunExtensionTest("side_panel/extension")) << message_;
+}
+
+// Verify chrome.sidePanel behavior without permissions.
+IN_PROC_BROWSER_TEST_F(SidePanelApiTest, PermissionMissing) {
+ ASSERT_TRUE(RunExtensionTest("side_panel/permission_missing")) << message_;
+}
+
+// Verify chrome.sidePanel.get behavior without side_panel manifest key.
+IN_PROC_BROWSER_TEST_F(SidePanelApiTest, MissingManifestKey) {
+ ASSERT_TRUE(RunExtensionTest("side_panel/missing_manifest_key")) << message_;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/side_panel/side_panel_service.cc b/chromium/chrome/browser/extensions/api/side_panel/side_panel_service.cc
new file mode 100644
index 00000000000..d97c121a736
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/side_panel/side_panel_service.cc
@@ -0,0 +1,112 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/side_panel/side_panel_service.h"
+
+#include <cstddef>
+#include <memory>
+
+#include "base/no_destructor.h"
+#include "chrome/common/extensions/api/side_panel.h"
+#include "chrome/common/extensions/api/side_panel/side_panel_info.h"
+#include "components/sessions/core/session_id.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace extensions {
+
+namespace {
+
+api::side_panel::PanelOptions GetPanelOptionsFromManifest(
+ const Extension& extension) {
+ auto path = SidePanelInfo::GetDefaultPath(&extension);
+ api::side_panel::PanelOptions options;
+ if (!path.empty()) {
+ options.path = std::make_unique<std::string>(std::string(path));
+ options.enabled = std::make_unique<bool>(true);
+ }
+ return options;
+}
+
+// TODO(crbug.com/1332599): Add a Clone() method for generated types.
+api::side_panel::PanelOptions CloneOptions(
+ const api::side_panel::PanelOptions& options) {
+ auto clone = api::side_panel::PanelOptions::FromValue(
+ base::Value(std::move(options.ToValue()->GetDict())));
+ return clone ? std::move(*clone) : api::side_panel::PanelOptions();
+}
+
+} // namespace
+
+SidePanelService::~SidePanelService() = default;
+
+SidePanelService::SidePanelService(content::BrowserContext* context)
+ : browser_context_(context) {}
+
+api::side_panel::PanelOptions SidePanelService::GetOptions(
+ const Extension& extension,
+ absl::optional<TabId> id) {
+ auto extension_panel_options = panels_.find(extension.id());
+
+ // Get default path from manifest if nothing was stored in this service for
+ // the calling extension.
+ if (extension_panel_options == panels_.end()) {
+ return GetPanelOptionsFromManifest(extension);
+ }
+
+ TabId default_tab_id = SessionID::InvalidValue().id();
+ TabId tab_id = id.has_value() ? id.value() : default_tab_id;
+ TabPanelOptions& tab_panel_options = extension_panel_options->second;
+
+ // The specific `tab_id` may have already been saved.
+ if (tab_id != default_tab_id) {
+ auto specific_tab_options = tab_panel_options.find(tab_id);
+ if (specific_tab_options != tab_panel_options.end())
+ return CloneOptions(specific_tab_options->second);
+ }
+
+ // Fall back to the default tab if no tab ID was specified or entries for the
+ // specific tab weren't found.
+ auto default_options = tab_panel_options.find(default_tab_id);
+ if (default_options != tab_panel_options.end()) {
+ auto options = CloneOptions(default_options->second);
+ return options;
+ }
+
+ // Fall back to the manifest-specified options as a last resort.
+ return GetPanelOptionsFromManifest(extension);
+}
+
+// Upsert to merge `panels_[extension_id][tab_id]` with `set_options`.
+void SidePanelService::SetOptions(const Extension& extension,
+ api::side_panel::PanelOptions options) {
+ TabId tab_id = SessionID::InvalidValue().id();
+ if (options.tab_id)
+ tab_id = *options.tab_id;
+ TabPanelOptions& extension_panel_options = panels_[extension.id()];
+ auto it = extension_panel_options.find(tab_id);
+ if (it == extension_panel_options.end()) {
+ extension_panel_options[tab_id] = std::move(options);
+ } else {
+ auto& existing_options = it->second;
+ if (options.path)
+ existing_options.path = std::move(options.path);
+ if (options.enabled)
+ existing_options.enabled = std::move(options.enabled);
+ }
+}
+
+// static
+BrowserContextKeyedAPIFactory<SidePanelService>*
+SidePanelService::GetFactoryInstance() {
+ static base::NoDestructor<BrowserContextKeyedAPIFactory<SidePanelService>>
+ instance;
+ return instance.get();
+}
+
+// static
+SidePanelService* SidePanelService::Get(content::BrowserContext* context) {
+ return BrowserContextKeyedAPIFactory<SidePanelService>::Get(context);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/side_panel/side_panel_service.h b/chromium/chrome/browser/extensions/api/side_panel/side_panel_service.h
new file mode 100644
index 00000000000..bb9175f805b
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/side_panel/side_panel_service.h
@@ -0,0 +1,63 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_SIDE_PANEL_SIDE_PANEL_SERVICE_H_
+#define CHROME_BROWSER_EXTENSIONS_API_SIDE_PANEL_SIDE_PANEL_SERVICE_H_
+
+#include "base/containers/flat_map.h"
+#include "chrome/common/extensions/api/side_panel.h"
+#include "extensions/browser/browser_context_keyed_api_factory.h"
+#include "extensions/common/extension_id.h"
+
+namespace extensions {
+
+// The single responsibility of this service is to be the source of truth for
+// side panel options. Extensions can interact with this service using the API
+// and side panel UI updates can rely on the response of GetOptions(tab_id).
+class SidePanelService : public BrowserContextKeyedAPI {
+ public:
+ explicit SidePanelService(content::BrowserContext* context);
+
+ SidePanelService(const SidePanelService&) = delete;
+ SidePanelService& operator=(const SidePanelService&) = delete;
+
+ ~SidePanelService() override;
+
+ // Convenience method to get the SidePanelService for a profile.
+ static SidePanelService* Get(content::BrowserContext* context);
+
+ // BrowserContextKeyedAPI implementation.
+ static BrowserContextKeyedAPIFactory<SidePanelService>* GetFactoryInstance();
+
+ // Get options for tab_id. Options are loaded in order first from service
+ // storage, manifest, or an empty object will be returned, if they're unset.
+ using TabId = int;
+ api::side_panel::PanelOptions GetOptions(const Extension& extension,
+ absl::optional<TabId> tab_id);
+
+ // Set options for tab_id if specified. Otherwise set default options.
+ void SetOptions(const Extension& extension,
+ api::side_panel::PanelOptions set_options);
+
+ private:
+ // TODO(crbug.com/1328645): Remove options for matching ExtensionId on
+ // uninstallation.
+ friend class BrowserContextKeyedAPIFactory<SidePanelService>;
+
+ content::BrowserContext* const browser_context_;
+
+ // BrowserContextKeyedAPI implementation.
+ static const char* service_name() { return "SidePanelService"; }
+ static const bool kServiceRedirectedInIncognito = true;
+ static const bool kServiceIsNULLWhileTesting = true;
+
+ using TabPanelOptions = base::flat_map<TabId, api::side_panel::PanelOptions>;
+ using ExtensionPanelOptions = base::flat_map<ExtensionId, TabPanelOptions>;
+
+ ExtensionPanelOptions panels_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_SIDE_PANEL_SIDE_PANEL_SERVICE_H_
diff --git a/chromium/chrome/browser/extensions/api/storage/policy_value_store.cc b/chromium/chrome/browser/extensions/api/storage/policy_value_store.cc
index 504f383a01f..8958996012d 100644
--- a/chromium/chrome/browser/extensions/api/storage/policy_value_store.cc
+++ b/chromium/chrome/browser/extensions/api/storage/policy_value_store.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/extensions/api/storage/policy_value_store.h"
+#include <algorithm>
#include <utility>
#include "base/logging.h"
@@ -41,10 +42,10 @@ void PolicyValueStore::SetCurrentPolicy(const policy::PolicyMap& policy) {
DCHECK(IsOnBackendSequence());
// Convert |policy| to a dictionary value. Only include mandatory policies
// for now.
- base::DictionaryValue current_policy;
+ base::Value::Dict current_policy;
for (const auto& it : policy) {
if (it.second.level == policy::POLICY_LEVEL_MANDATORY) {
- current_policy.SetKey(it.first, it.second.value_unsafe()->Clone());
+ current_policy.Set(it.first, it.second.value_unsafe()->Clone());
}
}
@@ -52,7 +53,7 @@ void PolicyValueStore::SetCurrentPolicy(const policy::PolicyMap& policy) {
// TODO(joaodasilva): it'd be better to have a less expensive way of
// determining which keys are currently stored, or of determining which keys
// must be removed.
- base::DictionaryValue previous_policy;
+ base::Value::Dict previous_policy;
ValueStore::ReadResult read_result = delegate_->Get();
if (!read_result.status().ok()) {
@@ -61,15 +62,15 @@ void PolicyValueStore::SetCurrentPolicy(const policy::PolicyMap& policy) {
// Leave |previous_policy| empty, so that events are generated for every
// policy in |current_policy|.
} else {
- read_result.settings().Swap(&previous_policy);
+ std::swap(read_result.settings(), previous_policy);
}
// Now get two lists of changes: changes after setting the current policies,
// and changes after removing old policies that aren't in |current_policy|
// anymore.
std::vector<std::string> removed_keys;
- for (auto kv : previous_policy.DictItems()) {
- if (!current_policy.FindKey(kv.first))
+ for (auto kv : previous_policy) {
+ if (!current_policy.Find(kv.first))
removed_keys.push_back(kv.first);
}
@@ -148,7 +149,7 @@ ValueStore::WriteResult PolicyValueStore::Set(WriteOptions options,
ValueStore::WriteResult PolicyValueStore::Set(
WriteOptions options,
- const base::DictionaryValue& settings) {
+ const base::Value::Dict& settings) {
return WriteResult(ReadOnlyError());
}
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 e202a7c6123..bf9ee43cc68 100644
--- a/chromium/chrome/browser/extensions/api/storage/policy_value_store.h
+++ b/chromium/chrome/browser/extensions/api/storage/policy_value_store.h
@@ -55,7 +55,7 @@ class PolicyValueStore : public value_store::ValueStore {
const std::string& key,
const base::Value& value) override;
WriteResult Set(WriteOptions options,
- const base::DictionaryValue& values) override;
+ const base::Value::Dict& values) override;
WriteResult Remove(const std::string& key) override;
WriteResult Remove(const std::vector<std::string>& keys) override;
WriteResult Clear() override;
diff --git a/chromium/chrome/browser/extensions/api/storage/policy_value_store_unittest.cc b/chromium/chrome/browser/extensions/api/storage/policy_value_store_unittest.cc
index 7c2b390bd1d..90a86e253da 100644
--- a/chromium/chrome/browser/extensions/api/storage/policy_value_store_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/storage/policy_value_store_unittest.cc
@@ -90,7 +90,7 @@ class MutablePolicyValueStore : public PolicyValueStore {
}
WriteResult Set(WriteOptions options,
- const base::DictionaryValue& values) override {
+ const base::Value::Dict& values) override {
return delegate()->Set(options, values);
}
@@ -166,10 +166,11 @@ TEST_F(PolicyValueStoreTest, DontProvideRecommendedPolicies) {
ValueStore::ReadResult result = store_->Get();
ASSERT_TRUE(result.status().ok());
- EXPECT_EQ(1u, result.settings().DictSize());
- base::Value* value = NULL;
- EXPECT_FALSE(result.settings().Get("may", &value));
- EXPECT_TRUE(result.settings().Get("must", &value));
+ EXPECT_EQ(1u, result.settings().size());
+ base::Value* value = result.settings().Find("may");
+ EXPECT_FALSE(value);
+ value = result.settings().Find("must");
+ ASSERT_TRUE(value);
EXPECT_EQ(expected, *value);
}
@@ -179,8 +180,8 @@ TEST_F(PolicyValueStoreTest, ReadOnly) {
base::Value string_value("value");
EXPECT_FALSE(store_->Set(options, "key", string_value).status().ok());
- base::DictionaryValue dict;
- dict.SetStringKey("key", "value");
+ base::Value::Dict dict;
+ dict.Set("key", "value");
EXPECT_FALSE(store_->Set(options, dict).status().ok());
EXPECT_FALSE(store_->Remove("key").status().ok());
diff --git a/chromium/chrome/browser/extensions/api/storage/settings_apitest.cc b/chromium/chrome/browser/extensions/api/storage/settings_apitest.cc
index fa3996c16ff..25e0302ab3a 100644
--- a/chromium/chrome/browser/extensions/api/storage/settings_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/storage/settings_apitest.cc
@@ -29,9 +29,9 @@
#include "components/sync/model/sync_change_processor.h"
#include "components/sync/model/sync_error_factory.h"
#include "components/sync/model/syncable_service.h"
-#include "components/sync/test/model/fake_sync_change_processor.h"
-#include "components/sync/test/model/sync_change_processor_wrapper_for_test.h"
-#include "components/sync/test/model/sync_error_factory_mock.h"
+#include "components/sync/test/fake_sync_change_processor.h"
+#include "components/sync/test/sync_change_processor_wrapper_for_test.h"
+#include "components/sync/test/sync_error_factory_mock.h"
#include "components/version_info/channel.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/api/storage/backend_task_runner.h"
diff --git a/chromium/chrome/browser/extensions/api/storage/settings_sync_unittest.cc b/chromium/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
index eee647483f8..ff22cc8d41b 100644
--- a/chromium/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
@@ -22,8 +22,8 @@
#include "chrome/test/base/testing_profile.h"
#include "components/sync/model/sync_change_processor.h"
#include "components/sync/model/sync_error_factory.h"
-#include "components/sync/test/model/sync_change_processor_wrapper_for_test.h"
-#include "components/sync/test/model/sync_error_factory_mock.h"
+#include "components/sync/test/sync_change_processor_wrapper_for_test.h"
+#include "components/sync/test/sync_error_factory_mock.h"
#include "components/value_store/test_value_store_factory.h"
#include "components/value_store/testing_value_store.h"
#include "content/public/test/browser_task_environment.h"
@@ -98,7 +98,8 @@ testing::AssertionResult SettingsEq(const char* _1,
<< "Expected: " << expected
<< ", actual has error: " << actual.status().message;
}
- return ValuesEq(_1, _2, &expected, &actual.settings());
+ base::Value settings(actual.PassSettings());
+ return ValuesEq(_1, _2, &expected, &settings);
}
// SyncChangeProcessor which just records the changes made, accessed after
diff --git a/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.cc b/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.cc
index 961c263e028..4b2ce7b403a 100644
--- a/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.cc
+++ b/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.cc
@@ -22,10 +22,10 @@ namespace extensions {
namespace {
void AddAllSyncData(const std::string& extension_id,
- const base::DictionaryValue& src,
+ const base::Value::Dict& src,
syncer::ModelType type,
syncer::SyncDataList* dst) {
- for (auto it : src.DictItems()) {
+ for (auto it : src) {
dst->push_back(settings_sync_util::CreateData(extension_id, it.first,
it.second, type));
}
diff --git a/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.cc b/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.cc
index f43309ea257..73f873eda70 100644
--- a/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.cc
+++ b/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.cc
@@ -97,7 +97,8 @@ ValueStore::WriteResult SyncableSettingsStorage::Set(
}
ValueStore::WriteResult SyncableSettingsStorage::Set(
- WriteOptions options, const base::DictionaryValue& values) {
+ WriteOptions options,
+ const base::Value::Dict& values) {
DCHECK(IsOnBackendSequence());
WriteResult result = HandleResult(delegate_->Set(options, values));
if (!result.status().ok())
@@ -172,8 +173,7 @@ absl::optional<syncer::ModelError> SyncableSettingsStorage::StartSyncing(
maybe_settings.status().message.c_str()));
}
- std::unique_ptr<base::DictionaryValue> current_settings =
- maybe_settings.PassSettings();
+ base::Value::Dict current_settings = maybe_settings.PassSettings();
return sync_state->DictEmpty()
? SendLocalSettingsToSync(std::move(current_settings))
: OverwriteLocalSettingsWithSync(std::move(sync_state),
@@ -182,15 +182,15 @@ absl::optional<syncer::ModelError> SyncableSettingsStorage::StartSyncing(
absl::optional<syncer::ModelError>
SyncableSettingsStorage::SendLocalSettingsToSync(
- std::unique_ptr<base::DictionaryValue> local_state) {
+ base::Value::Dict local_state) {
DCHECK(IsOnBackendSequence());
- if (local_state->DictEmpty())
+ if (local_state.empty())
return absl::nullopt;
// Transform the current settings into a list of sync changes.
value_store::ValueStoreChangeList changes;
- for (auto pair : local_state->DictItems()) {
+ for (auto pair : local_state) {
changes.push_back(value_store::ValueStoreChange(pair.first, absl::nullopt,
std::move(pair.second)));
}
@@ -205,13 +205,13 @@ SyncableSettingsStorage::SendLocalSettingsToSync(
absl::optional<syncer::ModelError>
SyncableSettingsStorage::OverwriteLocalSettingsWithSync(
std::unique_ptr<base::DictionaryValue> sync_state,
- std::unique_ptr<base::DictionaryValue> local_state) {
+ base::Value::Dict local_state) {
DCHECK(IsOnBackendSequence());
// This is implemented by building up a list of sync changes then sending
// those to ProcessSyncChanges. This generates events like onStorageChanged.
std::unique_ptr<SettingSyncDataList> changes(new SettingSyncDataList());
- for (auto it : local_state->DictItems()) {
+ for (auto it : local_state) {
absl::optional<base::Value> sync_value = sync_state->ExtractKey(it.first);
if (sync_value.has_value()) {
if (*sync_value == it.second) {
@@ -277,7 +277,7 @@ absl::optional<syncer::ModelError> SyncableSettingsStorage::ProcessSyncChanges(
sync_processor_->type()));
continue;
}
- current_value = maybe_settings.settings().ExtractKey(key);
+ current_value = maybe_settings.settings().Extract(key);
}
syncer::SyncError error;
diff --git a/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.h b/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.h
index 15d9abcc821..4f7c328caeb 100644
--- a/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.h
+++ b/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.h
@@ -54,7 +54,7 @@ class SyncableSettingsStorage : public value_store::ValueStore {
const std::string& key,
const base::Value& value) override;
WriteResult Set(WriteOptions options,
- const base::DictionaryValue& values) override;
+ const base::Value::Dict& values) override;
WriteResult Remove(const std::string& key) override;
WriteResult Remove(const std::vector<std::string>& keys) override;
WriteResult Clear() override;
@@ -94,13 +94,13 @@ class SyncableSettingsStorage : public value_store::ValueStore {
// in sync yet.
// Returns any error when trying to sync, or absl::nullopt on success.
absl::optional<syncer::ModelError> SendLocalSettingsToSync(
- std::unique_ptr<base::DictionaryValue> local_state);
+ base::Value::Dict local_state);
// Overwrites local state with sync state.
// Returns any error when trying to sync, or absl::nullopt on success.
absl::optional<syncer::ModelError> OverwriteLocalSettingsWithSync(
std::unique_ptr<base::DictionaryValue> sync_state,
- std::unique_ptr<base::DictionaryValue> local_state);
+ base::Value::Dict local_state);
// Called when an Add/Update/Remove comes from sync.
syncer::SyncError OnSyncAdd(const std::string& key,
diff --git a/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.cc b/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.cc
index 2f5f7a76451..b2095ffc3fc 100644
--- a/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "chrome/browser/extensions/extension_tab_util.h"
-#include "chrome/browser/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.h"
+#include "chrome/browser/preloading/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.h"
#include "components/no_state_prefetch/browser/no_state_prefetch_contents.h"
#include "components/sessions/core/session_id.h"
#include "content/public/browser/browser_thread.h"
diff --git a/chromium/chrome/browser/extensions/api/system_display/system_display_extension_apitest.cc b/chromium/chrome/browser/extensions/api/system_display/system_display_extension_apitest.cc
index 837d0bd43df..0315a196572 100644
--- a/chromium/chrome/browser/extensions/api/system_display/system_display_extension_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/system_display/system_display_extension_apitest.cc
@@ -62,7 +62,7 @@ IN_PROC_BROWSER_TEST_P(SystemDisplayExtensionApiTest, GetDisplayInfo) {
#endif // BUILDFLAG(IS_WIN)
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
+#if !(BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS))
using SystemDisplayExtensionApiFunctionTest = SystemDisplayExtensionApiTest;
diff --git a/chromium/chrome/browser/extensions/api/system_private/system_private_api.cc b/chromium/chrome/browser/extensions/api/system_private/system_private_api.cc
index 6c5df053249..7b12c529482 100644
--- a/chromium/chrome/browser/extensions/api/system_private/system_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/system_private/system_private_api.cc
@@ -19,8 +19,7 @@
#include "google_apis/google_api_keys.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/dbus/dbus_thread_manager.h" // nogncheck
-#include "chromeos/dbus/update_engine/update_engine_client.h"
+#include "chromeos/ash/components/dbus/update_engine/update_engine_client.h"
#else
#include "chrome/browser/upgrade_detector/upgrade_detector.h"
#endif
@@ -71,9 +70,8 @@ ExtensionFunction::ResponseAction SystemPrivateGetUpdateStatusFunction::Run() {
#if BUILDFLAG(IS_CHROMEOS_ASH)
// With UpdateEngineClient, we can provide more detailed information about
// system updates on ChromeOS.
- const update_engine::StatusResult status = chromeos::DBusThreadManager::Get()
- ->GetUpdateEngineClient()
- ->GetLastStatus();
+ const update_engine::StatusResult status =
+ ash::UpdateEngineClient::Get()->GetLastStatus();
// |download_progress| is set to 1 after download finishes
// (i.e. verify, finalize and need-reboot phase) to indicate the progress
// even though |status.download_progress| is 0 in these phases.
@@ -110,6 +108,8 @@ ExtensionFunction::ResponseAction SystemPrivateGetUpdateStatusFunction::Run() {
case update_engine::Operation::REPORTING_ERROR_EVENT:
case update_engine::Operation::ATTEMPTING_ROLLBACK:
case update_engine::Operation::NEED_PERMISSION_TO_UPDATE:
+ case update_engine::Operation::CLEANUP_PREVIOUS_UPDATE:
+ case update_engine::Operation::UPDATED_BUT_DEFERRED:
state = kNotAvailableState;
break;
default:
diff --git a/chromium/chrome/browser/extensions/api/system_private/system_private_apitest.cc b/chromium/chrome/browser/extensions/api/system_private/system_private_apitest.cc
index ce8416d6e26..d20c2ab1b08 100644
--- a/chromium/chrome/browser/extensions/api/system_private/system_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/system_private/system_private_apitest.cc
@@ -12,10 +12,8 @@
#include "content/public/test/browser_test.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/dbus/dbus_thread_manager.h" // nogncheck
-#include "chromeos/dbus/update_engine/fake_update_engine_client.h"
-
-using chromeos::UpdateEngineClient;
+#include "chromeos/ash/components/dbus/update_engine/fake_update_engine_client.h"
+#include "chromeos/ash/components/dbus/update_engine/update_engine_client.h"
#endif
namespace extensions {
@@ -33,16 +31,15 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, GetIncognitoModeAvailability) {
class GetUpdateStatusApiTest : public ExtensionApiTest {
public:
- GetUpdateStatusApiTest() : fake_update_engine_client_(NULL) {}
+ GetUpdateStatusApiTest() = default;
GetUpdateStatusApiTest(const GetUpdateStatusApiTest&) = delete;
GetUpdateStatusApiTest& operator=(const GetUpdateStatusApiTest&) = delete;
void SetUpInProcessBrowserTestFixture() override {
ExtensionApiTest::SetUpInProcessBrowserTestFixture();
- fake_update_engine_client_ = new chromeos::FakeUpdateEngineClient;
- chromeos::DBusThreadManager::GetSetterForTesting()->SetUpdateEngineClient(
- std::unique_ptr<UpdateEngineClient>(fake_update_engine_client_));
+ fake_update_engine_client_ =
+ ash::UpdateEngineClient::InitializeFakeForTest();
}
void TearDownInProcessBrowserTestFixture() override {
@@ -50,7 +47,7 @@ class GetUpdateStatusApiTest : public ExtensionApiTest {
}
protected:
- chromeos::FakeUpdateEngineClient* fake_update_engine_client_;
+ ash::FakeUpdateEngineClient* fake_update_engine_client_ = nullptr;
};
IN_PROC_BROWSER_TEST_F(GetUpdateStatusApiTest, Progress) {
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 65926f8d389..ce6e33f6d4b 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
@@ -292,14 +292,13 @@ void TabCaptureRegistry::DispatchStatusChangeEvent(
if (!router)
return;
- std::unique_ptr<base::ListValue> args(new base::ListValue());
+ base::Value::List args;
tab_capture::CaptureInfo info;
request->GetCaptureInfo(&info);
- args->GetList().Append(base::Value::FromUniquePtrValue(info.ToValue()));
+ args.Append(base::Value::FromUniquePtrValue(info.ToValue()));
auto event = std::make_unique<Event>(events::TAB_CAPTURE_ON_STATUS_CHANGED,
tab_capture::OnStatusChanged::kEventName,
- std::move(*args).TakeListDeprecated(),
- browser_context_);
+ std::move(args), browser_context_);
router->DispatchEventToExtension(request->extension_id(), std::move(event));
}
diff --git a/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc b/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc
index ba2780236a4..0fac333c0db 100644
--- a/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc
+++ b/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_api.cc
@@ -316,7 +316,7 @@ bool TabGroupsMoveFunction::MoveGroup(int group_id,
// Attach tabs in consecutive indices, to insert them in the same order.
target_tab_strip->InsertWebContentsAt(new_index + i,
std::move(web_contents),
- TabStripModel::ADD_NONE, *group);
+ AddTabTypes::ADD_NONE, *group);
}
return true;
diff --git a/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.cc b/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.cc
index efc4e7be62e..3d4942b9acf 100644
--- a/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.cc
+++ b/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.cc
@@ -94,7 +94,7 @@ void TabGroupsEventRouter::DispatchGroupUpdated(tab_groups::TabGroupId group) {
void TabGroupsEventRouter::DispatchEvent(events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> args) {
+ base::Value::List args) {
// |event_router_| can be null in tests.
if (!event_router_)
return;
diff --git a/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.h b/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.h
index 45956ad4763..f946ab60cf8 100644
--- a/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.h
+++ b/chromium/chrome/browser/extensions/api/tab_groups/tab_groups_event_router.h
@@ -48,7 +48,7 @@ class TabGroupsEventRouter : public TabStripModelObserver,
void DispatchEvent(events::HistogramValue histogram_value,
const std::string& event_name,
- std::vector<base::Value> args);
+ base::Value::List args);
const raw_ptr<Profile> profile_;
const raw_ptr<EventRouter> event_router_ = nullptr;
diff --git a/chromium/chrome/browser/extensions/api/tabs/execute_script_apitest.cc b/chromium/chrome/browser/extensions/api/tabs/execute_script_apitest.cc
index e4bc05e4d1f..8c1d9c421ce 100644
--- a/chromium/chrome/browser/extensions/api/tabs/execute_script_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/execute_script_apitest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/cfi_buildflags.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
@@ -196,8 +197,9 @@ class BackForwardCacheDisabledDestructiveScriptTest
base::test::ScopedFeatureList scoped_feature_list_;
};
-// Flaky on ASAN and -dbg. crbug.com/1293865
-#if defined(ADDRESS_SANITIZER) || !defined(NDEBUG)
+// Flaky on ASAN and -dbg, and Linux CFI bots. crbug.com/1293865
+#if defined(ADDRESS_SANITIZER) || !defined(NDEBUG) || \
+ (BUILDFLAG(CFI_ICALL_CHECK) && BUILDFLAG(IS_LINUX))
#define MAYBE_SynchronousRemoval DISABLED_SynchronousRemoval
#else
#define MAYBE_SynchronousRemoval SynchronousRemoval
@@ -208,8 +210,9 @@ IN_PROC_BROWSER_TEST_P(BackForwardCacheDisabledDestructiveScriptTest,
ASSERT_TRUE(RunSubtest("synchronous")) << message_;
}
-// Flaky on ASAN and -dbg. crbug.com/1293865
-#if defined(ADDRESS_SANITIZER) || !defined(NDEBUG)
+// Flaky on ASAN and -dbg and Linux CFI. crbug.com/1293865
+#if defined(ADDRESS_SANITIZER) || !defined(NDEBUG) || \
+ (BUILDFLAG(CFI_ICALL_CHECK) && BUILDFLAG(IS_LINUX))
#define MAYBE_MicrotaskRemoval DISABLED_MicrotaskRemoval
#else
#define MAYBE_MicrotaskRemoval MicrotaskRemoval
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc
index 0f9c3953b34..df2d3177c4f 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -58,9 +58,11 @@
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/recently_audible_helper.h"
+#include "chrome/browser/ui/tabs/tab_enums.h"
#include "chrome/browser/ui/tabs/tab_group.h"
#include "chrome/browser/ui/tabs/tab_group_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/tabs/tab_strip_user_gesture_details.h"
#include "chrome/browser/ui/tabs/tab_utils.h"
#include "chrome/browser/ui/window_sizer/window_sizer.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
@@ -365,7 +367,7 @@ int MoveTabToWindow(ExtensionFunction* function,
target_index = target_tab_strip->count();
return target_tab_strip->InsertWebContentsAt(
- target_index, std::move(web_contents), TabStripModel::ADD_NONE);
+ target_index, std::move(web_contents), AddTabTypes::ADD_NONE);
}
// This function sets the state of the browser window to a "locked"
@@ -792,7 +794,7 @@ ExtensionFunction::ResponseAction WindowsCreateFunction::Run() {
if (!target_tab_strip)
return RespondNow(Error(tabs_constants::kTabStripNotEditableError));
target_tab_strip->InsertWebContentsAt(
- urls.size(), std::move(detached_tab), TabStripModel::ADD_NONE);
+ urls.size(), std::move(detached_tab), AddTabTypes::ADD_NONE);
}
}
// Create a new tab if the created window is still empty. Don't create a new
@@ -800,7 +802,10 @@ ExtensionFunction::ResponseAction WindowsCreateFunction::Run() {
if (!contents && urls.empty() && window_type == Browser::TYPE_NORMAL) {
chrome::NewTab(new_window);
}
- chrome::SelectNumberedTab(new_window, 0, {TabStripModel::GestureType::kNone});
+ chrome::SelectNumberedTab(
+ new_window, 0,
+ TabStripUserGestureDetails(
+ TabStripUserGestureDetails::GestureType::kNone));
if (focused) {
new_window->window()->Show();
@@ -1389,7 +1394,7 @@ ExtensionFunction::ResponseAction TabsHighlightFunction::Run() {
if (!tabstrip)
return RespondNow(Error(tabs_constants::kTabStripNotEditableError));
ui::ListSelectionModel selection;
- int active_index = -1;
+ absl::optional<size_t> active_index;
if (params->highlight_info.tabs.as_integers) {
std::vector<int>& tab_indices = *params->highlight_info.tabs.as_integers;
@@ -1426,7 +1431,7 @@ ExtensionFunction::ResponseAction TabsHighlightFunction::Run() {
bool TabsHighlightFunction::HighlightTab(TabStripModel* tabstrip,
ui::ListSelectionModel* selection,
- int* active_index,
+ absl::optional<size_t>* active_index,
int index,
std::string* error) {
// Make sure the index is in range.
@@ -1437,8 +1442,8 @@ bool TabsHighlightFunction::HighlightTab(TabStripModel* tabstrip,
}
// By default, we make the first tab in the list active.
- if (*active_index == -1)
- *active_index = index;
+ if (!active_index->has_value())
+ *active_index = static_cast<size_t>(index);
selection->AddIndexToSelection(index);
return true;
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_api.h b/chromium/chrome/browser/extensions/api/tabs/tabs_api.h
index 03d1938fa7f..81302bfd4cb 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_api.h
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_api.h
@@ -126,7 +126,7 @@ class TabsHighlightFunction : public ExtensionFunction {
ResponseAction Run() override;
bool HighlightTab(TabStripModel* tabstrip,
ui::ListSelectionModel* selection,
- int* active_index,
+ absl::optional<size_t>* active_index,
int index,
std::string* error);
DECLARE_EXTENSION_FUNCTION("tabs.highlight", TABS_HIGHLIGHT)
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 7154cba7b24..c5c83950cac 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
@@ -1117,8 +1117,9 @@ TEST_F(TabsApiUnitTest, TabsGoForwardAndBackWithoutTabId) {
ASSERT_EQ(2, tab_strip_model->count());
// Activate first tab.
- tab_strip_model->ActivateTabAt(tab1_index,
- {TabStripModel::GestureType::kOther});
+ tab_strip_model->ActivateTabAt(
+ tab1_index, TabStripUserGestureDetails(
+ TabStripUserGestureDetails::GestureType::kOther));
// Go back without tab_id. But first tab should be navigated since it's
// activated.
@@ -1149,8 +1150,9 @@ TEST_F(TabsApiUnitTest, TabsGoForwardAndBackWithoutTabId) {
controller.GetLastCommittedEntry()->GetTransitionType());
// Activate second tab.
- tab_strip_model->ActivateTabAt(tab2_index,
- {TabStripModel::GestureType::kOther});
+ tab_strip_model->ActivateTabAt(
+ tab2_index, TabStripUserGestureDetails(
+ TabStripUserGestureDetails::GestureType::kOther));
auto goback_function2 = base::MakeRefCounted<TabsGoBackFunction>();
goback_function2->set_extension(extension_with_tabs_permission.get());
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_apitest.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_apitest.cc
index 2d28188efde..7dc16b8b529 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_apitest.cc
@@ -22,6 +22,7 @@
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/prerender_test_util.h"
#include "extensions/test/result_catcher.h"
#include "extensions/test/test_extension_dir.h"
#include "net/dns/mock_host_resolver.h"
@@ -465,6 +466,27 @@ IN_PROC_BROWSER_TEST_P(IncognitoExtensionApiTabTest, Tabs) {
INSTANTIATE_TEST_SUITE_P(All, IncognitoExtensionApiTabTest, testing::Bool());
+class ExtensionApiTabPrerenderingTest : public ExtensionApiTabTest {
+ public:
+ ExtensionApiTabPrerenderingTest()
+ : prerender_helper_(base::BindRepeating(
+ &ExtensionApiTabPrerenderingTest::GetWebContents,
+ base::Unretained(this))) {}
+ ~ExtensionApiTabPrerenderingTest() override = default;
+
+ content::WebContents* GetWebContents() {
+ return browser()->tab_strip_model()->GetWebContentsAt(0);
+ }
+
+ private:
+ content::test::PrerenderTestHelper prerender_helper_;
+};
+
+// TODO(crbug.com/1352966): Flaky on multiple platforms.
+IN_PROC_BROWSER_TEST_F(ExtensionApiTabPrerenderingTest, DISABLED_Prerendering) {
+ ASSERT_TRUE(RunExtensionTest("tabs/prerendering")) << message_;
+}
+
// Adding a new test? Awesome. But API tests are the old hotness. The new
// hotness is extension_function_test_utils. See tabs_test.cc for an example.
// We are trying to phase out many uses of API tests as they tend to be flaky.
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_event_router.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_event_router.cc
index 18c3467893d..040d5445904 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_event_router.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_event_router.cc
@@ -68,7 +68,7 @@ bool WillDispatchTabUpdatedEvent(
*event_args_out = std::make_unique<base::Value::List>();
(*event_args_out)->Append(ExtensionTabUtil::GetTabId(contents));
- (*event_args_out)->Append(base::Value(std::move(changed_properties)));
+ (*event_args_out)->Append(std::move(changed_properties));
(*event_args_out)->Append(std::move(tab_value));
return true;
}
@@ -239,10 +239,8 @@ void TabsEventRouter::OnTabStripModelChanged(
if (tab_strip_model->empty())
return;
- if (selection.active_tab_changed()) {
- DispatchActiveTabChanged(selection.old_contents, selection.new_contents,
- selection.new_model.active());
- }
+ if (selection.active_tab_changed())
+ DispatchActiveTabChanged(selection.old_contents, selection.new_contents);
if (selection.selection_changed()) {
DispatchTabSelectionChanged(tab_strip_model, selection.old_model);
@@ -297,8 +295,7 @@ void TabsEventRouter::OnZoomChanged(
Profile::FromBrowserContext(data.web_contents->GetBrowserContext());
DispatchEvent(profile, events::TABS_ON_ZOOM_CHANGE,
api::tabs::OnZoomChange::kEventName,
- std::make_unique<base::ListValue>(
- api::tabs::OnZoomChange::Create(zoom_change_info)),
+ api::tabs::OnZoomChange::Create(zoom_change_info),
EventRouter::USER_GESTURE_UNKNOWN);
}
@@ -352,14 +349,14 @@ void TabsEventRouter::DispatchTabInsertedAt(TabStripModel* tab_strip_model,
}
int tab_id = ExtensionTabUtil::GetTabId(contents);
- std::unique_ptr<base::ListValue> args(new base::ListValue);
- args->Append(tab_id);
+ base::Value::List args;
+ args.Append(tab_id);
base::Value::Dict object_args;
object_args.Set(tabs_constants::kNewWindowIdKey,
Value(ExtensionTabUtil::GetWindowIdOfTab(contents)));
object_args.Set(tabs_constants::kNewPositionKey, Value(index));
- args->Append(base::Value(std::move(object_args)));
+ args.Append(std::move(object_args));
Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
DispatchEvent(profile, events::TABS_ON_ATTACHED,
@@ -372,15 +369,15 @@ void TabsEventRouter::DispatchTabClosingAt(TabStripModel* tab_strip_model,
int index) {
int tab_id = ExtensionTabUtil::GetTabId(contents);
- std::unique_ptr<base::ListValue> args(new base::ListValue);
- args->Append(tab_id);
+ base::Value::List args;
+ args.Append(tab_id);
base::Value::Dict object_args;
object_args.Set(tabs_constants::kWindowIdKey,
ExtensionTabUtil::GetWindowIdOfTab(contents));
object_args.Set(tabs_constants::kWindowClosing,
tab_strip_model->closing_all());
- args->Append(base::Value(std::move(object_args)));
+ args.Append(std::move(object_args));
Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
DispatchEvent(profile, events::TABS_ON_REMOVED,
@@ -398,14 +395,14 @@ void TabsEventRouter::DispatchTabDetachedAt(WebContents* contents,
return;
}
- std::unique_ptr<base::ListValue> args(new base::ListValue);
- args->Append(ExtensionTabUtil::GetTabId(contents));
+ base::Value::List args;
+ args.Append(ExtensionTabUtil::GetTabId(contents));
base::Value::Dict object_args;
object_args.Set(tabs_constants::kOldWindowIdKey,
ExtensionTabUtil::GetWindowIdOfTab(contents));
object_args.Set(tabs_constants::kOldPositionKey, index);
- args->Append(base::Value(std::move(object_args)));
+ args.Append(std::move(object_args));
Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
DispatchEvent(profile, events::TABS_ON_DETACHED,
@@ -414,35 +411,32 @@ void TabsEventRouter::DispatchTabDetachedAt(WebContents* contents,
}
void TabsEventRouter::DispatchActiveTabChanged(WebContents* old_contents,
- WebContents* new_contents,
- int index) {
- auto args = std::make_unique<base::ListValue>();
+ WebContents* new_contents) {
+ base::Value::List args;
int tab_id = ExtensionTabUtil::GetTabId(new_contents);
- args->Append(tab_id);
+ args.Append(tab_id);
base::Value::Dict object_args;
object_args.Set(tabs_constants::kWindowIdKey,
ExtensionTabUtil::GetWindowIdOfTab(new_contents));
- args->Append(base::Value(object_args.Clone()));
+ args.Append(object_args.Clone());
// The onActivated event replaced onActiveChanged and onSelectionChanged. The
// deprecated events take two arguments: tabId, {windowId}.
Profile* profile =
Profile::FromBrowserContext(new_contents->GetBrowserContext());
- DispatchEvent(
- profile, events::TABS_ON_SELECTION_CHANGED,
- api::tabs::OnSelectionChanged::kEventName,
- base::ListValue::From(base::Value::ToUniquePtrValue(args->Clone())),
- EventRouter::USER_GESTURE_UNKNOWN);
+ DispatchEvent(profile, events::TABS_ON_SELECTION_CHANGED,
+ api::tabs::OnSelectionChanged::kEventName, args.Clone(),
+ EventRouter::USER_GESTURE_UNKNOWN);
DispatchEvent(profile, events::TABS_ON_ACTIVE_CHANGED,
api::tabs::OnActiveChanged::kEventName, std::move(args),
EventRouter::USER_GESTURE_UNKNOWN);
// The onActivated event takes one argument: {windowId, tabId}.
- auto on_activated_args = std::make_unique<base::ListValue>();
+ base::Value::List on_activated_args;
object_args.Set(tabs_constants::kTabIdKey, tab_id);
- on_activated_args->Append(base::Value(std::move(object_args)));
+ on_activated_args.Append(std::move(object_args));
DispatchEvent(
profile, events::TABS_ON_ACTIVATED, api::tabs::OnActivated::kEventName,
std::move(on_activated_args), EventRouter::USER_GESTURE_UNKNOWN);
@@ -463,7 +457,7 @@ void TabsEventRouter::DispatchTabSelectionChanged(
all_tabs.Append(tab_id);
}
- std::unique_ptr<base::ListValue> args(new base::ListValue);
+ base::Value::List args;
base::Value::Dict select_info;
select_info.Set(
@@ -471,15 +465,13 @@ void TabsEventRouter::DispatchTabSelectionChanged(
ExtensionTabUtil::GetWindowIdOfTabStripModel(tab_strip_model));
select_info.Set(tabs_constants::kTabIdsKey, std::move(all_tabs));
- args->Append(base::Value(std::move(select_info)));
+ args.Append(std::move(select_info));
// The onHighlighted event replaced onHighlightChanged.
Profile* profile = tab_strip_model->profile();
- DispatchEvent(
- profile, events::TABS_ON_HIGHLIGHT_CHANGED,
- api::tabs::OnHighlightChanged::kEventName,
- base::ListValue::From(base::Value::ToUniquePtrValue(args->Clone())),
- EventRouter::USER_GESTURE_UNKNOWN);
+ DispatchEvent(profile, events::TABS_ON_HIGHLIGHT_CHANGED,
+ api::tabs::OnHighlightChanged::kEventName, args.Clone(),
+ EventRouter::USER_GESTURE_UNKNOWN);
DispatchEvent(profile, events::TABS_ON_HIGHLIGHTED,
api::tabs::OnHighlighted::kEventName, std::move(args),
EventRouter::USER_GESTURE_UNKNOWN);
@@ -488,15 +480,15 @@ void TabsEventRouter::DispatchTabSelectionChanged(
void TabsEventRouter::DispatchTabMoved(WebContents* contents,
int from_index,
int to_index) {
- std::unique_ptr<base::ListValue> args(new base::ListValue);
- args->Append(ExtensionTabUtil::GetTabId(contents));
+ base::Value::List args;
+ args.Append(ExtensionTabUtil::GetTabId(contents));
base::Value::Dict object_args;
object_args.Set(tabs_constants::kWindowIdKey,
ExtensionTabUtil::GetWindowIdOfTab(contents));
object_args.Set(tabs_constants::kFromIndexKey, from_index);
object_args.Set(tabs_constants::kToIndexKey, to_index);
- args->Append(base::Value(std::move(object_args)));
+ args.Append(std::move(object_args));
Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
DispatchEvent(profile, events::TABS_ON_MOVED, api::tabs::OnMoved::kEventName,
@@ -510,9 +502,9 @@ void TabsEventRouter::DispatchTabReplacedAt(WebContents* old_contents,
// WebContents being swapped.
const int new_tab_id = ExtensionTabUtil::GetTabId(new_contents);
const int old_tab_id = ExtensionTabUtil::GetTabId(old_contents);
- std::unique_ptr<base::ListValue> args(new base::ListValue);
- args->Append(new_tab_id);
- args->Append(old_tab_id);
+ base::Value::List args;
+ args.Append(new_tab_id);
+ args.Append(old_tab_id);
DispatchEvent(Profile::FromBrowserContext(new_contents->GetBrowserContext()),
events::TABS_ON_REPLACED, api::tabs::OnReplaced::kEventName,
@@ -530,7 +522,7 @@ void TabsEventRouter::TabCreatedAt(WebContents* contents,
Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
auto event = std::make_unique<Event>(events::TABS_ON_CREATED,
api::tabs::OnCreated::kEventName,
- std::vector<base::Value>(), profile);
+ base::Value::List(), profile);
event->user_gesture = EventRouter::USER_GESTURE_NOT_ENABLED;
event->will_dispatch_callback =
base::BindRepeating(&WillDispatchTabCreatedEvent, contents, active);
@@ -572,15 +564,14 @@ void TabsEventRouter::DispatchEvent(
Profile* profile,
events::HistogramValue histogram_value,
const std::string& event_name,
- std::unique_ptr<base::ListValue> args,
+ base::Value::List args,
EventRouter::UserGestureState user_gesture) {
EventRouter* event_router = EventRouter::Get(profile);
if (!profile_->IsSameOrParent(profile) || !event_router)
return;
- auto event =
- std::make_unique<Event>(histogram_value, event_name,
- std::move(*args).TakeListDeprecated(), profile);
+ auto event = std::make_unique<Event>(histogram_value, event_name,
+ std::move(args), profile);
event->user_gesture = user_gesture;
event_router->BroadcastEvent(std::move(event));
}
@@ -597,7 +588,7 @@ void TabsEventRouter::DispatchTabUpdatedEvent(
events::TABS_ON_UPDATED, api::tabs::OnUpdated::kEventName,
// The event arguments depend on the extension's permission. They are set
// in WillDispatchTabUpdatedEvent().
- std::vector<base::Value>(), profile);
+ base::Value::List(), profile);
event->user_gesture = EventRouter::USER_GESTURE_NOT_ENABLED;
event->will_dispatch_callback =
base::BindRepeating(&WillDispatchTabUpdatedEvent, contents,
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_event_router.h b/chromium/chrome/browser/extensions/api/tabs/tabs_event_router.h
index e65c8ee1c2a..6247466e7fa 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_event_router.h
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_event_router.h
@@ -102,8 +102,7 @@ class TabsEventRouter : public TabStripModelObserver,
int index,
bool was_active);
void DispatchActiveTabChanged(content::WebContents* old_contents,
- content::WebContents* new_contents,
- int index);
+ content::WebContents* new_contents);
void DispatchTabSelectionChanged(TabStripModel* tab_strip_model,
const ui::ListSelectionModel& old_model);
void DispatchTabMoved(content::WebContents* contents,
@@ -132,7 +131,7 @@ class TabsEventRouter : public TabStripModelObserver,
void DispatchEvent(Profile* profile,
events::HistogramValue histogram_value,
const std::string& event_name,
- std::unique_ptr<base::ListValue> args,
+ base::Value::List args,
EventRouter::UserGestureState user_gesture);
// Packages |changed_property_names| as a tab updated event for the tab
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc
index 4e434a237a8..0793f8a36ee 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc
@@ -112,14 +112,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, MAYBE_QueryLastFocusedWindowTabs) {
scoped_refptr<const extensions::Extension> extension(
extensions::ExtensionBuilder("Test").Build());
function->set_extension(extension.get());
- std::unique_ptr<base::ListValue> result(
+ base::Value::List result_tabs(
utils::ToList(utils::RunFunctionAndReturnSingleResult(
function.get(), "[{\"lastFocusedWindow\":true}]", browser())));
- base::ListValue* result_tabs = result.get();
// We should have one initial tab and one added tab.
- EXPECT_EQ(2u, result_tabs->GetListDeprecated().size());
- for (const base::Value& result_tab : result_tabs->GetListDeprecated()) {
+ EXPECT_EQ(2u, result_tabs.size());
+ for (const base::Value& result_tab : result_tabs) {
EXPECT_EQ(focused_window_id,
api_test_utils::GetInteger(utils::ToDictionary(result_tab),
keys::kWindowIdKey));
@@ -128,13 +127,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, MAYBE_QueryLastFocusedWindowTabs) {
// Get tabs NOT in the 'last focused' window called from the focused browser.
function = new extensions::TabsQueryFunction();
function->set_extension(extension.get());
- result = utils::ToList(utils::RunFunctionAndReturnSingleResult(
+ result_tabs = utils::ToList(utils::RunFunctionAndReturnSingleResult(
function.get(), "[{\"lastFocusedWindow\":false}]", browser()));
- result_tabs = result.get();
// We should get one tab for each extra window and one for the initial window.
- EXPECT_EQ(kExtraWindows + 1, result_tabs->GetListDeprecated().size());
- for (const base::Value& result_tab : result_tabs->GetListDeprecated()) {
+ EXPECT_EQ(kExtraWindows + 1, result_tabs.size());
+ for (const base::Value& result_tab : result_tabs) {
EXPECT_NE(focused_window_id,
api_test_utils::GetInteger(utils::ToDictionary(result_tab),
keys::kWindowIdKey));
diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_test.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_test.cc
index 6e4d24ed62d..d1dde378ccb 100644
--- a/chromium/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -176,12 +176,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) {
EXPECT_EQ(window_id, GetWindowId(result));
// "populate" was enabled so tabs should be populated.
- std::unique_ptr<base::ListValue> tabs =
- api_test_utils::GetList(result, keys::kTabsKey);
- ASSERT_TRUE(tabs);
- ASSERT_FALSE(tabs->GetListDeprecated().empty());
- absl::optional<int> tab0_id =
- tabs->GetListDeprecated()[0].FindIntKey(keys::kIdKey);
+ base::Value::List tabs = api_test_utils::GetList(result, keys::kTabsKey);
+ ASSERT_FALSE(tabs.empty());
+ absl::optional<int> tab0_id = tabs[0].GetDict().FindInt(keys::kIdKey);
ASSERT_TRUE(tab0_id.has_value());
EXPECT_GE(*tab0_id, 0);
@@ -263,12 +260,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetCurrentWindow) {
// to RunFunctionAndReturnSingleResult.
EXPECT_EQ(window_id, GetWindowId(result));
// "populate" was enabled so tabs should be populated.
- std::unique_ptr<base::ListValue> tabs =
- api_test_utils::GetList(result, keys::kTabsKey);
- ASSERT_TRUE(tabs);
- ASSERT_FALSE(tabs->GetListDeprecated().empty());
- absl::optional<int> tab0_id =
- tabs->GetListDeprecated()[0].FindIntKey(keys::kIdKey);
+ base::Value::List tabs = api_test_utils::GetList(result, keys::kTabsKey);
+ ASSERT_FALSE(tabs.empty());
+ absl::optional<int> tab0_id = tabs[0].GetDict().FindInt(keys::kIdKey);
ASSERT_TRUE(tab0_id.has_value());
// The tab id should not be -1 as this is a browser window.
EXPECT_GE(*tab0_id, 0);
@@ -297,12 +291,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetAllWindows) {
scoped_refptr<WindowsGetAllFunction> function = new WindowsGetAllFunction();
scoped_refptr<const Extension> extension(ExtensionBuilder("Test").Build());
function->set_extension(extension.get());
- std::unique_ptr<base::ListValue> result = utils::ToList(
+ base::Value::List windows = utils::ToList(
utils::RunFunctionAndReturnSingleResult(function.get(), "[]", browser()));
- base::ListValue* windows = result.get();
- EXPECT_EQ(window_ids.size(), windows->GetListDeprecated().size());
- for (const base::Value& result_window : windows->GetListDeprecated()) {
+ EXPECT_EQ(window_ids.size(), windows.size());
+ for (const base::Value& result_window : windows) {
result_ids.insert(GetWindowId(utils::ToDictionary(result_window)));
// "populate" was not passed in so tabs are not populated.
@@ -315,12 +308,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetAllWindows) {
result_ids.clear();
function = new WindowsGetAllFunction();
function->set_extension(extension.get());
- result = utils::ToList(utils::RunFunctionAndReturnSingleResult(
+ windows = utils::ToList(utils::RunFunctionAndReturnSingleResult(
function.get(), "[{\"populate\": true}]", browser()));
- windows = result.get();
- EXPECT_EQ(window_ids.size(), windows->GetListDeprecated().size());
- for (const base::Value& result_window : windows->GetListDeprecated()) {
+ EXPECT_EQ(window_ids.size(), windows.size());
+ for (const base::Value& result_window : windows) {
result_ids.insert(GetWindowId(utils::ToDictionary(result_window)));
// "populate" was enabled so tabs should be populated.
@@ -361,16 +353,15 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetAllWindowsAllTypes) {
scoped_refptr<WindowsGetAllFunction> function = new WindowsGetAllFunction();
scoped_refptr<const Extension> extension(ExtensionBuilder("Test").Build());
function->set_extension(extension.get());
- std::unique_ptr<base::ListValue> result(
+ base::Value::List windows(
utils::ToList(utils::RunFunctionAndReturnSingleResult(
function.get(),
"[{\"windowTypes\": [\"app\", \"devtools\", \"normal\", \"panel\", "
"\"popup\"]}]",
browser())));
- base::ListValue* windows = result.get();
- EXPECT_EQ(window_ids.size(), windows->GetListDeprecated().size());
- for (const base::Value& result_window : windows->GetListDeprecated()) {
+ EXPECT_EQ(window_ids.size(), windows.size());
+ for (const base::Value& result_window : windows) {
result_ids.insert(GetWindowId(utils::ToDictionary(result_window)));
// "populate" was not passed in so tabs are not populated.
@@ -383,15 +374,14 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetAllWindowsAllTypes) {
result_ids.clear();
function = new WindowsGetAllFunction();
function->set_extension(extension.get());
- result = utils::ToList(utils::RunFunctionAndReturnSingleResult(
+ windows = utils::ToList(utils::RunFunctionAndReturnSingleResult(
function.get(),
"[{\"populate\": true, \"windowTypes\": [\"app\", \"devtools\", "
"\"normal\", \"panel\", \"popup\"]}]",
browser()));
- windows = result.get();
- EXPECT_EQ(window_ids.size(), windows->GetListDeprecated().size());
- for (const base::Value& result_window : windows->GetListDeprecated()) {
+ EXPECT_EQ(window_ids.size(), windows.size());
+ for (const base::Value& result_window : windows) {
result_ids.insert(GetWindowId(utils::ToDictionary(result_window)));
// "populate" was enabled so tabs should be populated.
@@ -602,27 +592,25 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, QueryCurrentWindowTabs) {
// Get tabs in the 'current' window called from non-focused browser.
scoped_refptr<TabsQueryFunction> function = new TabsQueryFunction();
function->set_extension(ExtensionBuilder("Test").Build().get());
- std::unique_ptr<base::ListValue> result(
+ base::Value::List result_tabs(
utils::ToList(utils::RunFunctionAndReturnSingleResult(
function.get(), "[{\"currentWindow\":true}]", browser())));
- base::ListValue* result_tabs = result.get();
// We should have one initial tab and one added tab.
- EXPECT_EQ(2u, result_tabs->GetListDeprecated().size());
- for (const base::Value& result_tab : result_tabs->GetListDeprecated()) {
+ EXPECT_EQ(2u, result_tabs.size());
+ for (const base::Value& result_tab : result_tabs) {
EXPECT_EQ(window_id, GetTabWindowId(utils::ToDictionary(result_tab)));
}
// Get tabs NOT in the 'current' window called from non-focused browser.
function = new TabsQueryFunction();
function->set_extension(ExtensionBuilder("Test").Build().get());
- result = utils::ToList(utils::RunFunctionAndReturnSingleResult(
+ result_tabs = utils::ToList(utils::RunFunctionAndReturnSingleResult(
function.get(), "[{\"currentWindow\":false}]", browser()));
- result_tabs = result.get();
// We should have one tab for each extra window.
- EXPECT_EQ(kExtraWindows, result_tabs->GetListDeprecated().size());
- for (const base::Value& result_tab : result_tabs->GetListDeprecated()) {
+ EXPECT_EQ(kExtraWindows, result_tabs.size());
+ for (const base::Value& result_tab : result_tabs) {
EXPECT_NE(window_id, GetTabWindowId(utils::ToDictionary(result_tab)));
}
}
@@ -643,15 +631,14 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, QueryAllTabsWithDevTools) {
// Get tabs in the 'current' window called from non-focused browser.
scoped_refptr<TabsQueryFunction> function = new TabsQueryFunction();
function->set_extension(ExtensionBuilder("Test").Build().get());
- std::unique_ptr<base::ListValue> result(
+ base::Value::List result_tabs(
utils::ToList(utils::RunFunctionAndReturnSingleResult(
function.get(), "[{}]", browser())));
std::set<int> result_ids;
- base::ListValue* result_tabs = result.get();
// We should have one tab per browser except for DevTools.
- EXPECT_EQ(kNumWindows, result_tabs->GetListDeprecated().size());
- for (const base::Value& result_tab : result_tabs->GetListDeprecated()) {
+ EXPECT_EQ(kNumWindows, result_tabs.size());
+ for (const base::Value& result_tab : result_tabs) {
result_ids.insert(GetTabWindowId(utils::ToDictionary(result_tab)));
}
EXPECT_EQ(window_ids, result_ids);
@@ -674,11 +661,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, QueryTabGroups) {
constexpr char kFormatQueryArgs[] = R"([{"groupId":%d}])";
const std::string args = base::StringPrintf(
kFormatQueryArgs, tab_groups_util::GetGroupId(group_id));
- std::unique_ptr<base::ListValue> result(
+ base::Value::List result(
utils::ToList(utils::RunFunctionAndReturnSingleResult(function.get(),
args, browser())));
- EXPECT_EQ(2u, result->GetListDeprecated().size());
+ EXPECT_EQ(2u, result.size());
}
IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DontCreateTabInClosingPopupWindow) {
@@ -1264,18 +1251,16 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DiscardedProperty) {
// Get non-discarded tabs.
{
- std::unique_ptr<base::ListValue> result(
- RunQueryFunction("[{\"discarded\": false}]"));
+ base::Value::List result(RunQueryFunction("[{\"discarded\": false}]"));
// The two created plus the default tab.
- EXPECT_EQ(3u, result->GetListDeprecated().size());
+ EXPECT_EQ(3u, result.size());
}
// Get discarded tabs.
{
- std::unique_ptr<base::ListValue> result(
- RunQueryFunction("[{\"discarded\": true}]"));
- EXPECT_EQ(0u, result->GetListDeprecated().size());
+ base::Value::List result(RunQueryFunction("[{\"discarded\": true}]"));
+ EXPECT_EQ(0u, result.size());
}
TabStripModel* tab_strip_model = browser()->tab_strip_model();
@@ -1297,22 +1282,19 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DiscardedProperty) {
// Get non-discarded tabs after discarding one tab.
{
- std::unique_ptr<base::ListValue> result(
- RunQueryFunction("[{\"discarded\": false}]"));
- EXPECT_EQ(2u, result->GetListDeprecated().size());
+ base::Value::List result(RunQueryFunction("[{\"discarded\": false}]"));
+ EXPECT_EQ(2u, result.size());
}
// Get discarded tabs after discarding one tab.
{
- std::unique_ptr<base::ListValue> result(
- RunQueryFunction("[{\"discarded\": true}]"));
- EXPECT_EQ(1u, result->GetListDeprecated().size());
+ base::Value::List result(RunQueryFunction("[{\"discarded\": true}]"));
+ EXPECT_EQ(1u, result.size());
// Make sure the returned tab is the correct one.
int tab_id_a = ExtensionTabUtil::GetTabId(web_contents_a);
- absl::optional<int> id =
- result->GetListDeprecated()[0].FindIntKey(keys::kIdKey);
+ absl::optional<int> id = result[0].FindIntKey(keys::kIdKey);
ASSERT_TRUE(id);
EXPECT_EQ(tab_id_a, *id);
@@ -1323,16 +1305,14 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DiscardedProperty) {
// Get non-discarded tabs after discarding two created tabs.
{
- std::unique_ptr<base::ListValue> result(
- RunQueryFunction("[{\"discarded\": false}]"));
- ASSERT_EQ(1u, result->GetListDeprecated().size());
+ base::Value::List result(RunQueryFunction("[{\"discarded\": false}]"));
+ ASSERT_EQ(1u, result.size());
// Make sure the returned tab is the correct one.
int tab_id_c =
ExtensionTabUtil::GetTabId(tab_strip_model->GetWebContentsAt(0));
- absl::optional<int> id =
- result->GetListDeprecated()[0].FindIntKey(keys::kIdKey);
+ absl::optional<int> id = result[0].FindIntKey(keys::kIdKey);
ASSERT_TRUE(id);
EXPECT_EQ(tab_id_c, *id);
@@ -1340,9 +1320,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DiscardedProperty) {
// Get discarded tabs after discarding two created tabs.
{
- std::unique_ptr<base::ListValue> result(
- RunQueryFunction("[{\"discarded\": true}]"));
- EXPECT_EQ(2u, result->GetListDeprecated().size());
+ base::Value::List result(RunQueryFunction("[{\"discarded\": true}]"));
+ EXPECT_EQ(2u, result.size());
}
// Activates the first created tab.
@@ -1350,16 +1329,14 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DiscardedProperty) {
// Get non-discarded tabs after activating a discarded tab.
{
- std::unique_ptr<base::ListValue> result(
- RunQueryFunction("[{\"discarded\": false}]"));
- EXPECT_EQ(2u, result->GetListDeprecated().size());
+ base::Value::List result(RunQueryFunction("[{\"discarded\": false}]"));
+ EXPECT_EQ(2u, result.size());
}
// Get discarded tabs after activating a discarded tab.
{
- std::unique_ptr<base::ListValue> result(
- RunQueryFunction("[{\"discarded\": true}]"));
- EXPECT_EQ(1u, result->GetListDeprecated().size());
+ base::Value::List result(RunQueryFunction("[{\"discarded\": true}]"));
+ EXPECT_EQ(1u, result.size());
}
}
@@ -1507,21 +1484,19 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, AutoDiscardableProperty) {
// Queries and results used.
const char* kAutoDiscardableQueryInfo = "[{\"autoDiscardable\": true}]";
const char* kNonAutoDiscardableQueryInfo = "[{\"autoDiscardable\": false}]";
- std::unique_ptr<base::ListValue> query_result;
- base::Value::Dict update_result;
// Get auto-discardable tabs. Returns all since tabs are auto-discardable
// by default.
- query_result = RunQueryFunction(kAutoDiscardableQueryInfo);
- EXPECT_EQ(3u, query_result->GetListDeprecated().size());
+ base::Value::List query_result = RunQueryFunction(kAutoDiscardableQueryInfo);
+ EXPECT_EQ(3u, query_result.size());
// Get non auto-discardable tabs.
query_result = RunQueryFunction(kNonAutoDiscardableQueryInfo);
- EXPECT_EQ(0u, query_result->GetListDeprecated().size());
+ EXPECT_EQ(0u, query_result.size());
// Update the auto-discardable state of web contents A.
int tab_id_a = ExtensionTabUtil::GetTabId(web_contents_a);
- update_result = RunUpdateFunction(
+ base::Value::Dict update_result = RunUpdateFunction(
base::StringPrintf("[%u, {\"autoDiscardable\": false}]", tab_id_a));
EXPECT_EQ(tab_id_a, api_test_utils::GetInteger(update_result, "id"));
EXPECT_FALSE(api_test_utils::GetBoolean(update_result, "autoDiscardable"));
@@ -1533,15 +1508,14 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, AutoDiscardableProperty) {
// Get auto-discardable tabs after changing the status of web contents A.
query_result = RunQueryFunction(kAutoDiscardableQueryInfo);
- EXPECT_EQ(2u, query_result->GetListDeprecated().size());
+ EXPECT_EQ(2u, query_result.size());
// Get non auto-discardable tabs after changing the status of web contents A.
query_result = RunQueryFunction(kNonAutoDiscardableQueryInfo);
- ASSERT_EQ(1u, query_result->GetListDeprecated().size());
+ ASSERT_EQ(1u, query_result.size());
// Make sure the returned tab is the correct one.
- absl::optional<int> tab_id =
- query_result->GetListDeprecated()[0].FindIntKey(keys::kIdKey);
+ absl::optional<int> tab_id = query_result[0].FindIntKey(keys::kIdKey);
ASSERT_TRUE(tab_id);
EXPECT_EQ(tab_id_a, *tab_id);
@@ -1554,18 +1528,17 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, AutoDiscardableProperty) {
// Get auto-discardable tabs after changing the status of both created tabs.
query_result = RunQueryFunction(kAutoDiscardableQueryInfo);
- EXPECT_EQ(1u, query_result->GetListDeprecated().size());
+ EXPECT_EQ(1u, query_result.size());
// Make sure the returned tab is the correct one.
- absl::optional<int> id_value =
- query_result->GetListDeprecated()[0].FindIntKey(keys::kIdKey);
+ absl::optional<int> id_value = query_result[0].FindIntKey(keys::kIdKey);
ASSERT_TRUE(id_value);
EXPECT_EQ(ExtensionTabUtil::GetTabId(tab_strip_model->GetWebContentsAt(0)),
*id_value);
// Get auto-discardable tabs after changing the status of both created tabs.
query_result = RunQueryFunction(kNonAutoDiscardableQueryInfo);
- EXPECT_EQ(2u, query_result->GetListDeprecated().size());
+ EXPECT_EQ(2u, query_result.size());
// Resets the first tab back to auto-discardable.
update_result = RunUpdateFunction(
@@ -1575,11 +1548,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, AutoDiscardableProperty) {
// Get auto-discardable tabs after resetting the status of web contents A.
query_result = RunQueryFunction(kAutoDiscardableQueryInfo);
- EXPECT_EQ(2u, query_result->GetListDeprecated().size());
+ EXPECT_EQ(2u, query_result.size());
// Get non auto-discardable tabs after resetting the status of web contents A.
query_result = RunQueryFunction(kNonAutoDiscardableQueryInfo);
- EXPECT_EQ(1u, query_result->GetListDeprecated().size());
+ EXPECT_EQ(1u, query_result.size());
}
// Tester class for the tabs.zoom* api functions.
@@ -2055,11 +2028,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TemporaryAddressSpoof) {
ASSERT_TRUE(navigation_manager.WaitForRequestStart());
browser()->tab_strip_model()->ActivateTabAt(
- 0, {TabStripModel::GestureType::kOther});
+ 0, TabStripUserGestureDetails(
+ TabStripUserGestureDetails::GestureType::kOther));
EXPECT_EQ(first_web_contents,
browser()->tab_strip_model()->GetActiveWebContents());
browser()->tab_strip_model()->ActivateTabAt(
- 1, {TabStripModel::GestureType::kOther});
+ 1, TabStripUserGestureDetails(
+ TabStripUserGestureDetails::GestureType::kOther));
EXPECT_EQ(second_web_contents,
browser()->tab_strip_model()->GetActiveWebContents());
diff --git a/chromium/chrome/browser/extensions/api/tabs/windows_event_router.cc b/chromium/chrome/browser/extensions/api/tabs/windows_event_router.cc
index 32e03171c0c..4d0befa34c4 100644
--- a/chromium/chrome/browser/extensions/api/tabs/windows_event_router.cc
+++ b/chromium/chrome/browser/extensions/api/tabs/windows_event_router.cc
@@ -304,7 +304,7 @@ void WindowsEventRouter::OnActiveWindowChanged(
std::unique_ptr<Event> event = std::make_unique<Event>(
events::WINDOWS_ON_FOCUS_CHANGED, windows::OnFocusChanged::kEventName,
- std::vector<base::Value>());
+ base::Value::List());
event->will_dispatch_callback =
base::BindRepeating(&WillDispatchWindowFocusedEvent, window_controller);
EventRouter::Get(profile_)->BroadcastEvent(std::move(event));
@@ -315,7 +315,7 @@ void WindowsEventRouter::DispatchEvent(events::HistogramValue histogram_value,
WindowController* window_controller,
std::unique_ptr<base::ListValue> args) {
auto event = std::make_unique<Event>(histogram_value, event_name,
- std::move(*args).TakeListDeprecated(),
+ std::move(args->GetList()),
window_controller->profile());
event->will_dispatch_callback =
base::BindRepeating(&WillDispatchWindowEvent, window_controller);
diff --git a/chromium/chrome/browser/extensions/api/terminal/DIR_METADATA b/chromium/chrome/browser/extensions/api/terminal/DIR_METADATA
index b3cd94034ff..06e627fbb01 100644
--- a/chromium/chrome/browser/extensions/api/terminal/DIR_METADATA
+++ b/chromium/chrome/browser/extensions/api/terminal/DIR_METADATA
@@ -1,3 +1 @@
-monorail {
- component: "UI>Shell>Containers"
-}
+mixins: "//chrome/browser/ash/guest_os/COMMON_METADATA"
diff --git a/chromium/chrome/browser/extensions/api/terminal/crostini_startup_status.cc b/chromium/chrome/browser/extensions/api/terminal/crostini_startup_status.cc
deleted file mode 100644
index 347dd47f287..00000000000
--- a/chromium/chrome/browser/extensions/api/terminal/crostini_startup_status.cc
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/api/terminal/crostini_startup_status.h"
-
-#include <algorithm>
-#include <memory>
-#include <vector>
-
-#include "base/containers/flat_map.h"
-#include "base/location.h"
-#include "base/no_destructor.h"
-#include "base/strings/strcat.h"
-#include "base/strings/stringprintf.h"
-#include "base/system/sys_info.h"
-#include "base/time/time.h"
-#include "chrome/browser/ash/crostini/crostini_util.h"
-#include "chrome/grit/generated_resources.h"
-#include "chromeos/dbus/util/version_loader.h"
-#include "components/version_info/version_info.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "ui/base/l10n/l10n_util.h"
-
-using crostini::mojom::InstallerState;
-
-namespace extensions {
-
-namespace {
-
-const char kCursorHide[] = "\x1b[?25l";
-const char kCursorShow[] = "\x1b[?25h";
-const char kColor0Normal[] = "\x1b[0m"; // Default.
-const char kColor1RedBright[] = "\x1b[1;31m";
-const char kColor2GreenBright[] = "\x1b[1;32m";
-const char kColor3Yellow[] = "\x1b[33m";
-const char kColor5Purple[] = "\x1b[35m";
-const char kEraseInLine[] = "\x1b[K";
-const char kSpinner[] = "|/-\\";
-const int kMaxStage = static_cast<int>(InstallerState::kMaxValue);
-
-std::string MoveForward(int i) {
- return base::StringPrintf("\x1b[%dC", i);
-}
-
-} // namespace
-
-CrostiniStartupStatus::CrostiniStartupStatus(
- base::RepeatingCallback<void(const std::string&)> print,
- bool verbose)
- : print_(std::move(print)), verbose_(verbose) {
-}
-
-CrostiniStartupStatus::~CrostiniStartupStatus() = default;
-
-void CrostiniStartupStatus::OnCrostiniRestarted(
- crostini::CrostiniResult result) {
- if (result != crostini::CrostiniResult::SUCCESS) {
- PrintAfterStage(
- kColor1RedBright,
- base::StringPrintf("\rError starting penguin container: %d (%s)\r\n",
- result, CrostiniResultString(result)));
- crostini::RecordAppLaunchResultHistogram(
- crostini::CrostiniAppLaunchAppType::kTerminal, result);
- } else {
- if (verbose_) {
- // We change the stage_string but don't increment the stage number. This
- // is deliberate, per UX they don't want more pieces in the stage progress
- // bar.
- const std::string& stage_string = l10n_util::GetStringUTF8(
- IDS_CROSTINI_TERMINAL_STATUS_CONNECT_CONTAINER);
- PrintStage(kColor3Yellow, stage_string);
- }
- }
-}
-
-void CrostiniStartupStatus::OnCrostiniConnected(
- crostini::CrostiniResult result) {
- crostini::RecordAppLaunchResultHistogram(
- crostini::CrostiniAppLaunchAppType::kTerminal, result);
- if (result != crostini::CrostiniResult::SUCCESS) {
- PrintAfterStage(
- kColor1RedBright,
- base::StringPrintf(
- "\rError connecting shell to penguin container: %d (%s)\r\n",
- result, CrostiniResultString(result)));
- } else {
- if (verbose_) {
- stage_index_ = kMaxStage + 1; // done.
- PrintStage(kColor2GreenBright,
- base::StrCat({l10n_util::GetStringUTF8(
- IDS_CROSTINI_TERMINAL_STATUS_READY),
- "\r\n"}));
- }
- }
- Print(
- base::StringPrintf("\r%s%s%s", kEraseInLine, kColor0Normal, kCursorShow));
-}
-
-void CrostiniStartupStatus::ShowProgressAtInterval() {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- show_progress_timer_ = std::make_unique<base::RepeatingTimer>();
- show_progress_timer_->Start(FROM_HERE, base::Milliseconds(300),
- base::BindRepeating(
- [](CrostiniStartupStatus* self) {
- self->spinner_index_++;
- self->PrintProgress();
- },
- this));
-}
-
-void CrostiniStartupStatus::OnStageStarted(InstallerState stage) {
- stage_index_ = static_cast<int>(stage) + 1;
- static base::NoDestructor<base::flat_map<InstallerState, std::string>>
- kStartStrings({
- {InstallerState::kStart,
- l10n_util::GetStringUTF8(IDS_CROSTINI_TERMINAL_STATUS_START)},
- {InstallerState::kInstallImageLoader,
- l10n_util::GetStringUTF8(
- IDS_CROSTINI_TERMINAL_STATUS_INSTALL_IMAGE_LOADER)},
- {InstallerState::kCreateDiskImage,
- l10n_util::GetStringUTF8(
- IDS_CROSTINI_TERMINAL_STATUS_CREATE_DISK_IMAGE)},
- {InstallerState::kStartTerminaVm,
- l10n_util::GetStringUTF8(
- IDS_CROSTINI_TERMINAL_STATUS_START_TERMINA_VM)},
- {InstallerState::kStartLxd,
- l10n_util::GetStringUTF8(IDS_CROSTINI_TERMINAL_STATUS_START_LXD)},
- {InstallerState::kCreateContainer,
- l10n_util::GetStringUTF8(
- IDS_CROSTINI_TERMINAL_STATUS_CREATE_CONTAINER)},
- {InstallerState::kSetupContainer,
- l10n_util::GetStringUTF8(
- IDS_CROSTINI_TERMINAL_STATUS_SETUP_CONTAINER)},
- {InstallerState::kStartContainer,
- l10n_util::GetStringUTF8(
- IDS_CROSTINI_TERMINAL_STATUS_START_CONTAINER)},
- });
- const std::string& stage_string =
- verbose_ ? (*kStartStrings)[stage] : std::string();
- PrintStage(kColor3Yellow, stage_string);
-}
-
-void CrostiniStartupStatus::OnContainerDownloading(int32_t download_percent) {
- if (download_percent % 8 == 0) {
- PrintAfterStage(kColor3Yellow, ".");
- }
-}
-
-void CrostiniStartupStatus::Print(const std::string& output) {
- print_.Run(output);
-}
-
-void CrostiniStartupStatus::InitializeProgress() {
- if (progress_initialized_) {
- return;
- }
- progress_initialized_ = true;
- Print(base::StringPrintf("%s%s[%s] ", kCursorHide, kColor5Purple,
- std::string(kMaxStage, ' ').c_str()));
-}
-
-void CrostiniStartupStatus::PrintProgress() {
- InitializeProgress();
- Print(base::StringPrintf("\r%s%s%c", MoveForward(stage_index_).c_str(),
- kColor5Purple, kSpinner[spinner_index_ & 0x3]));
-}
-
-void CrostiniStartupStatus::PrintStage(const char* color,
- const std::string& output) {
- DCHECK_GE(stage_index_, 1);
- InitializeProgress();
- std::string progress(stage_index_ - 1, '=');
- Print(base::StringPrintf("\r%s[%s%s%s%s%s ", kColor5Purple, progress.c_str(),
- MoveForward(3 + (kMaxStage - stage_index_)).c_str(),
- kEraseInLine, color, output.c_str()));
- end_of_line_index_ = 4 + kMaxStage + output.size();
-}
-
-void CrostiniStartupStatus::PrintAfterStage(const char* color,
- const std::string& output) {
- InitializeProgress();
- Print(base::StringPrintf("\r%s%s%s", MoveForward(end_of_line_index_).c_str(),
- color, output.c_str()));
- end_of_line_index_ += output.size();
-}
-
-} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/terminal/crostini_startup_status.h b/chromium/chrome/browser/extensions/api/terminal/crostini_startup_status.h
deleted file mode 100644
index f2a0508b26e..00000000000
--- a/chromium/chrome/browser/extensions/api/terminal/crostini_startup_status.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_API_TERMINAL_CROSTINI_STARTUP_STATUS_H_
-#define CHROME_BROWSER_EXTENSIONS_API_TERMINAL_CROSTINI_STARTUP_STATUS_H_
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/weak_ptr.h"
-#include "base/timer/timer.h"
-#include "chrome/browser/ash/crostini/crostini_manager.h"
-#include "chrome/browser/ash/crostini/crostini_simple_types.h"
-#include "chrome/browser/ash/crostini/crostini_types.mojom.h"
-
-namespace extensions {
-
-// Displays startup status to the crostini terminal.
-class CrostiniStartupStatus
- : public crostini::CrostiniManager::RestartObserver {
- public:
- CrostiniStartupStatus(base::RepeatingCallback<void(const std::string&)> print,
- bool verbose);
- ~CrostiniStartupStatus() override;
-
- // Updates the progress spinner every 300ms.
- void ShowProgressAtInterval();
-
- // Called when startup is complete.
- void OnCrostiniRestarted(crostini::CrostiniResult result);
- void OnCrostiniConnected(crostini::CrostiniResult result);
-
- private:
- FRIEND_TEST_ALL_PREFIXES(CrostiniStartupStatusTest, TestNotVerbose);
- FRIEND_TEST_ALL_PREFIXES(CrostiniStartupStatusTest, TestVerbose);
-
- // crostini::CrostiniManager::RestartObserver
- void OnStageStarted(crostini::mojom::InstallerState stage) override;
- void OnContainerDownloading(int32_t download_percent) override;
-
- void Print(const std::string& output);
- void InitializeProgress();
- void PrintProgress();
- void PrintStage(const char* color, const std::string& output);
- void PrintAfterStage(const char* color, const std::string& output);
-
- base::RepeatingCallback<void(const std::string& output)> print_;
- const bool verbose_;
- bool progress_initialized_ = false;
- int spinner_index_ = 0;
- int stage_index_ = 1;
- int end_of_line_index_ = 0;
- std::unique_ptr<base::RepeatingTimer> show_progress_timer_;
-
- base::WeakPtrFactory<CrostiniStartupStatus> weak_factory_{this};
-};
-
-} // namespace extensions
-
-#endif // CHROME_BROWSER_EXTENSIONS_API_TERMINAL_CROSTINI_STARTUP_STATUS_H_
diff --git a/chromium/chrome/browser/extensions/api/terminal/crostini_startup_status_unittest.cc b/chromium/chrome/browser/extensions/api/terminal/crostini_startup_status_unittest.cc
deleted file mode 100644
index 0ac09539c88..00000000000
--- a/chromium/chrome/browser/extensions/api/terminal/crostini_startup_status_unittest.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/api/terminal/crostini_startup_status.h"
-
-#include <memory>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/metrics/histogram_base.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "chrome/browser/ash/crostini/crostini_simple_types.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using crostini::mojom::InstallerState;
-
-namespace extensions {
-
-class CrostiniStartupStatusTest : public testing::Test {
- protected:
- void Print(const std::string& output) {
- output_.emplace_back(std::move(output));
- }
-
- void Done() { done_ = true; }
-
- std::unique_ptr<CrostiniStartupStatus> NewStartupStatus(bool verbose) {
- return std::make_unique<CrostiniStartupStatus>(
- base::BindRepeating(&CrostiniStartupStatusTest::Print,
- base::Unretained(this)),
- verbose);
- }
-
- std::vector<std::string> output_;
- bool done_ = false;
- base::HistogramTester histogram_tester_{};
-};
-
-TEST_F(CrostiniStartupStatusTest, TestNotVerbose) {
- auto startup_status = NewStartupStatus(false);
- startup_status->OnStageStarted(InstallerState::kStart);
- startup_status->OnStageStarted(InstallerState::kInstallImageLoader);
- startup_status->OnCrostiniRestarted(crostini::CrostiniResult::SUCCESS);
- startup_status->OnCrostiniConnected(crostini::CrostiniResult::SUCCESS);
-
- ASSERT_EQ(output_.size(), 4u);
- // Hide cursor, init progress.
- EXPECT_EQ(output_[0], "\x1b[?25l\x1b[35m[ ] ");
-
- // CR, purple, forward 12, yellow, empty-stage.
- EXPECT_EQ(output_[1], "\r\x1b[35m[\x1b[12C\x1b[K\x1b[33m ");
-
- // CR, purple, progress, forward 11, erase, yellow, empty-stage.
- EXPECT_EQ(output_[2], "\r\x1b[35m[=\x1b[11C\x1b[K\x1b[33m ");
-
- // CR, delete line, default color, show cursor.
- EXPECT_EQ(output_[3], "\r\x1b[K\x1b[0m\x1b[?25h");
-
- histogram_tester_.ExpectBucketCount("Crostini.AppLaunchResult",
- crostini::CrostiniResult::SUCCESS, 1);
- histogram_tester_.ExpectBucketCount("Crostini.AppLaunchResult.Terminal",
- crostini::CrostiniResult::SUCCESS, 1);
-}
-
-TEST_F(CrostiniStartupStatusTest, TestVerbose) {
- auto startup_status = NewStartupStatus(true);
- startup_status->OnStageStarted(InstallerState::kStart);
- startup_status->OnStageStarted(InstallerState::kInstallImageLoader);
- startup_status->OnCrostiniRestarted(crostini::CrostiniResult::SUCCESS);
- startup_status->OnCrostiniConnected(crostini::CrostiniResult::SUCCESS);
-
- ASSERT_EQ(output_.size(), 6u);
- // Hide cursor, init progress.
- EXPECT_EQ(output_[0], "\x1b[?25l\x1b[35m[ ] ");
-
- // CR, purple, forward 12, yellow, stage.
- EXPECT_EQ(output_[1], "\r\x1b[35m[\x1b[12C\x1b[K\x1b[33mInitializing ");
-
- // CR, purple, progress, forward 11, erase, yellow, stage.
- EXPECT_EQ(output_[2],
- "\r\x1b[35m[=\x1b[11C\x1b[K\x1b[33mChecking the virtual machine ");
-
- // CR, purple, progress, forward 11, erase, yellow, container connect
- // pseudo-stage.
- EXPECT_EQ(output_[3],
- "\r\x1B[35m[=\x1B[11C\x1B[K\x1B[33mConnecting to the container ");
-
- // CR, purple, progress, forward 2, erase, green, done, symbol, CRLF.
- EXPECT_EQ(output_[4],
- "\r\x1b[35m[==========\x1b[2C\x1b[K\x1b[1;32mReady\r\n ");
-
- // CR, delete line, default color, show cursor;
- EXPECT_EQ(output_[5], "\r\x1b[K\x1b[0m\x1b[?25h");
-
- histogram_tester_.ExpectBucketCount("Crostini.AppLaunchResult",
- crostini::CrostiniResult::SUCCESS, 1);
- histogram_tester_.ExpectBucketCount("Crostini.AppLaunchResult.Terminal",
- crostini::CrostiniResult::SUCCESS, 1);
-}
-
-TEST_F(CrostiniStartupStatusTest,
- TestNoOutOfBoundsAccessWhenRestartBeforeStageStart) {
- // Repro case for crbug/1214039.
- auto startup_status = NewStartupStatus(true);
- startup_status->OnCrostiniRestarted(crostini::CrostiniResult::SUCCESS);
-
- ASSERT_EQ(output_.size(), 2u);
-}
-
-} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/terminal/startup_status.cc b/chromium/chrome/browser/extensions/api/terminal/startup_status.cc
new file mode 100644
index 00000000000..c4db031b248
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/terminal/startup_status.cc
@@ -0,0 +1,148 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/terminal/startup_status.h"
+#include <unistd.h>
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/strings/strcat.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+namespace {
+
+const char kCursorHide[] = "\x1b[?25l";
+const char kCursorShow[] = "\x1b[?25h";
+const char kColor0Normal[] = "\x1b[0m"; // Default.
+const char kColor1RedBright[] = "\x1b[1;31m";
+const char kColor2GreenBright[] = "\x1b[1;32m";
+const char kColor3Yellow[] = "\x1b[33m";
+const char kColor5Purple[] = "\x1b[35m";
+const char kEraseInLine[] = "\x1b[K";
+const char kSpinnerCharacters[] = "|/-\\";
+
+std::string MoveForward(int i) {
+ return base::StringPrintf("\x1b[%dC", i);
+}
+
+} // namespace
+
+StartupStatusPrinter::StartupStatusPrinter(
+ base::RepeatingCallback<void(const std::string& output)> print,
+ bool verbose)
+ : print_(std::move(print)), verbose_(verbose) {}
+
+StartupStatusPrinter::~StartupStatusPrinter() = default;
+
+// Starts showing the progress indicator.
+void StartupStatusPrinter::StartShowingSpinner() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ show_progress_timer_ = std::make_unique<base::RepeatingTimer>();
+ show_progress_timer_->Start(
+ FROM_HERE, base::Milliseconds(300),
+ base::BindRepeating(&StartupStatusPrinter::PrintProgress,
+ // We own the timer, so this'll never get called after
+ // we're destroyed.
+ base::Unretained(this)));
+}
+
+void StartupStatusPrinter::PrintStageWithColor(int stage_index,
+ const char* color,
+ const std::string& stage_name) {
+ DCHECK_GE(stage_index_, 0);
+ DCHECK_LE(stage_index_, max_stage_);
+ InitializeProgress();
+ stage_index_ = stage_index;
+ auto output = verbose_ ? stage_name : "";
+ std::string progress(stage_index_, '=');
+ std::string padding(max_stage_ - stage_index_, ' ');
+ Print(base::StringPrintf("\r%s[%s%s] %s%s%s ", kColor5Purple,
+ progress.c_str(), padding.c_str(), kEraseInLine,
+ color, output.c_str()));
+ end_of_line_index_ = 4 + max_stage_ + output.size();
+}
+
+void StartupStatusPrinter::PrintStage(int stage_index,
+ const std::string& stage_name) {
+ PrintStageWithColor(stage_index, kColor3Yellow, stage_name);
+}
+
+void StartupStatusPrinter::PrintError(const std::string& output) {
+ InitializeProgress();
+ Print(base::StringPrintf("\r%s%s%s", MoveForward(end_of_line_index_).c_str(),
+ kColor1RedBright, output.c_str()));
+ end_of_line_index_ += output.size();
+ Print(
+ base::StringPrintf("\r%s%s%s", kEraseInLine, kColor0Normal, kCursorShow));
+}
+
+void StartupStatusPrinter::PrintSucceeded() {
+ InitializeProgress();
+ if (verbose_) {
+ auto output = base::StrCat(
+ {l10n_util::GetStringUTF8(IDS_CROSTINI_TERMINAL_STATUS_READY), "\r\n"});
+ PrintStageWithColor(max_stage_, kColor2GreenBright, output);
+ }
+ Print(
+ base::StringPrintf("\r%s%s%s", kEraseInLine, kColor0Normal, kCursorShow));
+}
+
+void StartupStatusPrinter::Print(const std::string& output) {
+ print_.Run(output);
+}
+
+void StartupStatusPrinter::InitializeProgress() {
+ if (progress_initialized_) {
+ return;
+ }
+ progress_initialized_ = true;
+ Print(base::StringPrintf("%s%s[%s] ", kCursorHide, kColor5Purple,
+ std::string(max_stage_, ' ').c_str()));
+}
+
+void StartupStatusPrinter::PrintProgress() {
+ InitializeProgress();
+ spinner_index_++;
+ Print(base::StringPrintf("\r%s%s%c", MoveForward(stage_index_).c_str(),
+ kColor5Purple,
+ kSpinnerCharacters[spinner_index_ & 0x3]));
+}
+
+StartupStatus::StartupStatus(std::unique_ptr<StartupStatusPrinter> printer,
+ int max_stage)
+ : printer_(std::move(printer)), max_stage_(max_stage) {
+ printer_->set_max_stage(max_stage);
+}
+
+StartupStatus::~StartupStatus() = default;
+
+void StartupStatus::OnConnectingToVsh() {
+ const std::string& stage_string =
+ l10n_util::GetStringUTF8(IDS_CROSTINI_TERMINAL_STATUS_CONNECT_CONTAINER);
+ printer()->PrintStage(max_stage_, stage_string);
+}
+void StartupStatus::StartShowingSpinner() {
+ printer()->StartShowingSpinner();
+}
+
+void StartupStatus::OnFinished(bool success,
+ const std::string& failure_reason) {
+ if (success) {
+ printer()->PrintSucceeded();
+ } else {
+ printer()->PrintError(failure_reason);
+ }
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/terminal/startup_status.h b/chromium/chrome/browser/extensions/api/terminal/startup_status.h
new file mode 100644
index 00000000000..52135498637
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/terminal/startup_status.h
@@ -0,0 +1,83 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_TERMINAL_STARTUP_STATUS_H_
+#define CHROME_BROWSER_EXTENSIONS_API_TERMINAL_STARTUP_STATUS_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+
+namespace extensions {
+
+class StartupStatusPrinter {
+ public:
+ explicit StartupStatusPrinter(
+ base::RepeatingCallback<void(const std::string& output)> print,
+ bool verbose);
+ ~StartupStatusPrinter();
+
+ // Starts showing the progress indicator.
+ void StartShowingSpinner();
+
+ // Updates the output for a new stage named `stage_name` and number
+ // `stage_index`. If `succeeded` is true, indicates that the last stage has
+ // completed successfully and we're now in the end-state.
+ void PrintStage(int stage_index, const std::string& stage_name);
+
+ // Displays an error message to the user.
+ void PrintError(const std::string& output);
+
+ // Displays a successful connection message to the user.
+ void PrintSucceeded();
+
+ // Sets the max stage number.
+ void set_max_stage(int max_stage) {
+ DCHECK(!progress_initialized_);
+ max_stage_ = max_stage;
+ }
+
+ base::WeakPtr<StartupStatusPrinter> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
+
+ private:
+ void Print(const std::string& output);
+ void InitializeProgress();
+ void PrintProgress();
+ void PrintStageWithColor(int stage_index,
+ const char* color,
+ const std::string& stage_name);
+
+ base::RepeatingCallback<void(const std::string& output)> print_;
+ const bool verbose_;
+ bool progress_initialized_ = false;
+ int spinner_index_ = 0;
+ int stage_index_ = 1;
+ int end_of_line_index_ = 0;
+ int max_stage_ = -1;
+ std::unique_ptr<base::RepeatingTimer> show_progress_timer_;
+ base::WeakPtrFactory<StartupStatusPrinter> weak_factory_{this};
+};
+
+class StartupStatus {
+ public:
+ explicit StartupStatus(std::unique_ptr<StartupStatusPrinter> printer,
+ int max_stage);
+ virtual ~StartupStatus();
+ void OnConnectingToVsh();
+ void OnFinished(bool success, const std::string& failure_reason);
+ void StartShowingSpinner();
+ StartupStatusPrinter* printer() { return printer_.get(); }
+
+ private:
+ std::unique_ptr<StartupStatusPrinter> printer_;
+ const int max_stage_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_TERMINAL_STARTUP_STATUS_H_
diff --git a/chromium/chrome/browser/extensions/api/terminal/startup_status_unittest.cc b/chromium/chrome/browser/extensions/api/terminal/startup_status_unittest.cc
new file mode 100644
index 00000000000..621b828d7de
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/terminal/startup_status_unittest.cc
@@ -0,0 +1,105 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/terminal/startup_status.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+class StartupStatusTest : public testing::Test {
+ protected:
+ void Print(const std::string& output) {
+ output_.emplace_back(std::move(output));
+ }
+
+ std::unique_ptr<StartupStatusPrinter> NewStatusPrinter(bool verbose) {
+ return std::make_unique<StartupStatusPrinter>(
+ base::BindRepeating(&StartupStatusTest::Print, base::Unretained(this)),
+ verbose);
+ }
+
+ std::vector<std::string> output_;
+};
+
+TEST_F(StartupStatusTest, TestNotVerbose) {
+ auto status_printer = NewStatusPrinter(false);
+ status_printer->set_max_stage(10);
+ status_printer->PrintStage(0, "Starting Stage");
+ status_printer->PrintStage(2, "Second Stage");
+ status_printer->PrintStage(10, "Last Stage");
+ status_printer->PrintSucceeded();
+
+ ASSERT_EQ(output_.size(), 5);
+
+ // Hide cursor, init progress.
+ EXPECT_EQ(output_[0], "\x1b[?25l\x1b[35m[ ] ");
+
+ // CR, purple, progress, erase-right, yellow, empty-stage.
+ EXPECT_EQ(output_[1], "\r\x1b[35m[ ] \x1b[K\x1b[33m ");
+
+ // CR, purple, progress, erase-right, yellow, empty-stage.
+ EXPECT_EQ(output_[2], "\r\x1b[35m[== ] \x1b[K\x1b[33m ");
+
+ // CR, purple, progress, erase-right, yellow, empty-stage.
+ EXPECT_EQ(output_[3], "\r\x1b[35m[==========] \x1b[K\x1b[33m ");
+
+ // CR, erase-right, default color, show cursor.
+ EXPECT_EQ(output_[4], "\r\x1b[K\x1b[0m\x1b[?25h");
+}
+
+TEST_F(StartupStatusTest, TestVerbose) {
+ auto status_printer = NewStatusPrinter(true);
+ status_printer->set_max_stage(10);
+ status_printer->PrintStage(0, "Starting Stage");
+ status_printer->PrintStage(2, "Second Stage");
+ status_printer->PrintStage(10, "Last Stage");
+ status_printer->PrintSucceeded();
+
+ ASSERT_EQ(output_.size(), 6);
+
+ // Hide cursor, init progress.
+ EXPECT_EQ(output_[0], "\x1b[?25l\x1b[35m[ ] ");
+
+ // CR, purple, progress, erase-right, yellow, stage.
+ EXPECT_EQ(output_[1], "\r\x1b[35m[ ] \x1b[K\x1b[33mStarting Stage ");
+
+ // CR, purple, progress, erase-right, yellow, stage.
+ EXPECT_EQ(output_[2], "\r\x1b[35m[== ] \x1b[K\x1b[33mSecond Stage ");
+
+ // CR, purple, progress, erase-right, yellow, stage.
+ EXPECT_EQ(output_[3], "\r\x1b[35m[==========] \x1b[K\x1b[33mLast Stage ");
+
+ // CR, purple, progress, erase-right, yellow, stage.
+ EXPECT_EQ(output_[4], "\r\x1b[35m[==========] \x1b[K\x1b[1;32mReady\r\n ");
+
+ // CR, erase-right, default color, show cursor.
+ EXPECT_EQ(output_[5], "\r\x1b[K\x1b[0m\x1b[?25h");
+}
+
+TEST_F(StartupStatusTest, TestError) {
+ auto status_printer = NewStatusPrinter(false);
+ status_printer->set_max_stage(10);
+ status_printer->PrintStage(1, "First Stage");
+ status_printer->PrintError("Error message"); // Prints two things.
+
+ ASSERT_EQ(output_.size(), 4);
+
+ // Hide cursor, init progress.
+ EXPECT_EQ(output_[0], "\x1b[?25l\x1b[35m[ ] ");
+ // CR, purple, progress, erase-right, yellow, stage.
+ EXPECT_EQ(output_[1], "\r\x1b[35m[= ] \x1b[K\x1b[33m ");
+
+ // CR, Move forward 14 characters, red, error message.
+ EXPECT_EQ(output_[2], "\r\x1b[14C\x1b[1;31mError message");
+
+ // CR, erase-right, default color, show cursor.
+ EXPECT_EQ(output_[3], "\r\x1b[K\x1b[0m\x1b[?25h");
+}
+
+} // namespace extensions
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 9a769941b6b..46d4aa2bedc 100644
--- a/chromium/chrome/browser/extensions/api/terminal/terminal_private_api.cc
+++ b/chromium/chrome/browser/extensions/api/terminal/terminal_private_api.cc
@@ -28,13 +28,19 @@
#include "base/system/sys_info.h"
#include "base/task/task_runner_util.h"
#include "base/values.h"
-#include "chrome/browser/ash/crostini/crostini_features.h"
-#include "chrome/browser/ash/crostini/crostini_manager.h"
#include "chrome/browser/ash/crostini/crostini_pref_names.h"
-#include "chrome/browser/ash/crostini/crostini_terminal.h"
#include "chrome/browser/ash/crostini/crostini_util.h"
+#include "chrome/browser/ash/guest_os/guest_id.h"
+#include "chrome/browser/ash/guest_os/guest_os_pref_names.h"
+#include "chrome/browser/ash/guest_os/guest_os_session_tracker.h"
+#include "chrome/browser/ash/guest_os/guest_os_terminal.h"
+#include "chrome/browser/ash/guest_os/public/guest_os_service.h"
+#include "chrome/browser/ash/guest_os/public/guest_os_terminal_provider.h"
+#include "chrome/browser/ash/guest_os/public/guest_os_terminal_provider_registry.h"
+#include "chrome/browser/ash/guest_os/public/types.h"
+#include "chrome/browser/ash/guest_os/virtual_machines/virtual_machines_util.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/api/terminal/crostini_startup_status.h"
+#include "chrome/browser/extensions/api/terminal/startup_status.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/policy/system_features_disable_list_policy_handler.h"
@@ -45,6 +51,7 @@
#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"
#include "chromeos/process_proxy/process_proxy_registry.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_context.h"
@@ -73,8 +80,6 @@ namespace OpenWindow = extensions::api::terminal_private::OpenWindow;
namespace GetPrefs = extensions::api::terminal_private::GetPrefs;
namespace SetPrefs = extensions::api::terminal_private::SetPrefs;
-using crostini::mojom::InstallerState;
-
namespace {
const char kCroshName[] = "crosh";
@@ -90,16 +95,17 @@ const char kSwitchVmName[] = "vm_name";
const char kSwitchTargetContainer[] = "target_container";
const char kSwitchStartupId[] = "startup_id";
const char kSwitchCurrentWorkingDir[] = "cwd";
+const char kSwitchContainerFeatures[] = "container_features";
const char kCwdTerminalIdPrefix[] = "terminal_id:";
// Prefs that we read and observe.
static const base::NoDestructor<std::vector<std::string>> kPrefsReadAllowList{{
ash::prefs::kAccessibilitySpokenFeedbackEnabled,
- crostini::prefs::kCrostiniContainers,
crostini::prefs::kCrostiniEnabled,
- crostini::prefs::kCrostiniTerminalSettings,
+ guest_os::prefs::kGuestOsTerminalSettings,
crostini::prefs::kTerminalSshAllowedByPolicy,
+ guest_os::prefs::kGuestOsContainers,
}};
void CloseTerminal(const std::string& terminal_id,
@@ -178,6 +184,19 @@ std::string GetSwitch(const base::CommandLine& src,
return result;
}
+std::string GetContainerFeaturesArg() {
+ std::string result;
+ // There are only a few available features so concatenating strings is
+ // sufficient.
+ for (vm_tools::cicerone::ContainerFeature feature :
+ crostini::GetContainerFeatures()) {
+ if (!result.empty())
+ result += ",";
+ result += base::NumberToString(static_cast<int>(feature));
+ }
+ return result;
+}
+
void NotifyProcessOutput(content::BrowserContext* browser_context,
const std::string& terminal_id,
const std::string& output_type,
@@ -189,10 +208,10 @@ void NotifyProcessOutput(content::BrowserContext* browser_context,
return;
}
- std::vector<base::Value> args;
- args.push_back(base::Value(terminal_id));
- args.push_back(base::Value(output_type));
- args.push_back(base::Value(base::make_span(
+ base::Value::List args;
+ args.Append(terminal_id);
+ args.Append(output_type);
+ args.Append(base::Value(base::make_span(
reinterpret_cast<const uint8_t*>(&output[0]), output.size())));
extensions::EventRouter* event_router =
@@ -210,10 +229,10 @@ void PrefChanged(Profile* profile, const std::string& pref_name) {
if (!event_router) {
return;
}
- std::vector<base::Value> args;
+ base::Value::List args;
base::Value prefs(base::Value::Type::DICTIONARY);
- prefs.SetKey(pref_name, profile->GetPrefs()->Get(pref_name)->Clone());
- args.push_back(std::move(prefs));
+ prefs.SetKey(pref_name, profile->GetPrefs()->GetValue(pref_name).Clone());
+ args.Append(std::move(prefs));
auto event = std::make_unique<extensions::Event>(
extensions::events::TERMINAL_PRIVATE_ON_PREF_CHANGED,
terminal_private::OnPrefChanged::kEventName, std::move(args));
@@ -296,11 +315,10 @@ TerminalPrivateOpenTerminalProcessFunction::OpenProcess(
base::CommandLine(base::FilePath(kStubbedCroshCommand)));
}
} else if (process_name == kVmShellName) {
- // Ensure crostini is allowed before starting terminal.
- Profile* profile = Profile::FromBrowserContext(browser_context());
- if (!crostini::CrostiniFeatures::Get()->IsAllowedNow(profile))
+ // Ensure vms are allowed before starting terminal.
+ if (!virtual_machines::AreVirtualMachinesAllowedByPolicy()) {
return RespondNow(Error("vmshell not allowed"));
-
+ }
// command=vmshell: ensure --owner_id, --vm_name, --target_container, --cwd
// are set, and the specified vm/container is running.
base::CommandLine cmdline((base::FilePath(kVmShellCommand)));
@@ -314,29 +332,57 @@ TerminalPrivateOpenTerminalProcessFunction::OpenProcess(
std::string vm_name = GetSwitch(params_args, &cmdline, kSwitchVmName,
crostini::kCrostiniDefaultVmName);
std::string container_name =
- GetSwitch(params_args, &cmdline, kSwitchTargetContainer,
- crostini::kCrostiniDefaultContainerName);
+ GetSwitch(params_args, &cmdline, kSwitchTargetContainer, "");
GetSwitch(params_args, &cmdline, kSwitchCurrentWorkingDir, "");
std::string startup_id = params_args.GetSwitchValueASCII(kSwitchStartupId);
- container_id_ =
- std::make_unique<crostini::ContainerId>(vm_name, container_name);
- VLOG(1) << "Starting " << *container_id_
+ guest_id_ = std::make_unique<guest_os::GuestId>(guest_os::VmType::UNKNOWN,
+ vm_name, container_name);
+
+ // Unlike the other switches, this is computed here directly rather than
+ // taken from |args|.
+ std::string container_features = GetContainerFeaturesArg();
+ if (!container_features.empty())
+ cmdline.AppendSwitchASCII(kSwitchContainerFeatures, container_features);
+
+ VLOG(1) << "Starting " << *guest_id_
<< ", cmdline=" << cmdline.GetCommandLineString();
- auto* mgr = crostini::CrostiniManager::GetForProfile(profile);
- bool verbose = !mgr->GetContainerInfo(*container_id_).has_value();
- startup_status_ = std::make_unique<CrostiniStartupStatus>(
+ Profile* profile = Profile::FromBrowserContext(browser_context());
+ auto* service = guest_os::GuestOsService::GetForProfile(profile);
+ guest_os::GuestOsTerminalProvider* provider = nullptr;
+ if (service) {
+ provider = service->TerminalProviderRegistry()->Get(*guest_id_);
+ }
+ auto* tracker = guest_os::GuestOsSessionTracker::GetForProfile(profile);
+ bool verbose = !(tracker && tracker->GetInfo(*guest_id_).has_value());
+ auto status_printer = std::make_unique<StartupStatusPrinter>(
base::BindRepeating(&NotifyProcessOutput, browser_context(), startup_id,
api::terminal_private::ToString(
api::terminal_private::OUTPUT_TYPE_STDOUT)),
verbose);
- startup_status_->ShowProgressAtInterval();
- mgr->RestartCrostini(
- *container_id_,
- base::BindOnce(
- &TerminalPrivateOpenTerminalProcessFunction::OnCrostiniRestarted,
- this, user_id_hash, std::move(cmdline)),
- startup_status_.get());
+ if (provider) {
+ startup_status_ =
+ provider->CreateStartupStatus(std::move(status_printer));
+ startup_status_->StartShowingSpinner();
+ provider->EnsureRunning(
+ startup_status_.get(),
+ base::BindOnce(
+ &TerminalPrivateOpenTerminalProcessFunction::OnGuestRunning, this,
+ user_id_hash, std::move(cmdline)));
+ } else {
+ // Don't recognise the guest. Options include:
+ // * It doesn't exist but the terminal app thinks it does e.g. out-of-sync
+ // prefs, race between uninstalling and launching terminal.
+ // * We're installing Bruschetta, and it's using the terminal to finish
+ // installing. We don't show Bruschetta until it's installed, but it's
+ // running and users need to connect to it.
+ // Given this, try and connect directly to it, if it succeeds, great, if
+ // it fails, then report failure to the user.
+ startup_status_ =
+ std::make_unique<StartupStatus>(std::move(status_printer), 2);
+ startup_status_->StartShowingSpinner();
+ OpenVmshellProcess(user_id_hash, std::move(cmdline));
+ }
} else {
// command=[unrecognized].
return RespondNow(Error("Invalid process name: " + process_name));
@@ -344,25 +390,24 @@ TerminalPrivateOpenTerminalProcessFunction::OpenProcess(
return RespondLater();
}
-void TerminalPrivateOpenTerminalProcessFunction::OnCrostiniRestarted(
+void TerminalPrivateOpenTerminalProcessFunction::OnGuestRunning(
const std::string& user_id_hash,
base::CommandLine cmdline,
- crostini::CrostiniResult result) {
- startup_status_->OnCrostiniRestarted(result);
- if (result == crostini::CrostiniResult::SUCCESS) {
+ bool success,
+ std::string failure_reason) {
+ if (success) {
OpenVmshellProcess(user_id_hash, std::move(cmdline));
} else {
- const std::string msg =
- base::StringPrintf("Error starting crostini for terminal: %d (%s)",
- result, CrostiniResultString(result));
- LOG(ERROR) << msg;
- Respond(Error(msg));
+ startup_status_->OnFinished(success, failure_reason);
+ LOG(ERROR) << failure_reason;
+ Respond(Error(failure_reason));
}
}
void TerminalPrivateOpenTerminalProcessFunction::OpenVmshellProcess(
const std::string& user_id_hash,
base::CommandLine cmdline) {
+ startup_status_->OnConnectingToVsh();
const std::string cwd = cmdline.GetSwitchValueASCII(kSwitchCurrentWorkingDir);
if (!base::StartsWith(cwd, kCwdTerminalIdPrefix)) {
@@ -376,28 +421,31 @@ void TerminalPrivateOpenTerminalProcessFunction::OpenVmshellProcess(
cwd.substr(sizeof(kCwdTerminalIdPrefix) - 1));
// Lookup container shell pid from cicierone to use for cwd.
- crostini::CrostiniManager::GetForProfile(
- Profile::FromBrowserContext(browser_context()))
- ->GetVshSession(
- *container_id_, host_pid,
- base::BindOnce(
- &TerminalPrivateOpenTerminalProcessFunction::OnGetVshSession,
- this, user_id_hash, std::move(cmdline), /*terminal_id=*/cwd));
+ vm_tools::cicerone::GetVshSessionRequest request;
+ request.set_vm_name(guest_id_->vm_name);
+ request.set_container_name(guest_id_->container_name);
+ request.set_owner_id(crostini::CryptohomeIdForProfile(
+ Profile::FromBrowserContext(browser_context())));
+ request.set_host_vsh_pid(host_pid);
+ ash::CiceroneClient::Get()->GetVshSession(
+ request,
+ base::BindOnce(
+ &TerminalPrivateOpenTerminalProcessFunction::OnGetVshSession, this,
+ user_id_hash, std::move(cmdline), /*terminal_id=*/cwd));
}
void TerminalPrivateOpenTerminalProcessFunction::OnGetVshSession(
const std::string& user_id_hash,
base::CommandLine cmdline,
const std::string& terminal_id,
- bool success,
- const std::string& failure_reason,
- int32_t container_shell_pid) {
- if (!success) {
- LOG(WARNING) << "Failed to get vsh session for " << terminal_id << ". "
- << failure_reason;
+ absl::optional<vm_tools::cicerone::GetVshSessionResponse> response) {
+ if (!response || !response->success()) {
+ LOG(WARNING) << "Failed to get vsh session for " << terminal_id << ": "
+ << (response ? response->failure_reason() : "empty response");
} else {
- cmdline.AppendSwitchASCII(kSwitchCurrentWorkingDir,
- base::NumberToString(container_shell_pid));
+ cmdline.AppendSwitchASCII(
+ kSwitchCurrentWorkingDir,
+ base::NumberToString(response->container_shell_pid()));
}
OpenProcess(user_id_hash, std::move(cmdline));
}
@@ -438,9 +486,8 @@ void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(
bool success,
const std::string& terminal_id) {
if (startup_status_) {
- startup_status_->OnCrostiniConnected(
- success ? crostini::CrostiniResult::SUCCESS
- : crostini::CrostiniResult::VSH_CONNECT_FAILED);
+ startup_status_->OnFinished(
+ success, success ? "" : "Error connecting shell to guest");
}
auto* contents = GetSenderWebContents();
if (!contents) {
@@ -508,9 +555,12 @@ ExtensionFunction::ResponseAction TerminalPrivateSendInputFunction::Run() {
void TerminalPrivateSendInputFunction::SendInputOnRegistryTaskRunner(
const std::string& terminal_id,
const std::string& text) {
- bool success =
- chromeos::ProcessProxyRegistry::Get()->SendInput(terminal_id, text);
+ chromeos::ProcessProxyRegistry::Get()->SendInput(
+ terminal_id, text,
+ base::BindOnce(&TerminalPrivateSendInputFunction::OnSendInput, this));
+}
+void TerminalPrivateSendInputFunction::OnSendInput(bool success) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&TerminalPrivateSendInputFunction::RespondOnUIThread, this,
@@ -629,7 +679,7 @@ ExtensionFunction::ResponseAction TerminalPrivateOpenWindowFunction::Run() {
OpenWindow::Params::Create(args()));
EXTENSION_FUNCTION_VALIDATE(params.get());
- const std::string* url = &crostini::GetTerminalHomeUrl();
+ const std::string* url = &guest_os::GetTerminalHomeUrl();
bool as_tab = false;
auto& data = params->data;
@@ -650,7 +700,7 @@ ExtensionFunction::ResponseAction TerminalPrivateOpenWindowFunction::Run() {
LOG(ERROR) << "cannot find the browser";
}
} else {
- crostini::LaunchTerminalWithUrl(
+ guest_os::LaunchTerminalWithUrl(
Profile::FromBrowserContext(browser_context()),
display::kInvalidDisplayId, GURL(*url));
}
@@ -663,7 +713,7 @@ TerminalPrivateOpenOptionsPageFunction::
ExtensionFunction::ResponseAction
TerminalPrivateOpenOptionsPageFunction::Run() {
- crostini::LaunchTerminalSettings(
+ guest_os::LaunchTerminalSettings(
Profile::FromBrowserContext(browser_context()));
return RespondNow(NoArguments());
}
@@ -684,6 +734,9 @@ TerminalPrivateGetOSInfoFunction::~TerminalPrivateGetOSInfoFunction() = default;
ExtensionFunction::ResponseAction TerminalPrivateGetOSInfoFunction::Run() {
base::DictionaryValue info;
+ info.SetBoolKey("alternative_emulator",
+ base::FeatureList::IsEnabled(
+ chromeos::features::kTerminalAlternativeEmulator));
info.SetBoolKey(
"multi_profile",
base::FeatureList::IsEnabled(chromeos::features::kTerminalMultiProfile));
@@ -708,11 +761,11 @@ ExtensionFunction::ResponseAction TerminalPrivateGetPrefsFunction::Run() {
LOG(WARNING) << "Ignoring non-allowed GetPrefs path=" << path;
continue;
}
- if (path == crostini::prefs::kCrostiniTerminalSettings) {
- crostini::RecordTerminalSettingsChangesUMAs(
+ if (path == guest_os::prefs::kGuestOsTerminalSettings) {
+ guest_os::RecordTerminalSettingsChangesUMAs(
Profile::FromBrowserContext(browser_context()));
}
- result.SetKey(path, service->Get(path)->Clone());
+ result.SetKey(path, service->GetValue(path).Clone());
}
return RespondNow(OneArgument(std::move(result)));
}
@@ -728,7 +781,7 @@ ExtensionFunction::ResponseAction TerminalPrivateSetPrefsFunction::Run() {
static const base::NoDestructor<
base::flat_map<std::string, base::Value::Type>>
- kAllowList{{{crostini::prefs::kCrostiniTerminalSettings,
+ kAllowList{{{guest_os::prefs::kGuestOsTerminalSettings,
base::Value::Type::DICTIONARY}}};
for (base::DictionaryValue::Iterator it(params->prefs.additional_properties);
diff --git a/chromium/chrome/browser/extensions/api/terminal/terminal_private_api.h b/chromium/chrome/browser/extensions/api/terminal/terminal_private_api.h
index fe9a26253d8..d23d3626b84 100644
--- a/chromium/chrome/browser/extensions/api/terminal/terminal_private_api.h
+++ b/chromium/chrome/browser/extensions/api/terminal/terminal_private_api.h
@@ -9,21 +9,20 @@
#include <string>
#include <vector>
-#include "chrome/browser/ash/crostini/crostini_simple_types.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/value_store/value_store.h"
+#include "chromeos/ash/components/dbus/cicerone/cicerone_service.pb.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/extension_function.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
class PrefChangeRegistrar;
-namespace crostini {
-struct ContainerId;
-} // namespace crostini
+namespace guest_os {
+struct GuestId;
+} // namespace guest_os
namespace extensions {
-class CrostiniStartupStatus;
+class StartupStatus;
class TerminalPrivateAPI : public BrowserContextKeyedAPI {
public:
@@ -66,20 +65,19 @@ class TerminalPrivateOpenTerminalProcessFunction : public ExtensionFunction {
std::unique_ptr<std::vector<std::string>> args);
private:
- void OnCrostiniRestarted(
- const std::string& user_id_hash,
- base::CommandLine cmdline,
- crostini::CrostiniResult result);
+ void OnGuestRunning(const std::string& user_id_hash,
+ base::CommandLine cmdline,
+ bool success,
+ std::string failure_reason);
void OpenVmshellProcess(const std::string& user_id_hash,
base::CommandLine cmdline);
- void OnGetVshSession(const std::string& user_id_hash,
- base::CommandLine cmdline,
- const std::string& terminal_id,
- bool success,
- const std::string& failure_reason,
- int32_t container_shell_pid);
+ void OnGetVshSession(
+ const std::string& user_id_hash,
+ base::CommandLine cmdline,
+ const std::string& terminal_id,
+ absl::optional<vm_tools::cicerone::GetVshSessionResponse>);
void OpenProcess(const std::string& user_id_hash,
base::CommandLine cmdline);
@@ -95,8 +93,8 @@ class TerminalPrivateOpenTerminalProcessFunction : public ExtensionFunction {
base::CommandLine cmdline,
const std::string& user_id_hash);
void RespondOnUIThread(bool success, const std::string& terminal_id);
- std::unique_ptr<CrostiniStartupStatus> startup_status_;
- std::unique_ptr<crostini::ContainerId> container_id_;
+ std::unique_ptr<StartupStatus> startup_status_;
+ std::unique_ptr<guest_os::GuestId> guest_id_;
};
// Opens new vmshell process. Returns the new terminal id.
@@ -127,6 +125,7 @@ class TerminalPrivateSendInputFunction : public ExtensionFunction {
private:
void SendInputOnRegistryTaskRunner(const std::string& terminal_id,
const std::string& input);
+ void OnSendInput(bool success);
void RespondOnUIThread(bool success);
};
diff --git a/chromium/chrome/browser/extensions/api/terminal/terminal_private_apitest.cc b/chromium/chrome/browser/extensions/api/terminal/terminal_private_apitest.cc
index af66bd0a738..7a50f0a4a55 100644
--- a/chromium/chrome/browser/extensions/api/terminal/terminal_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/terminal/terminal_private_apitest.cc
@@ -70,8 +70,8 @@ class CatProcess {
chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
- chromeos::ProcessProxyRegistry::Get()->SendInput(this->process_id_,
- data);
+ chromeos::ProcessProxyRegistry::Get()->SendInput(
+ this->process_id_, data, base::DoNothing());
}));
run_loop.Run();
diff --git a/chromium/chrome/browser/extensions/api/terminal/terminal_private_browsertest.cc b/chromium/chrome/browser/extensions/api/terminal/terminal_private_browsertest.cc
index 979c64d1450..d643c3b7309 100644
--- a/chromium/chrome/browser/extensions/api/terminal/terminal_private_browsertest.cc
+++ b/chromium/chrome/browser/extensions/api/terminal/terminal_private_browsertest.cc
@@ -4,8 +4,11 @@
#include <memory>
+#include "ash/components/settings/cros_settings_names.h"
#include "chrome/browser/ash/crostini/crostini_browser_test_util.h"
#include "chrome/browser/ash/crostini/fake_crostini_features.h"
+#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
+#include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/policy/system_features_disable_list_policy_handler.h"
#include "chrome/browser/ui/browser.h"
@@ -39,6 +42,7 @@ class TerminalPrivateBrowserTest : public CrostiniBrowserTestBase {
/*world_id=*/1);
EXPECT_EQ(eval_result.value.GetString(), expected);
}
+ ash::ScopedTestingCrosSettings cros_settings_;
};
IN_PROC_BROWSER_TEST_F(TerminalPrivateBrowserTest, OpenTerminalProcessChecks) {
@@ -51,12 +55,13 @@ IN_PROC_BROWSER_TEST_F(TerminalPrivateBrowserTest, OpenTerminalProcessChecks) {
resolve(lastError ? lastError.message : "success");
})}))";
- // 'vmshell not allowed' when crostini is not allowed.
- fake_crostini_features_.set_could_be_allowed(true);
- fake_crostini_features_.set_is_allowed_now(false);
+ // 'vmshell not allowed' when VMs are not allowed.
+ cros_settings_.device_settings()->SetBoolean(ash::kVirtualMachinesAllowed,
+ false);
ExpectJsResult(script, "vmshell not allowed");
- fake_crostini_features_.set_is_allowed_now(true);
+ cros_settings_.device_settings()->SetBoolean(ash::kVirtualMachinesAllowed,
+ true);
ExpectJsResult(script, "success");
// openTerminalProcess not defined.
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 e7409cc8c60..d2944efa889 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
@@ -14,6 +14,7 @@
#include "ash/public/cpp/keyboard/keyboard_switches.h"
#include "ash/public/cpp/keyboard/keyboard_types.h"
#include "base/bind.h"
+#include "base/check.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
@@ -527,15 +528,15 @@ void ChromeVirtualKeyboardDelegate::OnHasInputDevices(
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto* keyboard_client = ChromeKeyboardControllerClient::Get();
- std::unique_ptr<base::DictionaryValue> results(new base::DictionaryValue());
- results->SetStringKey("layout", GetKeyboardLayout());
+ base::Value::Dict results;
+ results.Set("layout", GetKeyboardLayout());
// TODO(bshe): Consolidate a11y, hotrod and normal mode into a mode enum. See
// crbug.com/529474.
- results->SetBoolKey("a11ymode",
- keyboard_client->IsEnableFlagSet(
- keyboard::KeyboardEnableFlag::kAccessibilityEnabled));
- results->SetBoolKey("hotrodmode", g_hotrod_keyboard_enabled);
+ results.Set("a11ymode",
+ keyboard_client->IsEnableFlagSet(
+ keyboard::KeyboardEnableFlag::kAccessibilityEnabled));
+ results.Set("hotrodmode", g_hotrod_keyboard_enabled);
base::Value features(base::Value::Type::LIST);
keyboard::KeyboardConfig config = keyboard_client->GetKeyboardConfig();
@@ -577,8 +578,8 @@ void ChromeVirtualKeyboardDelegate::OnHasInputDevices(
"borderedkey", base::FeatureList::IsEnabled(
chromeos::features::kVirtualKeyboardBorderedKey)));
features.Append(GenerateFeatureFlag(
- "multitouch",
- base::FeatureList::IsEnabled(features::kVirtualKeyboardMultitouch)));
+ "multitouch", base::FeatureList::IsEnabled(
+ chromeos::features::kVirtualKeyboardMultitouch)));
features.Append(GenerateFeatureFlag(
"roundCorners", base::FeatureList::IsEnabled(
chromeos::features::kVirtualKeyboardRoundCorners)));
@@ -597,32 +598,38 @@ void ChromeVirtualKeyboardDelegate::OnHasInputDevices(
GenerateFeatureFlag("autocorrectparamstuning",
base::FeatureList::IsEnabled(
chromeos::features::kAutocorrectParamsTuning)));
+ features.Append(
+ GenerateFeatureFlag("handwritinglibrarydlc",
+ base::FeatureList::IsEnabled(
+ chromeos::features::kHandwritingLibraryDlc)));
- results->SetKey("features", std::move(features));
+ results.Set("features", std::move(features));
std::move(on_settings_callback).Run(std::move(results));
}
void ChromeVirtualKeyboardDelegate::DispatchConfigChangeEvent(
- std::unique_ptr<base::DictionaryValue> settings) {
+ absl::optional<base::Value::Dict> settings) {
+ DCHECK(settings);
+
EventRouter* router = GetRouterForEventName(
browser_context_, keyboard_api::OnKeyboardConfigChanged::kEventName);
if (!router)
return;
- auto event_args = std::make_unique<base::ListValue>();
- event_args->Append(base::Value::FromUniquePtrValue(std::move(settings)));
+ base::Value::List event_args;
+ event_args.Append(base::Value(std::move(*settings)));
auto event = std::make_unique<extensions::Event>(
extensions::events::VIRTUAL_KEYBOARD_PRIVATE_ON_KEYBOARD_CONFIG_CHANGED,
- keyboard_api::OnKeyboardConfigChanged::kEventName,
- std::move(*event_args).TakeListDeprecated(), browser_context_);
+ keyboard_api::OnKeyboardConfigChanged::kEventName, std::move(event_args),
+ browser_context_);
router->BroadcastEvent(std::move(event));
}
-api::virtual_keyboard::FeatureRestrictions
-ChromeVirtualKeyboardDelegate::RestrictFeatures(
- const api::virtual_keyboard::RestrictFeatures::Params& params) {
+void ChromeVirtualKeyboardDelegate::RestrictFeatures(
+ const api::virtual_keyboard::RestrictFeatures::Params& params,
+ OnRestrictFeaturesCallback callback) {
const api::virtual_keyboard::FeatureRestrictions& restrictions =
params.restrictions;
api::virtual_keyboard::FeatureRestrictions update;
@@ -669,7 +676,7 @@ ChromeVirtualKeyboardDelegate::RestrictFeatures(
// Keeping this unnecessary reload for now, just to avoid behaviour changes.
ChromeKeyboardControllerClient::Get()->RebuildKeyboardIfEnabled();
}
- return update;
+ std::move(callback).Run(std::move(update));
}
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h b/chromium/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h
index ef16c2c0204..12cd15fe3d2 100644
--- a/chromium/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h
+++ b/chromium/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h
@@ -9,9 +9,11 @@
#include "ash/public/cpp/clipboard_history_controller.h"
#include "base/memory/weak_ptr.h"
+#include "base/values.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_delegate.h"
#include "extensions/common/api/virtual_keyboard.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace media {
class AudioSystem;
@@ -66,8 +68,9 @@ class ChromeVirtualKeyboardDelegate
OnGetClipboardHistoryCallback get_history_callback) override;
bool PasteClipboardItem(const std::string& clipboard_item_id) override;
bool DeleteClipboardItem(const std::string& clipboard_item_id) override;
- api::virtual_keyboard::FeatureRestrictions RestrictFeatures(
- const api::virtual_keyboard::RestrictFeatures::Params& params) override;
+ void RestrictFeatures(
+ const api::virtual_keyboard::RestrictFeatures::Params& params,
+ OnRestrictFeaturesCallback callback) override;
private:
// ash::ClipboardHistoryController::Observer:
@@ -79,8 +82,7 @@ class ChromeVirtualKeyboardDelegate
void OnHasInputDevices(OnKeyboardSettingsCallback on_settings_callback,
bool has_audio_input_devices);
- void DispatchConfigChangeEvent(
- std::unique_ptr<base::DictionaryValue> settings);
+ void DispatchConfigChangeEvent(absl::optional<base::Value::Dict> settings);
content::BrowserContext* browser_context_;
std::unique_ptr<media::AudioSystem> audio_system_;
diff --git a/chromium/chrome/browser/extensions/api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.cc b/chromium/chrome/browser/extensions/api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.cc
new file mode 100644
index 00000000000..67c5cd383b8
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.cc
@@ -0,0 +1,230 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "chrome/browser/extensions/api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.h"
+
+#include "base/notreached.h"
+#include "chromeos/crosapi/mojom/virtual_keyboard.mojom.h"
+#include "chromeos/lacros/lacros_service.h"
+
+namespace extensions {
+namespace {
+void UpdateRestriction(
+ crosapi::mojom::VirtualKeyboardFeature feature,
+ bool enabled,
+ crosapi::mojom::VirtualKeyboardRestrictions* restrictions) {
+ if (enabled) {
+ restrictions->enabled_features.push_back(feature);
+ } else {
+ restrictions->disabled_features.push_back(feature);
+ }
+}
+
+void PopulateFeatureRestrictions(
+ const std::vector<crosapi::mojom::VirtualKeyboardFeature>& features,
+ bool enabled,
+ api::virtual_keyboard::FeatureRestrictions* update) {
+ for (auto feature : features) {
+ switch (feature) {
+ case crosapi::mojom::VirtualKeyboardFeature::AUTOCOMPLETE:
+ update->auto_complete_enabled = std::make_unique<bool>(enabled);
+ break;
+ case crosapi::mojom::VirtualKeyboardFeature::AUTOCORRECT:
+ update->auto_correct_enabled = std::make_unique<bool>(enabled);
+ break;
+ case crosapi::mojom::VirtualKeyboardFeature::HANDWRITING:
+ update->handwriting_enabled = std::make_unique<bool>(enabled);
+ break;
+ case crosapi::mojom::VirtualKeyboardFeature::SPELL_CHECK:
+ update->spell_check_enabled = std::make_unique<bool>(enabled);
+ break;
+ case crosapi::mojom::VirtualKeyboardFeature::VOICE_INPUT:
+ update->voice_input_enabled = std::make_unique<bool>(enabled);
+ break;
+ case crosapi::mojom::VirtualKeyboardFeature::NONE:
+ NOTREACHED();
+ break;
+ }
+ }
+}
+} // namespace
+
+LacrosVirtualKeyboardDelegate::LacrosVirtualKeyboardDelegate() = default;
+
+LacrosVirtualKeyboardDelegate::~LacrosVirtualKeyboardDelegate() = default;
+
+void LacrosVirtualKeyboardDelegate::GetKeyboardConfig(
+ OnKeyboardSettingsCallback on_settings_callback) {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+void LacrosVirtualKeyboardDelegate::OnKeyboardConfigChanged() {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+bool LacrosVirtualKeyboardDelegate::HideKeyboard() {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::InsertText(const std::u16string& text) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::OnKeyboardLoaded() {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+void LacrosVirtualKeyboardDelegate::SetHotrodKeyboard(bool enable) {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+bool LacrosVirtualKeyboardDelegate::LockKeyboard(bool state) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::SendKeyEvent(const std::string& type,
+ int char_value,
+ int key_code,
+ const std::string& key_name,
+ int modifiers) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::ShowLanguageSettings() {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::ShowSuggestionSettings() {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::IsSettingsEnabled() {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::SetVirtualKeyboardMode(
+ int mode_enum,
+ gfx::Rect target_bounds,
+ OnSetModeCallback on_set_mode_callback) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::SetDraggableArea(
+ const api::virtual_keyboard_private::Bounds& rect) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::SetRequestedKeyboardState(int state_enum) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::SetOccludedBounds(
+ const std::vector<gfx::Rect>& bounds) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::SetHitTestBounds(
+ const std::vector<gfx::Rect>& bounds) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::SetAreaToRemainOnScreen(
+ const gfx::Rect& bounds) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::SetWindowBoundsInScreen(
+ const gfx::Rect& bounds_in_screen) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+void LacrosVirtualKeyboardDelegate::GetClipboardHistory(
+ const std::set<std::string>& item_ids_filter,
+ OnGetClipboardHistoryCallback get_history_callback) {
+ NOTIMPLEMENTED_LOG_ONCE();
+}
+
+bool LacrosVirtualKeyboardDelegate::PasteClipboardItem(
+ const std::string& clipboard_item_id) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+bool LacrosVirtualKeyboardDelegate::DeleteClipboardItem(
+ const std::string& clipboard_item_id) {
+ NOTIMPLEMENTED_LOG_ONCE();
+ return false;
+}
+
+void LacrosVirtualKeyboardDelegate::ParseRestrictFeaturesResult(
+ OnRestrictFeaturesCallback callback,
+ crosapi::mojom::VirtualKeyboardRestrictionsPtr update_mojo) {
+ api::virtual_keyboard::FeatureRestrictions update;
+ PopulateFeatureRestrictions(update_mojo->enabled_features, true, &update);
+ PopulateFeatureRestrictions(update_mojo->disabled_features, false, &update);
+ std::move(callback).Run(std::move(update));
+}
+
+void LacrosVirtualKeyboardDelegate::RestrictFeatures(
+ const api::virtual_keyboard::RestrictFeatures::Params& params,
+ OnRestrictFeaturesCallback callback) {
+ const api::virtual_keyboard::FeatureRestrictions& restrictions =
+ params.restrictions;
+
+ auto* lacros_service = chromeos::LacrosService::Get();
+ if (!lacros_service->IsAvailable<crosapi::mojom::VirtualKeyboard>()) {
+ std::move(callback).Run(api::virtual_keyboard::FeatureRestrictions());
+ return;
+ }
+
+ auto restrictions_mojo = crosapi::mojom::VirtualKeyboardRestrictions::New();
+ if (restrictions.auto_complete_enabled) {
+ UpdateRestriction(crosapi::mojom::VirtualKeyboardFeature::AUTOCOMPLETE,
+ *restrictions.auto_complete_enabled,
+ restrictions_mojo.get());
+ }
+ if (restrictions.auto_correct_enabled) {
+ UpdateRestriction(crosapi::mojom::VirtualKeyboardFeature::AUTOCORRECT,
+ *restrictions.auto_correct_enabled,
+ restrictions_mojo.get());
+ }
+ if (restrictions.handwriting_enabled) {
+ UpdateRestriction(crosapi::mojom::VirtualKeyboardFeature::HANDWRITING,
+ *restrictions.handwriting_enabled,
+ restrictions_mojo.get());
+ }
+ if (restrictions.spell_check_enabled) {
+ UpdateRestriction(crosapi::mojom::VirtualKeyboardFeature::SPELL_CHECK,
+ *restrictions.spell_check_enabled,
+ restrictions_mojo.get());
+ }
+ if (restrictions.voice_input_enabled) {
+ UpdateRestriction(crosapi::mojom::VirtualKeyboardFeature::VOICE_INPUT,
+ *restrictions.voice_input_enabled,
+ restrictions_mojo.get());
+ }
+
+ lacros_service->GetRemote<crosapi::mojom::VirtualKeyboard>()
+ ->RestrictFeatures(
+ std::move(restrictions_mojo),
+ base::BindOnce(
+ &LacrosVirtualKeyboardDelegate::ParseRestrictFeaturesResult,
+ weak_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.h b/chromium/chrome/browser/extensions/api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.h
new file mode 100644
index 00000000000..9e55511c897
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/virtual_keyboard_private/lacros_virtual_keyboard_delegate.h
@@ -0,0 +1,76 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_VIRTUAL_KEYBOARD_PRIVATE_LACROS_VIRTUAL_KEYBOARD_DELEGATE_H_
+#define CHROME_BROWSER_EXTENSIONS_API_VIRTUAL_KEYBOARD_PRIVATE_LACROS_VIRTUAL_KEYBOARD_DELEGATE_H_
+
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "chromeos/crosapi/mojom/virtual_keyboard.mojom.h"
+#include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_delegate.h"
+#include "extensions/common/api/virtual_keyboard.h"
+
+namespace extensions {
+
+// The virtual keyboard api delegate for lacros browser, it handles virtual
+// keyboar api request from lacros browser extensions. Currently it only
+// supports RestrictFeatures requests, all other apis are unimplemented.
+class LacrosVirtualKeyboardDelegate : public VirtualKeyboardDelegate {
+ public:
+ LacrosVirtualKeyboardDelegate();
+
+ LacrosVirtualKeyboardDelegate(const LacrosVirtualKeyboardDelegate&) = delete;
+ LacrosVirtualKeyboardDelegate& operator=(
+ const LacrosVirtualKeyboardDelegate&) = delete;
+
+ ~LacrosVirtualKeyboardDelegate() override;
+
+ private:
+ // VirtualKeyboardDelegate impl:
+ void GetKeyboardConfig(
+ OnKeyboardSettingsCallback on_settings_callback) override;
+ void OnKeyboardConfigChanged() override;
+ bool HideKeyboard() override;
+ bool InsertText(const std::u16string& text) override;
+ bool OnKeyboardLoaded() override;
+ void SetHotrodKeyboard(bool enable) override;
+ bool LockKeyboard(bool state) override;
+ bool SendKeyEvent(const std::string& type,
+ int char_value,
+ int key_code,
+ const std::string& key_name,
+ int modifiers) override;
+ bool ShowLanguageSettings() override;
+ bool ShowSuggestionSettings() override;
+ bool IsSettingsEnabled() override;
+ bool SetVirtualKeyboardMode(int mode_enum,
+ gfx::Rect target_bounds,
+ OnSetModeCallback on_set_mode_callback) override;
+ bool SetDraggableArea(
+ const api::virtual_keyboard_private::Bounds& rect) override;
+ bool SetRequestedKeyboardState(int state_enum) override;
+ bool SetOccludedBounds(const std::vector<gfx::Rect>& bounds) override;
+ bool SetHitTestBounds(const std::vector<gfx::Rect>& bounds) override;
+ bool SetAreaToRemainOnScreen(const gfx::Rect& bounds) override;
+ bool SetWindowBoundsInScreen(const gfx::Rect& bounds_in_screen) override;
+ void GetClipboardHistory(
+ const std::set<std::string>& item_ids_filter,
+ OnGetClipboardHistoryCallback get_history_callback) override;
+ bool PasteClipboardItem(const std::string& clipboard_item_id) override;
+ bool DeleteClipboardItem(const std::string& clipboard_item_id) override;
+ void RestrictFeatures(
+ const api::virtual_keyboard::RestrictFeatures::Params& params,
+ OnRestrictFeaturesCallback callback) override;
+
+ void ParseRestrictFeaturesResult(
+ OnRestrictFeaturesCallback callback,
+ crosapi::mojom::VirtualKeyboardRestrictionsPtr update);
+
+ base::WeakPtrFactory<LacrosVirtualKeyboardDelegate> weak_factory_{this};
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_VIRTUAL_KEYBOARD_PRIVATE_LACROS_VIRTUAL_KEYBOARD_DELEGATE_H_
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 0ad00574eb3..304c58205ee 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
@@ -77,7 +77,13 @@ class VirtualKeyboardPrivateApiTest : public extensions::ExtensionApiTest {
}
};
-IN_PROC_BROWSER_TEST_F(VirtualKeyboardPrivateApiTest, Multipaste) {
+// TODO(crbug.com/1352320): Flaky on release bots.
+#if defined(NDEBUG)
+#define MAYBE_Multipaste DISABLED_Multipaste
+#else
+#define MAYBE_Multipaste Multipaste
+#endif
+IN_PROC_BROWSER_TEST_F(VirtualKeyboardPrivateApiTest, MAYBE_Multipaste) {
// Copy to the clipboard an item of each display format type.
CopyHtmlItem();
CopyTextItem();
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 1c2051ad1b0..91c2cfad9ca 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
@@ -15,8 +15,8 @@
#include "chrome/browser/extensions/extension_apitest.h"
#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/network/shill_property_handler.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"
@@ -33,10 +33,10 @@
#include "chrome/browser/ash/crosapi/crosapi_manager.h"
#include "chrome/browser/ash/crosapi/vpn_service_ash.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chromeos/dbus/shill/fake_shill_third_party_vpn_driver_client.h"
-#include "chromeos/dbus/shill/shill_manager_client.h"
-#include "chromeos/dbus/shill/shill_profile_client.h"
-#include "chromeos/network/network_profile_handler.h"
+#include "chromeos/ash/components/dbus/shill/fake_shill_third_party_vpn_driver_client.h"
+#include "chromeos/ash/components/dbus/shill/shill_manager_client.h"
+#include "chromeos/ash/components/dbus/shill/shill_profile_client.h"
+#include "chromeos/ash/components/network/network_profile_handler.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#endif
@@ -89,7 +89,7 @@ void DoNothingSuccessCallback(const std::string& service_path,
// Records the number of calls and their parameters. Always replies successfully
// to calls.
class TestShillThirdPartyVpnDriverClient
- : public FakeShillThirdPartyVpnDriverClient {
+ : public ash::FakeShillThirdPartyVpnDriverClient {
public:
void SetParameters(const std::string& object_path_value,
const base::Value& parameters,
@@ -309,7 +309,7 @@ class VpnProviderApiTestAsh : public VpnProviderApiTestBase {
bool HasService(const std::string& service_path) const {
std::string profile_path;
base::Value properties =
- ShillProfileClient::Get()->GetTestInterface()->GetService(
+ ash::ShillProfileClient::Get()->GetTestInterface()->GetService(
service_path, &profile_path);
return properties.is_dict();
}
@@ -325,15 +325,15 @@ class VpnProviderApiTestAsh : public VpnProviderApiTestBase {
}
void ClearNetworkProfiles() {
- ShillProfileClient::Get()->GetTestInterface()->ClearProfiles();
+ ash::ShillProfileClient::Get()->GetTestInterface()->ClearProfiles();
// ShillProfileClient doesn't notify NetworkProfileHandler that profiles got
// cleared, therefore we have to call ShillManagerClient explicitly.
- ShillManagerClient::Get()->GetTestInterface()->ClearProfiles();
+ ash::ShillManagerClient::Get()->GetTestInterface()->ClearProfiles();
}
protected:
void AddNetworkProfileForUser() {
- ShillProfileClient::Get()->GetTestInterface()->AddProfile(
+ ash::ShillProfileClient::Get()->GetTestInterface()->AddProfile(
kNetworkProfilePath,
ash::ProfileHelper::GetUserIdHashFromProfile(profile()));
content::RunAllPendingInMessageLoop();
diff --git a/chromium/chrome/browser/extensions/api/web_accessible_resources_apitest.cc b/chromium/chrome/browser/extensions/api/web_accessible_resources_apitest.cc
new file mode 100644
index 00000000000..e66010d437c
--- /dev/null
+++ b/chromium/chrome/browser/extensions/api/web_accessible_resources_apitest.cc
@@ -0,0 +1,355 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/version_info/channel.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "extensions/browser/background_script_executor.h"
+#include "extensions/common/extension_features.h"
+#include "extensions/test/result_catcher.h"
+#include "extensions/test/test_extension_dir.h"
+#include "net/base/filename_util.h"
+#include "net/dns/mock_host_resolver.h"
+
+namespace extensions {
+namespace {
+
+class WebAccessibleResourcesApiTest : public ExtensionApiTest {
+ public:
+ void SetUpOnMainThread() override {
+ ExtensionApiTest::SetUpOnMainThread();
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ }
+};
+
+// Fetch web accessible resources directly from a file:// page.
+IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesApiTest,
+ FileSchemeInitiators_MainWorld) {
+ // Load extension.
+ TestExtensionDir extension_dir;
+ const char* kManifestStub = R"({
+ "name": "Test",
+ "version": "0.1",
+ "manifest_version": 3,
+ "web_accessible_resources": [
+ {
+ "resources": [ "ok_0.html" ],
+ "matches": [ "file://*/*" ]
+ },
+ {
+ "resources": [ "ok_1.html" ],
+ "matches": [ "<all_urls>" ]
+ },
+ {
+ "resources": [ "no_0.html" ],
+ "matches": [ "http://*.example.com/*" ]
+ },
+ {
+ "resources": [ "no_1.html" ],
+ "matches": [ "*://*/*" ]
+ }
+ ]
+ })";
+ extension_dir.WriteManifest(kManifestStub);
+ extension_dir.WriteFile(FILE_PATH_LITERAL("ok_0.html"), "ok_0.html");
+ extension_dir.WriteFile(FILE_PATH_LITERAL("ok_1.html"), "ok_1.html");
+ extension_dir.WriteFile(FILE_PATH_LITERAL("no_0.html"), "no_0.html");
+ extension_dir.WriteFile(FILE_PATH_LITERAL("no_1.html"), "no_1.html");
+ const Extension* extension =
+ LoadExtension(extension_dir.UnpackedPath(), {.allow_file_access = true});
+
+ // Navigate to extension's index.html via file:// and test.
+ base::FilePath test_page;
+ ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_page));
+ test_page = test_page.AppendASCII("simple.html");
+ GURL gurl = net::FilePathToFileURL(test_page);
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
+ auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+ static constexpr char kScriptTemplate[] = R"(
+ // Verify that web accessible resource can be fetched.
+ async function run(expectOk, filename) {
+ return new Promise(async resolve => {
+ const url = `chrome-extension://%s/${filename}`;
+
+ // Fetch and verify the contents of fetched web accessible resources.
+ const verifyFetch = (actual) => {
+ if (expectOk == (filename == actual)) {
+ resolve();
+ } else {
+ reject(`Unexpected result. File: ${filename}. Found: ${actual}`);
+ }
+ };
+ fetch(url)
+ .then(result => result.text())
+ .catch(error => verifyFetch(error))
+ .then(text => verifyFetch(text));
+ });
+ }
+
+ // Run tests.
+ const testCases = [
+ [true, 'ok_0.html'],
+ [true, 'ok_1.html'],
+ [false, 'no_0.html'],
+ [false, 'no_1.html']
+ ];
+ const tests = testCases.map(testCase => run(...testCase));
+ Promise.all(tests).then(response => true);
+ )";
+ std::string script =
+ base::StringPrintf(kScriptTemplate, extension->id().c_str());
+ ASSERT_TRUE(content::EvalJs(web_contents, script).ExtractBool());
+}
+
+// Test loading of subresources using an initiator coming from a file:// scheme,
+// and, notably, from within a content script context.
+IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesApiTest,
+ FileSchemeInitiators_ContentScript) {
+ // Load extension.
+ TestExtensionDir test_dir;
+ const char* kManifestStub = R"({
+ "name": "Test",
+ "version": "0.1",
+ "manifest_version": 3,
+ "background": {"service_worker": "service_worker.js"},
+ "host_permissions": ["file:///*"],
+ "permissions": ["scripting"],
+ "web_accessible_resources": [
+ {
+ "resources": [ "ok_0.html" ],
+ "matches": [ "file://*/*" ]
+ },
+ {
+ "resources": [ "ok_1.html" ],
+ "matches": [ "<all_urls>" ]
+ },
+ {
+ "resources": [ "no_0.html" ],
+ "matches": [ "http://*.example.com/*" ]
+ },
+ {
+ "resources": [ "no_1.html" ],
+ "matches": [ "*://*/*" ]
+ }
+ ]
+ })";
+ test_dir.WriteManifest(kManifestStub);
+ test_dir.WriteFile(FILE_PATH_LITERAL("ok_0.html"), "ok_0.html");
+ test_dir.WriteFile(FILE_PATH_LITERAL("ok_1.html"), "ok_1.html");
+ test_dir.WriteFile(FILE_PATH_LITERAL("no_0.html"), "no_0.html");
+ test_dir.WriteFile(FILE_PATH_LITERAL("no_1.html"), "no_1.html");
+ test_dir.WriteFile(FILE_PATH_LITERAL("service_worker.js"), "");
+ const char* kTestJs = R"(
+ // Verify that web accessible resource can be fetched.
+ async function run(expectOk, filename) {
+ return new Promise(async resolve => {
+ const url = chrome.runtime.getURL(filename);
+
+ // Fetch and verify the contents of fetched web accessible resources.
+ const verifyFetch = (actual) => {
+ chrome.test.assertEq(expectOk, filename == actual);
+ resolve();
+ };
+ fetch(url)
+ .then(result => result.text())
+ .catch(error => verifyFetch(error))
+ .then(text => verifyFetch(text));
+ });
+ }
+
+ // Run tests.
+ const testCases = [
+ [true, 'ok_0.html'],
+ [true, 'ok_1.html'],
+ [false, 'no_0.html'],
+ [false, 'no_1.html']
+ ];
+ const tests = testCases.map(testCase => run(...testCase));
+ Promise.all(tests).then(() => chrome.test.succeed());
+ )";
+ test_dir.WriteFile(FILE_PATH_LITERAL("test.js"), kTestJs);
+ const Extension* extension =
+ LoadExtension(test_dir.UnpackedPath(), {.allow_file_access = true});
+
+ // Navigate to extension's index.html via file:// and test.
+ ResultCatcher catcher;
+ base::FilePath test_page;
+ base::PathService::Get(chrome::DIR_TEST_DATA, &test_page);
+ test_page = test_page.AppendASCII("simple.html");
+ GURL gurl = net::FilePathToFileURL(test_page);
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
+ auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+ const int tab_id = ExtensionTabUtil::GetTabId(web_contents);
+ std::string script = base::StringPrintf(
+ R"(
+ (async () => {
+ await chrome.scripting.executeScript(
+ {target: {tabId: %d}, files: ['test.js']})
+ })();
+ )",
+ tab_id);
+ BackgroundScriptExecutor::ExecuteScriptAsync(
+ profile(), extension->id(), base::StringPrintf(script.c_str(), tab_id));
+ ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+class WebAccessibleResourcesDynamicUrlApiTest : public ExtensionApiTest {
+ public:
+ WebAccessibleResourcesDynamicUrlApiTest() {
+ feature_list_.InitAndEnableFeature(
+ extensions_features::kExtensionDynamicURLRedirection);
+ }
+
+ void SetUpOnMainThread() override {
+ ExtensionApiTest::SetUpOnMainThread();
+ host_resolver()->AddRule("*", "127.0.0.1");
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ }
+
+ protected:
+ const Extension* GetExtension(const char* manifest_piece) {
+ // manifest.json.
+ const char* kManifestStub = R"({
+ "name": "Test",
+ "version": "1.0",
+ "manifest_version": 3,
+ "host_permissions": ["<all_urls>"],
+ "web_accessible_resources": [
+ {
+ "resources": ["dynamic_web_accessible_resource.html"],
+ "matches": ["<all_urls>"],
+ "use_dynamic_url": true
+ },
+ {
+ "resources": ["web_accessible_resource.html"],
+ "matches": ["<all_urls>"]
+ }
+ ],
+ %s
+ })";
+ auto kManifest = base::StringPrintf(kManifestStub, manifest_piece);
+ test_dir_.WriteManifest(kManifest);
+
+ // content.js
+ const char* kTestScript = R"(
+ // Verify that web accessible resource can be fetched.
+ async function run(expectOk, filename, identifier) {
+ return new Promise(async resolve => {
+ // Verify URL.
+ let expected = chrome.runtime.getURL(filename);
+ let url = `chrome-extension://${identifier}/${filename}`;
+ chrome.test.assertEq(expectOk, expected == url);
+
+ // Verify contents of fetched web accessible resource.
+ const verify = (actual) => {
+ chrome.test.assertEq(expectOk, filename == actual);
+ resolve();
+ };
+
+ // Fetch web accessible resource.
+ fetch(url)
+ .then(result => result.text())
+ .catch(error => verify(error))
+ .then(text => verify(text));
+ });
+ }
+
+ // Verify that identifiers don't match.
+ const id = chrome.runtime.id;
+ const dynamicId = chrome.runtime.dynamicId;
+ chrome.test.assertTrue(id != dynamicId);
+
+ // Run tests.
+ const testCases = [
+ [true, 'dynamic_web_accessible_resource.html', dynamicId],
+ [true, 'web_accessible_resource.html', id],
+ [false, 'web_accessible_resource.html', 'error'],
+ [false, 'dynamic_web_accessible_resource.html', 'error'],
+ ];
+ const tests = testCases.map(testCase => run(...testCase));
+ Promise.all(tests).then(() => chrome.test.succeed());
+ )";
+
+ // Write files and load extension.
+ WriteFile(FILE_PATH_LITERAL("content.js"), kTestScript);
+ WriteFile(FILE_PATH_LITERAL("dynamic_web_accessible_resource.html"),
+ "dynamic_web_accessible_resource.html");
+ WriteFile(FILE_PATH_LITERAL("web_accessible_resource.html"),
+ "web_accessible_resource.html");
+ const Extension* extension = LoadExtension(test_dir_.UnpackedPath());
+ return extension;
+ }
+
+ // Write file to extension directory.
+ void WriteFile(const base::FilePath::CharType* filename,
+ const char* contents) {
+ test_dir_.WriteFile(filename, contents);
+ }
+
+ private:
+ base::test::ScopedFeatureList feature_list_;
+ ScopedCurrentChannel current_channel_{version_info::Channel::CANARY};
+ TestExtensionDir test_dir_;
+};
+
+// Load dynamic web accessible resource from a content script.
+IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesDynamicUrlApiTest, ContentScript) {
+ const char* kManifest = R"(
+ "content_scripts": [
+ {
+ "matches": ["<all_urls>"],
+ "js": ["content.js"],
+ "run_at": "document_start"
+ }
+ ]
+ )";
+ const Extension* extension = GetExtension(kManifest);
+ ASSERT_TRUE(extension);
+
+ ResultCatcher catcher;
+ GURL gurl = embedded_test_server()->GetURL("example.com", "/empty.html");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
+ ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+// Load dynamic web accessible resources via chrome.scripting.executeScript().
+IN_PROC_BROWSER_TEST_F(WebAccessibleResourcesDynamicUrlApiTest, ExecuteScript) {
+ // Load extension.
+ WriteFile(FILE_PATH_LITERAL("worker.js"), "// Intentionally blank.");
+ const char* kManifest = R"(
+ "permissions": ["scripting"],
+ "background": {"service_worker": "worker.js"}
+ )";
+ const Extension* extension = GetExtension(kManifest);
+ ASSERT_TRUE(extension);
+
+ // Navigate to a non extension page and test.
+ ResultCatcher catcher;
+ GURL gurl = embedded_test_server()->GetURL("example.com", "/empty.html");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
+ auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+ const int tab_id = ExtensionTabUtil::GetTabId(web_contents);
+ std::string script = base::StringPrintf(
+ R"(
+ (async () => {
+ await chrome.scripting.executeScript(
+ {target: {tabId: %d}, files: ['content.js']})
+ })();
+ )",
+ tab_id);
+ BackgroundScriptExecutor::ExecuteScriptAsync(
+ profile(), extension->id(), base::StringPrintf(script.c_str(), tab_id));
+ ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+} // namespace
+} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/web_authentication_proxy/value_conversions.cc b/chromium/chrome/browser/extensions/api/web_authentication_proxy/value_conversions.cc
index f8e99cbdd5a..444eb5758d8 100644
--- a/chromium/chrome/browser/extensions/api/web_authentication_proxy/value_conversions.cc
+++ b/chromium/chrome/browser/extensions/api/web_authentication_proxy/value_conversions.cc
@@ -92,52 +92,52 @@ std::vector<uint8_t> ToByteVector(const std::string& in) {
}
base::Value ToValue(const device::PublicKeyCredentialRpEntity& relying_party) {
- base::Value value(base::Value::Type::DICTIONARY);
- value.SetStringKey("id", relying_party.id);
+ base::Value::Dict value;
+ value.Set("id", relying_party.id);
// `PublicKeyCredentialEntity.name` is required in the IDL but optional on the
// mojo struct.
- value.SetKey("name", base::Value(relying_party.name.value_or("")));
- return value;
+ value.Set("name", relying_party.name.value_or(""));
+ return base::Value(std::move(value));
}
base::Value ToValue(const device::PublicKeyCredentialUserEntity& user) {
- base::Value value(base::Value::Type::DICTIONARY);
- value.SetStringKey("id", Base64UrlEncode(user.id));
+ base::Value::Dict value;
+ value.Set("id", Base64UrlEncode(user.id));
// `PublicKeyCredentialEntity.name` is required in the IDL but optional on the
// mojo struct.
- value.SetKey("name", base::Value(user.name.value_or("")));
+ value.Set("name", user.name.value_or(""));
if (user.display_name) {
- value.SetKey("displayName", base::Value(*user.display_name));
+ value.Set("displayName", *user.display_name);
}
- return value;
+ return base::Value(std::move(value));
}
base::Value ToValue(
const device::PublicKeyCredentialParams::CredentialInfo& params) {
- base::Value value(base::Value::Type::DICTIONARY);
+ base::Value::Dict value;
switch (params.type) {
case device::CredentialType::kPublicKey:
- value.SetKey("type", base::Value(device::kPublicKey));
+ value.Set("type", device::kPublicKey);
}
- value.SetIntKey("alg", params.algorithm);
- return value;
+ value.Set("alg", params.algorithm);
+ return base::Value(std::move(value));
}
base::Value ToValue(const device::PublicKeyCredentialDescriptor& descriptor) {
- base::Value value(base::Value::Type::DICTIONARY);
+ base::Value::Dict value;
switch (descriptor.credential_type) {
case device::CredentialType::kPublicKey:
- value.SetKey("type", base::Value(device::kPublicKey));
+ value.Set("type", device::kPublicKey);
}
- value.SetStringKey("id", Base64UrlEncode(descriptor.id));
- std::vector<base::Value> transports;
+ value.Set("id", Base64UrlEncode(descriptor.id));
+ base::Value::List transports;
for (const device::FidoTransportProtocol& transport : descriptor.transports) {
- transports.emplace_back(base::Value(ToString(transport)));
+ transports.Append(ToString(transport));
}
if (!transports.empty()) {
- value.SetKey("transports", base::Value(std::move(transports)));
+ value.Set("transports", std::move(transports));
}
- return value;
+ return base::Value(std::move(value));
}
base::Value ToValue(
@@ -180,17 +180,17 @@ base::Value ToValue(
base::Value ToValue(
const device::AuthenticatorSelectionCriteria& authenticator_selection) {
- base::Value value(base::Value::Type::DICTIONARY);
+ base::Value::Dict value;
absl::optional<std::string> attachment;
if (authenticator_selection.authenticator_attachment !=
device::AuthenticatorAttachment::kAny) {
- value.SetKey("authenticatorAttachment",
- ToValue(authenticator_selection.authenticator_attachment));
+ value.Set("authenticatorAttachment",
+ ToValue(authenticator_selection.authenticator_attachment));
}
- value.SetKey("residentKey", ToValue(authenticator_selection.resident_key));
- value.SetKey("userVerification",
- ToValue(authenticator_selection.user_verification_requirement));
- return value;
+ value.Set("residentKey", ToValue(authenticator_selection.resident_key));
+ value.Set("userVerification",
+ ToValue(authenticator_selection.user_verification_requirement));
+ return base::Value(std::move(value));
}
base::Value ToValue(const device::AttestationConveyancePreference&
@@ -211,12 +211,11 @@ base::Value ToValue(const device::AttestationConveyancePreference&
base::Value ToValue(const blink::mojom::RemoteDesktopClientOverride&
remote_desktop_client_override) {
- base::Value value(base::Value::Type::DICTIONARY);
- value.SetStringKey("origin",
- remote_desktop_client_override.origin.Serialize());
- value.SetBoolKey("sameOriginWithAncestors",
- remote_desktop_client_override.same_origin_with_ancestors);
- return value;
+ base::Value::Dict value;
+ value.Set("origin", remote_desktop_client_override.origin.Serialize());
+ value.Set("sameOriginWithAncestors",
+ remote_desktop_client_override.same_origin_with_ancestors);
+ return base::Value(std::move(value));
}
base::Value ToValue(const blink::mojom::ProtectionPolicy policy) {
@@ -246,35 +245,30 @@ base::Value ToValue(const device::LargeBlobSupport large_blob) {
}
base::Value ToValue(const device::CableDiscoveryData& cable_authentication) {
- base::Value value(base::Value::Type::DICTIONARY);
+ base::Value::Dict value;
switch (cable_authentication.version) {
case device::CableDiscoveryData::Version::INVALID:
NOTREACHED();
break;
case device::CableDiscoveryData::Version::V1:
- value.SetKey("version", base::Value(1));
- value.SetKey(
- "clientEid",
- base::Value(Base64UrlEncode(cable_authentication.v1->client_eid)));
- value.SetKey("authenticatorEid",
- base::Value(Base64UrlEncode(
- cable_authentication.v1->authenticator_eid)));
- value.SetKey("sessionPreKey",
- base::Value(Base64UrlEncode(
- cable_authentication.v1->session_pre_key)));
+ value.Set("version", 1);
+ value.Set("clientEid",
+ Base64UrlEncode(cable_authentication.v1->client_eid));
+ value.Set("authenticatorEid",
+ Base64UrlEncode(cable_authentication.v1->authenticator_eid));
+ value.Set("sessionPreKey",
+ Base64UrlEncode(cable_authentication.v1->session_pre_key));
break;
case device::CableDiscoveryData::Version::V2:
- value.SetKey("version", base::Value(2));
- value.SetKey(
- "clientEid",
- base::Value(Base64UrlEncode(cable_authentication.v2->experiments)));
- value.SetKey("authenticatorEid", base::Value(""));
- value.SetKey("sessionPreKey",
- base::Value(Base64UrlEncode(
- cable_authentication.v2->server_link_data)));
+ value.Set("version", 2);
+ value.Set("clientEid",
+ Base64UrlEncode(cable_authentication.v2->experiments));
+ value.Set("authenticatorEid", "");
+ value.Set("sessionPreKey",
+ Base64UrlEncode(cable_authentication.v2->server_link_data));
break;
}
- return value;
+ return base::Value(std::move(value));
}
absl::optional<device::FidoTransportProtocol> FidoTransportProtocolFromValue(
@@ -308,32 +302,30 @@ NullableAuthenticatorAttachmentFromValue(const base::Value& value) {
base::Value ToValue(
const blink::mojom::PublicKeyCredentialCreationOptionsPtr& options) {
- base::Value value(base::Value::Type::DICTIONARY);
- value.SetKey("rp", ToValue(options->relying_party));
- value.SetKey("user", ToValue(options->user));
- value.SetStringKey("challenge", Base64UrlEncode(options->challenge));
- std::vector<base::Value> public_key_parameters;
+ base::Value::Dict value;
+ value.Set("rp", ToValue(options->relying_party));
+ value.Set("user", ToValue(options->user));
+ value.Set("challenge", Base64UrlEncode(options->challenge));
+ base::Value::List public_key_parameters;
for (const device::PublicKeyCredentialParams::CredentialInfo& params :
options->public_key_parameters) {
- public_key_parameters.push_back(ToValue(params));
+ public_key_parameters.Append(ToValue(params));
}
- value.SetKey("pubKeyCredParams",
- base::Value(std::move(public_key_parameters)));
- std::vector<base::Value> exclude_credentials;
+ value.Set("pubKeyCredParams", std::move(public_key_parameters));
+ base::Value::List exclude_credentials;
for (const device::PublicKeyCredentialDescriptor& descriptor :
options->exclude_credentials) {
- exclude_credentials.push_back(ToValue(descriptor));
+ exclude_credentials.Append(ToValue(descriptor));
}
- value.SetKey("excludeCredentials",
- base::Value(std::move(exclude_credentials)));
+ value.Set("excludeCredentials", std::move(exclude_credentials));
if (options->authenticator_selection) {
- value.SetKey("authenticatorSelection",
- ToValue(*options->authenticator_selection));
+ value.Set("authenticatorSelection",
+ ToValue(*options->authenticator_selection));
}
- value.SetKey("attestation", ToValue(options->attestation));
+ value.Set("attestation", ToValue(options->attestation));
base::Value::Dict& extensions =
- value.GetDict().Set("extensions", base::Value::Dict())->GetDict();
+ value.Set("extensions", base::Value::Dict())->GetDict();
if (options->hmac_create_secret) {
extensions.Set("hmacCreateSecret", true);
@@ -344,21 +336,20 @@ base::Value ToValue(
extensions.Set("credentialProtectionPolicy",
ToValue(options->protection_policy));
extensions.Set("enforceCredentialProtectionPolicy",
- base::Value(options->enforce_protection_policy));
+ options->enforce_protection_policy);
}
if (options->appid_exclude) {
- extensions.Set("appIdExclude", base::Value(*options->appid_exclude));
+ extensions.Set("appIdExclude", *options->appid_exclude);
}
if (options->cred_props) {
- extensions.Set("credProps", base::Value(true));
+ extensions.Set("credProps", true);
}
if (options->large_blob_enable != device::LargeBlobSupport::kNotRequested) {
- base::Value large_blob_value(base::Value::Type::DICTIONARY);
- large_blob_value.GetDict().Set("support",
- ToValue(options->large_blob_enable));
+ base::Value::Dict large_blob_value;
+ large_blob_value.Set("support", ToValue(options->large_blob_enable));
extensions.Set("largeBlob", std::move(large_blob_value));
}
@@ -369,11 +360,11 @@ base::Value ToValue(
}
if (options->google_legacy_app_id_support) {
- extensions.Set("googleLegacyAppidSupport", base::Value(true));
+ extensions.Set("googleLegacyAppidSupport", true);
}
if (options->min_pin_length_requested) {
- extensions.Set("minPinLength", base::Value(true));
+ extensions.Set("minPinLength", true);
}
if (options->remote_desktop_client_override) {
@@ -383,39 +374,38 @@ base::Value ToValue(
DCHECK(!options->prf_enable);
- return value;
+ return base::Value(std::move(value));
}
base::Value ToValue(
const blink::mojom::PublicKeyCredentialRequestOptionsPtr& options) {
- base::Value value(base::Value::Type::DICTIONARY);
- value.SetStringKey("challenge", Base64UrlEncode(options->challenge));
- value.SetStringKey("rpId", options->relying_party_id);
+ base::Value::Dict value;
+ value.Set("challenge", Base64UrlEncode(options->challenge));
+ value.Set("rpId", options->relying_party_id);
- std::vector<base::Value> allow_credentials;
+ base::Value::List allow_credentials;
for (const device::PublicKeyCredentialDescriptor& descriptor :
options->allow_credentials) {
- allow_credentials.push_back(ToValue(descriptor));
+ allow_credentials.Append(ToValue(descriptor));
}
- value.SetKey("allowCredentials", base::Value(std::move(allow_credentials)));
+ value.Set("allowCredentials", std::move(allow_credentials));
- value.SetKey("userVerification", ToValue(options->user_verification));
+ value.Set("userVerification", ToValue(options->user_verification));
base::Value::Dict& extensions =
- value.GetDict().Set("extensions", base::Value::Dict())->GetDict();
+ value.Set("extensions", base::Value::Dict())->GetDict();
if (options->appid) {
- extensions.Set("appid", base::Value(*options->appid));
+ extensions.Set("appid", *options->appid);
}
- std::vector<base::Value> cable_authentication_data;
+ base::Value::List cable_authentication_data;
for (const device::CableDiscoveryData& cable :
options->cable_authentication_data) {
- cable_authentication_data.push_back(ToValue(cable));
+ cable_authentication_data.Append(ToValue(cable));
}
if (!cable_authentication_data.empty()) {
- extensions.Set("cableAuthentication",
- base::Value(std::move(cable_authentication_data)));
+ extensions.Set("cableAuthentication", std::move(cable_authentication_data));
}
if (options->get_cred_blob) {
@@ -423,13 +413,13 @@ base::Value ToValue(
}
if (options->large_blob_read || options->large_blob_write) {
- base::Value large_blob_value(base::Value::Type::DICTIONARY);
+ base::Value::Dict large_blob_value;
if (options->large_blob_read) {
- large_blob_value.GetDict().Set({"read"}, base::Value(true));
+ large_blob_value.Set("read", true);
}
if (options->large_blob_write) {
- large_blob_value.GetDict().Set(
- {"write"}, base::Value(Base64UrlEncode(*options->large_blob_write)));
+ large_blob_value.Set("write",
+ Base64UrlEncode(*options->large_blob_write));
}
extensions.Set("largeBlob", std::move(large_blob_value));
}
@@ -441,7 +431,7 @@ base::Value ToValue(
DCHECK(!options->prf);
- return value;
+ return base::Value(std::move(value));
}
std::pair<blink::mojom::MakeCredentialAuthenticatorResponsePtr, std::string>
diff --git a/chromium/chrome/browser/extensions/api/web_authentication_proxy/web_authentication_proxy_service.cc b/chromium/chrome/browser/extensions/api/web_authentication_proxy/web_authentication_proxy_service.cc
index 9beda38b103..50f212b301d 100644
--- a/chromium/chrome/browser/extensions/api/web_authentication_proxy/web_authentication_proxy_service.cc
+++ b/chromium/chrome/browser/extensions/api/web_authentication_proxy/web_authentication_proxy_service.cc
@@ -214,13 +214,13 @@ void WebAuthenticationProxyService::OnParseCreateResponse(
RequestId request_id,
data_decoder::DataDecoder::ValueOrError value_or_error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (value_or_error.error) {
+ if (!value_or_error.has_value()) {
std::move(respond_callback)
- .Run("Parsing responseJson failed: " + *value_or_error.error);
+ .Run("Parsing responseJson failed: " + value_or_error.error());
return;
}
auto [response, error] =
- webauthn_proxy::MakeCredentialResponseFromValue(*value_or_error.value);
+ webauthn_proxy::MakeCredentialResponseFromValue(*value_or_error);
if (!response) {
std::move(respond_callback).Run("Invalid responseJson: " + error);
return;
@@ -245,13 +245,13 @@ void WebAuthenticationProxyService::OnParseGetResponse(
RequestId request_id,
data_decoder::DataDecoder::ValueOrError value_or_error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (value_or_error.error) {
+ if (!value_or_error.has_value()) {
std::move(respond_callback)
- .Run("Parsing responseJson failed: " + *value_or_error.error);
+ .Run("Parsing responseJson failed: " + value_or_error.error());
return;
}
auto [response, error] =
- webauthn_proxy::GetAssertionResponseFromValue(*value_or_error.value);
+ webauthn_proxy::GetAssertionResponseFromValue(*value_or_error);
if (!response) {
std::move(respond_callback).Run("Invalid responseJson: " + error);
return;
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 d1c95bb1c4c..b492b94bff2 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
@@ -542,9 +542,9 @@ ExtensionFunction::ResponseAction WebNavigationGetFrameFunction::Run() {
ExtensionApiFrameIdMap::GetDocumentId(parent_frame_host).ToString());
}
frame_details.frame_type =
- ToString(ExtensionApiFrameIdMap::GetFrameType(render_frame_host));
+ ExtensionApiFrameIdMap::GetFrameType(render_frame_host);
frame_details.document_lifecycle =
- ToString(ExtensionApiFrameIdMap::GetDocumentLifecycle(render_frame_host));
+ ExtensionApiFrameIdMap::GetDocumentLifecycle(render_frame_host);
return RespondNow(ArgumentList(GetFrame::Results::Create(frame_details)));
}
@@ -565,10 +565,9 @@ ExtensionFunction::ResponseAction WebNavigationGetAllFramesFunction::Run() {
std::vector<GetAllFrames::Results::DetailsType> result_list;
- // We only iterate the frames in the active page. We currently do not
- // expose back/forward cached frames or prerender frames in the GetAllFrames
- // API.
- web_contents->GetPrimaryMainFrame()->ForEachRenderFrameHost(
+ // We currently do not expose back/forward cached frames in the GetAllFrames
+ // API, but we do explicitly include prerendered frames.
+ web_contents->ForEachRenderFrameHost(
base::BindRepeating(
[](content::WebContents* web_contents,
std::vector<GetAllFrames::Results::DetailsType>& result_list,
@@ -588,6 +587,14 @@ ExtensionFunction::ResponseAction WebNavigationGetAllFramesFunction::Run() {
return content::RenderFrameHost::FrameIterationAction::kContinue;
}
+ // Skip back/forward cached frames.
+ if (render_frame_host->IsInLifecycleState(
+ content::RenderFrameHost::LifecycleState::
+ kInBackForwardCache)) {
+ return content::RenderFrameHost::FrameIterationAction::
+ kSkipChildren;
+ }
+
GetAllFrames::Results::DetailsType frame;
frame.url = navigation_state->GetUrl().spec();
frame.frame_id =
@@ -604,11 +611,10 @@ ExtensionFunction::ResponseAction WebNavigationGetAllFramesFunction::Run() {
ExtensionApiFrameIdMap::GetDocumentId(parent_frame_host)
.ToString());
}
- frame.frame_type = ToString(
- ExtensionApiFrameIdMap::GetFrameType(render_frame_host));
+ frame.frame_type =
+ ExtensionApiFrameIdMap::GetFrameType(render_frame_host);
frame.document_lifecycle =
- ToString(ExtensionApiFrameIdMap::GetDocumentLifecycle(
- render_frame_host));
+ ExtensionApiFrameIdMap::GetDocumentLifecycle(render_frame_host);
frame.process_id = render_frame_host->GetProcess()->GetID();
frame.error_occurred = navigation_state->GetErrorOccurredInFrame();
result_list.push_back(std::move(frame));
diff --git a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc
index 86a4e3e25cf..edba29be7f1 100644
--- a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc
+++ b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc
@@ -82,10 +82,9 @@ std::unique_ptr<Event> CreateOnBeforeNavigateEvent(
details.parent_document_id = std::make_unique<std::string>(
ExtensionApiFrameIdMap::GetDocumentId(parent_frame_host).ToString());
}
- details.frame_type =
- ToString(ExtensionApiFrameIdMap::GetFrameType(navigation_handle));
+ details.frame_type = ExtensionApiFrameIdMap::GetFrameType(navigation_handle);
details.document_lifecycle =
- ToString(ExtensionApiFrameIdMap::GetDocumentLifecycle(navigation_handle));
+ ExtensionApiFrameIdMap::GetDocumentLifecycle(navigation_handle);
details.time_stamp = MilliSecondsFromTime(base::Time::Now());
auto event = std::make_unique<Event>(
@@ -168,9 +167,8 @@ void DispatchOnCommitted(events::HistogramValue histogram_value,
content::BrowserContext* browser_context =
navigation_handle->GetWebContents()->GetBrowserContext();
- auto event = std::make_unique<Event>(
- histogram_value, event_name,
- base::Value(std::move(args)).TakeListDeprecated(), browser_context);
+ auto event = std::make_unique<Event>(histogram_value, event_name,
+ std::move(args), browser_context);
DispatchEvent(browser_context, std::move(event), url);
}
@@ -193,10 +191,9 @@ void DispatchOnDOMContentLoaded(content::WebContents* web_contents,
details.parent_document_id = std::make_unique<std::string>(
ExtensionApiFrameIdMap::GetDocumentId(parent_frame_host).ToString());
}
- details.frame_type =
- ToString(ExtensionApiFrameIdMap::GetFrameType(frame_host));
+ details.frame_type = ExtensionApiFrameIdMap::GetFrameType(frame_host);
details.document_lifecycle =
- ToString(ExtensionApiFrameIdMap::GetDocumentLifecycle(frame_host));
+ ExtensionApiFrameIdMap::GetDocumentLifecycle(frame_host);
details.time_stamp = MilliSecondsFromTime(base::Time::Now());
content::BrowserContext* browser_context = web_contents->GetBrowserContext();
@@ -226,10 +223,9 @@ void DispatchOnCompleted(content::WebContents* web_contents,
details.parent_document_id = std::make_unique<std::string>(
ExtensionApiFrameIdMap::GetDocumentId(parent_frame_host).ToString());
}
- details.frame_type =
- ToString(ExtensionApiFrameIdMap::GetFrameType(frame_host));
+ details.frame_type = ExtensionApiFrameIdMap::GetFrameType(frame_host);
details.document_lifecycle =
- ToString(ExtensionApiFrameIdMap::GetDocumentLifecycle(frame_host));
+ ExtensionApiFrameIdMap::GetDocumentLifecycle(frame_host);
details.time_stamp = MilliSecondsFromTime(base::Time::Now());
content::BrowserContext* browser_context = web_contents->GetBrowserContext();
@@ -298,10 +294,9 @@ void DispatchOnErrorOccurred(content::WebContents* web_contents,
details.parent_document_id = std::make_unique<std::string>(
ExtensionApiFrameIdMap::GetDocumentId(parent_frame_host).ToString());
}
- details.frame_type =
- ToString(ExtensionApiFrameIdMap::GetFrameType(frame_host));
+ details.frame_type = ExtensionApiFrameIdMap::GetFrameType(frame_host);
details.document_lifecycle =
- ToString(ExtensionApiFrameIdMap::GetDocumentLifecycle(frame_host));
+ ExtensionApiFrameIdMap::GetDocumentLifecycle(frame_host);
details.time_stamp = MilliSecondsFromTime(base::Time::Now());
content::BrowserContext* browser_context = web_contents->GetBrowserContext();
@@ -333,10 +328,9 @@ void DispatchOnErrorOccurred(content::NavigationHandle* navigation_handle) {
details.parent_document_id = std::make_unique<std::string>(
ExtensionApiFrameIdMap::GetDocumentId(parent_frame_host).ToString());
}
- details.frame_type =
- ToString(ExtensionApiFrameIdMap::GetFrameType(navigation_handle));
+ details.frame_type = ExtensionApiFrameIdMap::GetFrameType(navigation_handle);
details.document_lifecycle =
- ToString(ExtensionApiFrameIdMap::GetDocumentLifecycle(navigation_handle));
+ ExtensionApiFrameIdMap::GetDocumentLifecycle(navigation_handle);
details.time_stamp = MilliSecondsFromTime(base::Time::Now());
content::BrowserContext* browser_context =
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 8feee120d67..95a246aad4d 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
@@ -45,6 +45,7 @@
#include "content/public/test/download_test_observer.h"
#include "content/public/test/fenced_frame_test_util.h"
#include "content/public/test/no_renderer_crashes_assertion.h"
+#include "content/public/test/prerender_test_util.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/switches.h"
@@ -225,6 +226,10 @@ class WebNavigationApiTest : public ExtensionApiTest {
// with deferred commits.
command_line->AppendSwitch(blink::switches::kAllowPreCommitInput);
}
+
+ content::WebContents* GetWebContents() {
+ return browser()->tab_strip_model()->GetActiveWebContents();
+ }
};
class WebNavigationApiBackForwardCacheTest : public WebNavigationApiTest {
@@ -263,14 +268,48 @@ class WebNavigationApiTestWithContextType
}
};
+class WebNavigationApiPrerenderTestWithContextType
+ : public WebNavigationApiTest,
+ public testing::WithParamInterface<ContextType> {
+ public:
+ WebNavigationApiPrerenderTestWithContextType()
+ : WebNavigationApiTest(GetParam()) {}
+ ~WebNavigationApiPrerenderTestWithContextType() override = default;
+ WebNavigationApiPrerenderTestWithContextType(
+ const WebNavigationApiPrerenderTestWithContextType&) = delete;
+ WebNavigationApiPrerenderTestWithContextType& operator=(
+ const WebNavigationApiPrerenderTestWithContextType&) = delete;
+
+ private:
+ content::test::ScopedPrerenderFeatureList prerender_feature_list_;
+};
+
IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, Api) {
ASSERT_TRUE(RunExtensionTest("webnavigation/api")) << message_;
}
-IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, GetFrame) {
+// TODO(crbug.com/1352957): Flakily timing out on win/mac/cros.
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS)
+#define MAYBE_GetFrame DISABLED_GetFrame
+#else
+#define MAYBE_GetFrame GetFrame
+#endif
+IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, MAYBE_GetFrame) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
ASSERT_TRUE(RunExtensionTest("webnavigation/getFrame")) << message_;
}
+IN_PROC_BROWSER_TEST_P(WebNavigationApiPrerenderTestWithContextType, GetFrame) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ ASSERT_TRUE(RunExtensionTest("webnavigation/getFrame")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_P(WebNavigationApiPrerenderTestWithContextType,
+ Prerendering) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ ASSERT_TRUE(RunExtensionTest("webnavigation/prerendering")) << message_;
+}
+
IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, GetFrameIncognito) {
ASSERT_TRUE(StartEmbeddedTestServer());
@@ -291,6 +330,12 @@ INSTANTIATE_TEST_SUITE_P(PersistentBackground,
INSTANTIATE_TEST_SUITE_P(ServiceWorker,
WebNavigationApiTestWithContextType,
testing::Values(ContextType::kServiceWorker));
+INSTANTIATE_TEST_SUITE_P(PersistentBackground,
+ WebNavigationApiPrerenderTestWithContextType,
+ testing::Values(ContextType::kPersistentBackground));
+INSTANTIATE_TEST_SUITE_P(ServiceWorker,
+ WebNavigationApiPrerenderTestWithContextType,
+ testing::Values(ContextType::kServiceWorker));
IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, ClientRedirect) {
ASSERT_TRUE(RunExtensionTest("webnavigation/clientRedirect")) << message_;
@@ -336,7 +381,7 @@ IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType,
ASSERT_TRUE(RunExtensionTest("webnavigation/serverRedirectSingleProcess"))
<< message_;
- WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+ WebContents* tab = GetWebContents();
EXPECT_TRUE(content::WaitForLoadStop(tab));
ResultCatcher catcher;
@@ -408,7 +453,7 @@ IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, UserAction) {
// Wait for the extension to set itself up and return control to us.
ASSERT_TRUE(RunExtensionTest("webnavigation/userAction")) << message_;
- WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+ WebContents* tab = GetWebContents();
EXPECT_TRUE(content::WaitForLoadStop(tab));
ResultCatcher catcher;
@@ -444,7 +489,7 @@ IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, RequestOpenTab) {
// Wait for the extension to set itself up and return control to us.
ASSERT_TRUE(RunExtensionTest("webnavigation/requestOpenTab")) << message_;
- WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+ WebContents* tab = GetWebContents();
EXPECT_TRUE(content::WaitForLoadStop(tab));
ResultCatcher catcher;
@@ -483,7 +528,7 @@ IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, TargetBlank) {
// Wait for the extension to set itself up and return control to us.
ASSERT_TRUE(RunExtensionTest("webnavigation/targetBlank")) << message_;
- WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+ WebContents* tab = GetWebContents();
EXPECT_TRUE(content::WaitForLoadStop(tab));
ResultCatcher catcher;
@@ -638,7 +683,7 @@ IN_PROC_BROWSER_TEST_P(WebNavigationApiTestWithContextType, Crash) {
// Wait for the extension to set itself up and return control to us.
ASSERT_TRUE(RunExtensionTest("webnavigation/crash")) << message_;
- WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+ WebContents* tab = GetWebContents();
EXPECT_TRUE(content::WaitForLoadStop(tab));
ResultCatcher catcher;
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 bfcf2e8896d..84679090272 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
@@ -58,11 +58,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-forward.h"
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/login/login_state/scoped_test_public_session_login_state.h"
-#include "components/crx_file/id_util.h"
-#endif
-
namespace helpers = extension_web_request_api_helpers;
namespace keys = extension_web_request_api_constants;
namespace web_request = extensions::api::web_request;
@@ -231,7 +226,6 @@ TEST_F(ExtensionWebRequestTest, BrowserContextShutdown) {
// created and destroyed. Unfortunately, that doesn't work with test profiles,
// so the test needs to simulate those calls
event_router->OnOTRBrowserContextCreated(&profile_, otr_profile);
- EXPECT_EQ(2u, event_router->cross_browser_context_map_.size());
EXPECT_EQ(0u,
event_router->GetListenerCountForTesting(otr_profile, kEventName));
EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerImpl(otr_profile));
@@ -252,7 +246,6 @@ TEST_F(ExtensionWebRequestTest, BrowserContextShutdown) {
// Simulate the OTR being destroyed.
event_router->OnOTRBrowserContextDestroyed(&profile_, otr_profile);
- EXPECT_EQ(0u, event_router->cross_browser_context_map_.size());
EXPECT_EQ(0u,
event_router->GetListenerCountForTesting(otr_profile, kEventName));
EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerImpl(otr_profile));
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 82e2696922f..361206dfe9a 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
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <array>
#include <memory>
#include <utility>
#include <vector>
@@ -29,6 +30,7 @@
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/devtools/protocol/devtools_protocol_test_support.h"
#include "chrome/browser/devtools/url_constants.h"
#include "chrome/browser/extensions/active_tab_permission_granter.h"
#include "chrome/browser/extensions/api/extension_action/test_extension_action_api_observer.h"
@@ -62,7 +64,6 @@
#include "chrome/common/url_constants.h"
#include "chrome/test/base/search_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
-#include "chromeos/login/login_state/scoped_test_public_session_login_state.h"
#include "components/embedder_support/switches.h"
#include "components/google/core/common/google_switches.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
@@ -88,15 +89,19 @@
#include "content/public/common/page_type.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/prerender_test_util.h"
#include "content/public/test/simple_url_loader_test_helper.h"
+#include "content/public/test/test_navigation_observer.h"
#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/web_request_api.h"
+#include "extensions/browser/background_script_executor.h"
#include "extensions/browser/blocked_action_type.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/process_manager.h"
+#include "extensions/browser/service_worker/service_worker_test_utils.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/extension_features.h"
#include "extensions/common/features/feature.h"
@@ -131,7 +136,6 @@
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chromeos/login/login_state/login_state.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
using content::WebContents;
@@ -245,23 +249,50 @@ void PerformXhrInFrame(content::RenderFrameHost* frame,
EXPECT_TRUE(success);
}
+base::Value ExecuteScriptAndReturnValue(const ExtensionId& extension_id,
+ content::BrowserContext* context,
+ const std::string& script) {
+ return BackgroundScriptExecutor::ExecuteScript(
+ context, extension_id, script,
+ BackgroundScriptExecutor::ResultCapture::kSendScriptResult);
+}
+
+absl::optional<bool> ExecuteScriptAndReturnBool(
+ const ExtensionId& extension_id,
+ content::BrowserContext* context,
+ const std::string& script) {
+ absl::optional<bool> result;
+ base::Value script_result =
+ ExecuteScriptAndReturnValue(extension_id, context, script);
+ if (script_result.is_bool())
+ result = script_result.GetBool();
+ return result;
+}
+
+absl::optional<std::string> ExecuteScriptAndReturnString(
+ const ExtensionId& extension_id,
+ content::BrowserContext* context,
+ const std::string& script) {
+ absl::optional<std::string> result;
+ base::Value script_result =
+ ExecuteScriptAndReturnValue(extension_id, context, script);
+ if (script_result.is_string())
+ result = script_result.GetString();
+ return result;
+}
+
// Returns the current count of a variable stored in the |extension| background
// page. Returns -1 if something goes awry.
int GetCountFromBackgroundPage(const Extension* extension,
content::BrowserContext* context,
const std::string& variable_name) {
- ExtensionHost* host =
- ProcessManager::Get(context)->GetBackgroundHostForExtension(
- extension->id());
- if (!host || !host->host_contents())
+ const std::string script = base::StringPrintf(
+ "chrome.test.sendScriptResult(%s)", variable_name.c_str());
+ base::Value value =
+ ExecuteScriptAndReturnValue(extension->id(), context, script);
+ if (!value.is_int())
return -1;
-
- int count = -1;
- if (!ExecuteScriptAndExtractInt(
- host->host_contents(),
- "window.domAutomationController.send(" + variable_name + ")", &count))
- return -1;
- return count;
+ return value.GetInt();
}
// Returns the current count of webRequests received by the |extension| in
@@ -269,8 +300,7 @@ int GetCountFromBackgroundPage(const Extension* extension,
// object). Returns -1 if something goes awry.
int GetWebRequestCountFromBackgroundPage(const Extension* extension,
content::BrowserContext* context) {
- return GetCountFromBackgroundPage(extension, context,
- "window.webRequestCount");
+ return GetCountFromBackgroundPage(extension, context, "self.webRequestCount");
}
// Returns true if the |extension|'s background page saw an event for a request
@@ -278,22 +308,14 @@ int GetWebRequestCountFromBackgroundPage(const Extension* extension,
bool HasSeenWebRequestInBackgroundPage(const Extension* extension,
content::BrowserContext* context,
const std::string& hostname) {
- // TODO(devlin): Here and in Get*CountFromBackgroundPage(), we should leverage
- // ExecuteScriptInBackgroundPage().
- ExtensionHost* host =
- ProcessManager::Get(context)->GetBackgroundHostForExtension(
- extension->id());
- if (!host || !host->host_contents())
- return false;
-
- bool seen = false;
- std::string script = base::StringPrintf(
- R"(domAutomationController.send(
- window.requestedHostnames.includes('%s'));)",
+ const std::string script = base::StringPrintf(
+ R"(chrome.test.sendScriptResult(
+ self.requestedHostnames.includes('%s'));)",
hostname.c_str());
- EXPECT_TRUE(
- ExecuteScriptAndExtractBool(host->host_contents(), script, &seen));
- return seen;
+ base::Value value =
+ ExecuteScriptAndReturnValue(extension->id(), context, script);
+ DCHECK(value.is_bool());
+ return value.GetBool();
}
void WaitForExtraHeadersListener(base::WaitableEvent* event,
@@ -311,8 +333,18 @@ void WaitForExtraHeadersListener(base::WaitableEvent* event,
} // namespace
+using ContextType = ExtensionBrowserTest::ContextType;
+
class ExtensionWebRequestApiTest : public ExtensionApiTest {
public:
+ explicit ExtensionWebRequestApiTest(
+ ContextType context_type = ContextType::kFromManifest)
+ : ExtensionApiTest(context_type) {}
+ ExtensionWebRequestApiTest(const ExtensionWebRequestApiTest&) = delete;
+ ExtensionWebRequestApiTest& operator=(const ExtensionWebRequestApiTest&) =
+ delete;
+ ~ExtensionWebRequestApiTest() override = default;
+
void SetUpOnMainThread() override {
ExtensionApiTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
@@ -326,12 +358,12 @@ class ExtensionWebRequestApiTest : public ExtensionApiTest {
kOriginTrialPublicKeyForTesting);
}
- void RunPermissionTest(
- const char* extension_directory,
- bool load_extension_with_incognito_permission,
- bool wait_for_extension_loaded_in_incognito,
- const char* expected_content_regular_window,
- const char* exptected_content_incognito_window);
+ void RunPermissionTest(const char* extension_directory,
+ bool load_extension_with_incognito_permission,
+ bool wait_for_extension_loaded_in_incognito,
+ const char* expected_content_regular_window,
+ const char* exptected_content_incognito_window,
+ ContextType context_type);
mojo::PendingRemote<network::mojom::URLLoaderFactory>
CreateURLLoaderFactory() {
@@ -452,20 +484,199 @@ class DevToolsFrontendInWebRequestApiTest : public ExtensionApiTest {
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestApi) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(RunExtensionTest("webrequest", {.page_url = "test_api.html"}))
- << message_;
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_api")) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestSimple) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(RunExtensionTest("webrequest", {.page_url = "test_simple.html"}))
- << message_;
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_simple")) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestComplex) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(RunExtensionTest("webrequest", {.page_url = "test_complex.html"}))
- << message_;
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_complex")) << message_;
+}
+
+class ExtensionDevToolsProtocolTest
+ : public ExtensionWebRequestApiTest,
+ public content::TestDevToolsProtocolClient {
+ protected:
+ void Attach() { AttachToWebContents(web_contents()); }
+
+ void TearDownOnMainThread() override {
+ DetachProtocolClient();
+ ExtensionWebRequestApiTest::TearDownOnMainThread();
+ }
+
+ content::WebContents* web_contents() {
+ return browser()->tab_strip_model()->GetWebContentsAt(0);
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(ExtensionDevToolsProtocolTest,
+ HeaderOverriddenByExtension) {
+ Attach();
+ ASSERT_TRUE(embedded_test_server()->Start());
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(R"({
+ "name": "Header Override Test",
+ "manifest_version": 2,
+ "version": "0.1",
+ "background": { "scripts": ["background.js"], "persistent": true },
+ "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
+ })");
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
+ chrome.webRequest.onHeadersReceived.addListener(function(details) {
+ var headers = details.responseHeaders;
+ headers.push({name: "extensionHeaderName",
+ value: "extensionHeaderValue"});
+ return {responseHeaders: headers};
+ },
+ {urls: ['<all_urls>']},
+ ['responseHeaders', 'extraHeaders', 'blocking']);
+ chrome.test.sendMessage('ready');
+ )");
+
+ ExtensionTestMessageListener listener("ready");
+ ASSERT_TRUE(LoadExtension(test_dir.UnpackedPath()));
+ EXPECT_TRUE(listener.WaitUntilSatisfied());
+
+ SendCommand("Network.enable", base::Value::Dict(), true);
+ const GURL url(
+ embedded_test_server()->GetURL("/set-cookie?cookieName=cookieValue"));
+ ui_test_utils::NavigateToURLWithDisposition(
+ browser(), url, WindowOpenDisposition::CURRENT_TAB,
+ ui_test_utils::BROWSER_TEST_NONE);
+
+ // Check that `Network.responseReceived` contains the response header added
+ // by the extension
+ base::Value::Dict response_received_result =
+ WaitForNotification("Network.responseReceived", false);
+ auto* extension_header = response_received_result.FindByDottedPath(
+ "response.headers.extensionHeaderName");
+ ASSERT_TRUE(extension_header);
+ ASSERT_EQ(*extension_header, "extensionHeaderValue");
+
+ // Check that the cookie as specified in the original headers has been set
+ auto* get_all_cookies_result =
+ SendCommand("Network.getAllCookies", base::Value::Dict(), true);
+ const base::Value::List* cookies =
+ get_all_cookies_result->FindList("cookies");
+ ASSERT_TRUE(cookies);
+ ASSERT_EQ(cookies->size(), 1u);
+ auto* cookie_name = cookies->front().FindStringKey("name");
+ ASSERT_TRUE(cookie_name);
+ ASSERT_EQ(*cookie_name, "cookieName");
+ auto* cookie_value = cookies->front().FindStringKey("value");
+ ASSERT_TRUE(cookie_value);
+ ASSERT_EQ(*cookie_value, "cookieValue");
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionDevToolsProtocolTest,
+ HeaderOverrideViaProtocolAllowedByExtension) {
+ Attach();
+ ASSERT_TRUE(embedded_test_server()->Start());
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(R"({
+ "name": "Header Override Test",
+ "manifest_version": 2,
+ "version": "0.1",
+ "background": { "scripts": ["background.js"], "persistent": true },
+ "permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
+ })");
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
+ chrome.webRequest.onHeadersReceived.addListener(function(details) {
+ var headers = details.responseHeaders;
+ headers.push({name: "extensionHeaderName",
+ value: "extensionHeaderValue"});
+ return {responseHeaders: headers};
+ },
+ {urls: ['<all_urls>']},
+ ['responseHeaders', 'extraHeaders', 'blocking']);
+ chrome.test.sendMessage('ready');
+ )");
+
+ ExtensionTestMessageListener listener("ready");
+ ASSERT_TRUE(LoadExtension(test_dir.UnpackedPath()));
+ EXPECT_TRUE(listener.WaitUntilSatisfied());
+
+ SendCommand("Network.enable", base::Value::Dict(), true);
+
+ base::Value::Dict enable_params;
+ base::Value::List patterns;
+ base::Value::Dict pattern;
+ pattern.Set("requestStage", "Response");
+ patterns.Append(std::move(pattern));
+ enable_params.Set("patterns", std::move(patterns));
+ SendCommand("Fetch.enable", std::move(enable_params), true);
+
+ const GURL url(
+ embedded_test_server()->GetURL("/set-cookie?cookieName=cookieValue"));
+ ui_test_utils::NavigateToURLWithDisposition(
+ browser(), url, WindowOpenDisposition::CURRENT_TAB,
+ ui_test_utils::BROWSER_TEST_NONE);
+ base::Value::Dict request_paused_result =
+ WaitForNotification("Fetch.requestPaused", true);
+ std::string* request_id = request_paused_result.FindString("requestId");
+
+ // Checks that `Fetch.requestPaused` contains the response headers added by
+ // the extension
+ base::Value::List* response_headers =
+ request_paused_result.FindListByDottedPath("responseHeaders");
+ auto* header_name = response_headers->back().FindStringKey("name");
+ ASSERT_TRUE(header_name);
+ ASSERT_EQ(*header_name, "extensionHeaderName");
+ auto* header_value = response_headers->back().FindStringKey("value");
+ ASSERT_TRUE(header_value);
+ ASSERT_EQ(*header_value, "extensionHeaderValue");
+
+ // Response headers are replaced by new overrides
+ base::Value::Dict params;
+ params.Set("requestId", *request_id);
+ base::Value::Dict header_1;
+ header_1.Set("name", "firstName");
+ header_1.Set("value", "firstValue");
+ base::Value::Dict header_2;
+ header_2.Set("name", "secondName");
+ header_2.Set("value", "secondValue");
+ base::Value::List headers;
+ headers.Append(std::move(header_1));
+ headers.Append(std::move(header_2));
+ params.Set("responseHeaders", std::move(headers));
+ params.Set("responseCode", 200);
+ params.Set("body", "");
+ SendCommand("Fetch.fulfillRequest", std::move(params), false);
+
+ // Check that `Network.responseReceived` contains the response headers as
+ // specified via `Fetch.fulfillRequest`
+ base::Value::Dict response_received_result =
+ WaitForNotification("Network.responseReceived", false);
+ auto* first_header =
+ response_received_result.FindByDottedPath("response.headers.firstName");
+ ASSERT_TRUE(first_header);
+ ASSERT_EQ(*first_header, "firstValue");
+ auto* second_header =
+ response_received_result.FindByDottedPath("response.headers.secondName");
+ ASSERT_TRUE(second_header);
+ ASSERT_EQ(*second_header, "secondValue");
+ ASSERT_EQ(response_received_result.FindByDottedPath("response.headers")
+ ->GetDict()
+ .size(),
+ 2u);
+
+ // Check that the cookie as specified in the original headers has been set
+ auto* get_all_cookies_result =
+ SendCommand("Network.getAllCookies", base::Value::Dict(), true);
+ const base::Value::List* cookies =
+ get_all_cookies_result->FindList("cookies");
+ ASSERT_TRUE(cookies);
+ ASSERT_EQ(cookies->size(), 1u);
+ auto* cookie_name = cookies->front().FindStringKey("name");
+ ASSERT_TRUE(cookie_name);
+ ASSERT_EQ(*cookie_name, "cookieName");
+ auto* cookie_value = cookies->front().FindStringKey("value");
+ ASSERT_TRUE(cookie_value);
+ ASSERT_EQ(*cookie_value, "cookieValue");
}
// This test times out regularly on ASAN/MSAN trybots. See
@@ -473,25 +684,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestComplex) {
// TODO(crbug.com/1177120) Re-enable test
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, DISABLED_WebRequestTypes) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(RunExtensionTest("webrequest", {.page_url = "test_types.html"}))
- << message_;
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_types")) << message_;
}
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestPublicSession) {
- ASSERT_TRUE(StartEmbeddedTestServer());
- chromeos::ScopedTestPublicSessionLoginState login_state;
- // Disable a CHECK while doing api tests.
- WebRequestPermissions::AllowAllExtensionLocationsInPublicSessionForTesting(
- true);
- ASSERT_TRUE(
- RunExtensionTest("webrequest_public_session", {.page_url = "test.html"}))
- << message_;
- WebRequestPermissions::AllowAllExtensionLocationsInPublicSessionForTesting(
- false);
-}
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-
// Test that a request to an OpenSearch description document (OSDD) generates
// an event with the expected details.
// Flaky on Windows and Mac: https://crbug.com/1218893
@@ -509,15 +704,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, MAYBE_WebRequestTestOSDD) {
search_test_utils::WaitForTemplateURLServiceToLoad(
TemplateURLServiceFactory::GetForProfile(profile()));
- ASSERT_TRUE(RunExtensionTest("webrequest", {.page_url = "test_osdd.html"}))
- << message_;
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_osdd")) << message_;
}
// Test that the webRequest events are dispatched with the expected details when
// a frame or tab is removed while a response is being received.
-// Flaky: https://crbug.com/617865
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
- DISABLED_WebRequestUnloadAfterRequest) {
+ WebRequestUnloadAfterRequest) {
ASSERT_TRUE(StartEmbeddedTestServer());
ASSERT_TRUE(
RunExtensionTest("webrequest", {.page_url = "test_unload.html?1"}))
@@ -561,41 +754,79 @@ class ExtensionWebRequestApiAuthRequiredTest
: public ExtensionWebRequestApiTest,
public testing::WithParamInterface<ProfileMode> {
protected:
- bool GetEnableIncognito() const {
+ static bool GetEnableIncognito() {
return GetParam() == ProfileMode::kIncognito;
}
+
+ static std::string FormatCustomArg(const char* test_name) {
+ static constexpr char custom_arg_format[] =
+ R"({"testName": "%s", "runInIncognito": %s})";
+
+ return base::StringPrintf(custom_arg_format, test_name,
+ GetEnableIncognito() ? "true" : "false");
+ }
};
-// Note: this is flaky on multiple platforms (crbug.com/1003598).
IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiAuthRequiredTest,
- DISABLED_WebRequestAuthRequired) {
+ WebRequestAuthRequired) {
CancelLoginDialog login_dialog_helper;
ASSERT_TRUE(StartEmbeddedTestServer());
- // Pass "debug" as a custom arg to debug test flakiness.
- ASSERT_TRUE(RunExtensionTest("webrequest",
- {.page_url = "test_auth_required.html",
- .custom_arg = R"({"debug": true})",
- .open_in_incognito = GetEnableIncognito()},
- {.allow_in_incognito = GetEnableIncognito()}))
+ // If running in incognito, create an incognito browser so the test
+ // framework can create an incognito window.
+ const bool incognito = GetEnableIncognito();
+ if (incognito)
+ CreateIncognitoBrowser(profile());
+
+ ASSERT_TRUE(RunExtensionTest(
+ "webrequest/test_auth_required",
+ {.custom_arg = FormatCustomArg("authRequiredNonBlocking").c_str()},
+ {.allow_in_incognito = incognito}))
+ << message_;
+ ASSERT_TRUE(RunExtensionTest(
+ "webrequest/test_auth_required",
+ {.custom_arg = FormatCustomArg("authRequiredSyncNoAction").c_str()},
+ {.allow_in_incognito = incognito}))
+ << message_;
+ ASSERT_TRUE(RunExtensionTest(
+ "webrequest/test_auth_required",
+ {.custom_arg = FormatCustomArg("authRequiredSyncCancelAuth").c_str()},
+ {.allow_in_incognito = incognito}))
+ << message_;
+ ASSERT_TRUE(RunExtensionTest(
+ "webrequest/test_auth_required",
+ {.custom_arg = FormatCustomArg("authRequiredSyncSetAuth").c_str()},
+ {.allow_in_incognito = incognito}))
<< message_;
}
-// Note: this is flaky on multiple platforms (crbug.com/1003598). Temporarily
-// enabled to find flakiness cause.
IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiAuthRequiredTest,
- DISABLED_WebRequestAuthRequiredAsync) {
+ WebRequestAuthRequiredAsync) {
CancelLoginDialog login_dialog_helper;
ASSERT_TRUE(StartEmbeddedTestServer());
- // Pass "debug" as a custom arg to debug test flakiness.
- ASSERT_TRUE(RunExtensionTest("webrequest",
- {.page_url = "test_auth_required_async.html",
- .custom_arg = R"({"debug": true})",
- .open_in_incognito = GetEnableIncognito()},
- {.allow_in_incognito = GetEnableIncognito()}))
+ // If running in incognito, create an incognito browser so the tests
+ // run in an incognito window.
+ const bool incognito = GetEnableIncognito();
+ if (incognito)
+ CreateIncognitoBrowser(profile());
+
+ ASSERT_TRUE(RunExtensionTest(
+ "webrequest/test_auth_required_async",
+ {.custom_arg = FormatCustomArg("authRequiredAsyncNoAction").c_str()},
+ {.allow_in_incognito = incognito}))
+ << message_;
+ ASSERT_TRUE(RunExtensionTest(
+ "webrequest/test_auth_required_async",
+ {.custom_arg = FormatCustomArg("authRequiredAsyncCancelAuth").c_str()},
+ {.allow_in_incognito = incognito}))
+ << message_;
+ ASSERT_TRUE(RunExtensionTest(
+ "webrequest/test_auth_required_async",
+ {.custom_arg = FormatCustomArg("authRequiredAsyncSetAuth").c_str()},
+ {.allow_in_incognito = incognito}))
<< message_;
}
@@ -605,11 +836,16 @@ IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiAuthRequiredTest,
DISABLED_WebRequestAuthRequiredParallel) {
CancelLoginDialog login_dialog_helper;
+ const bool incognito = GetEnableIncognito();
+ if (incognito)
+ CreateIncognitoBrowser(profile());
+
+ const char* const custom_arg = incognito ? R"({"runInIncognito": true})"
+ : R"({"runInIncognito": false})";
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(RunExtensionTest("webrequest",
- {.page_url = "test_auth_required_parallel.html",
- .open_in_incognito = GetEnableIncognito()},
- {.allow_in_incognito = GetEnableIncognito()}))
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_auth_required_parallel",
+ {.custom_arg = custom_arg},
+ {.allow_in_incognito = incognito}))
<< message_;
}
@@ -620,35 +856,42 @@ INSTANTIATE_TEST_SUITE_P(Incognito,
ExtensionWebRequestApiAuthRequiredTest,
::testing::Values(ProfileMode::kIncognito));
+IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestBlocking) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_blocking",
+ {.custom_arg = R"({"testSuite": "normal"})"}))
+ << message_;
+}
+
// This test times out regularly on win_rel trybots. See http://crbug.com/122178
// Also on Linux/ChromiumOS debug, ASAN and MSAN builds.
// https://crbug.com/670415
+// Slower and flaky tests should be isolated in the "slow" group of tests in
+// the JS file. This prevents losing test coverage for those tests that are
+// not causing timeouts and flakes.
#if BUILDFLAG(IS_WIN) || !defined(NDEBUG) || defined(ADDRESS_SANITIZER) || \
defined(MEMORY_SANITIZER)
-#define MAYBE_WebRequestBlocking DISABLED_WebRequestBlocking
+#define MAYBE_WebRequestBlockingSlow DISABLED_WebRequestBlockingSlow
#else
-#define MAYBE_WebRequestBlocking WebRequestBlocking
+#define MAYBE_WebRequestBlockingSlow WebRequestBlockingSlow
#endif
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, MAYBE_WebRequestBlocking) {
+IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+ MAYBE_WebRequestBlockingSlow) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(
- RunExtensionTest("webrequest", {.page_url = "test_blocking.html"}))
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_blocking",
+ {.custom_arg = R"({"testSuite": "slow"})"}))
<< message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
WebRequestBlockingSetCookieHeader) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(
- RunExtensionTest("webrequest", {.page_url = "test_blocking_cookie.html"}))
- << message_;
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_blocking_cookie")) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestExtraHeaders) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(
- RunExtensionTest("webrequest", {.page_url = "test_extra_headers.html"}))
- << message_;
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_extra_headers")) << message_;
}
// Flaky on all platforms: https://crbug.com/1003661
@@ -657,38 +900,32 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
CancelLoginDialog login_dialog_helper;
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(RunExtensionTest("webrequest",
- {.page_url = "test_extra_headers_auth.html"}))
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_extra_headers_auth"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestChangeCSPHeaders) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(RunExtensionTest("webrequest",
- {.page_url = "test_change_csp_headers.html"}))
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_change_csp_headers"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
WebRequestCORSWithExtraHeaders) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(RunExtensionTest("webrequest", {.page_url = "test_cors.html"}))
- << message_;
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_cors")) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestRedirects) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(
- RunExtensionTest("webrequest", {.page_url = "test_redirects.html"}))
- << message_;
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_redirects")) << message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
WebRequestRedirectsWithExtraHeaders) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(RunExtensionTest("webrequest",
- {.page_url = "test_redirects.html",
- .custom_arg = R"({"useExtraHeaders": true})"}))
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_redirects",
+ {.custom_arg = R"({"useExtraHeaders": true})"}))
<< message_;
}
@@ -711,34 +948,30 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
std::string config_string;
base::JSONWriter::Write(custom_args, &config_string);
- ASSERT_TRUE(RunExtensionTest("webrequest",
- {.page_url = "test_redirects_from_secure.html",
- .custom_arg = config_string.c_str()}))
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_redirects_from_secure",
+ {.custom_arg = config_string.c_str()}))
<< message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
WebRequestSubresourceRedirects) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(RunExtensionTest("webrequest",
- {.page_url = "test_subresource_redirects.html"}))
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_subresource_redirects"))
<< message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
WebRequestSubresourceRedirectsWithExtraHeaders) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(RunExtensionTest("webrequest",
- {.page_url = "test_subresource_redirects.html",
- .custom_arg = R"({"useExtraHeaders": true})"}))
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_subresource_redirects",
+ {.custom_arg = R"({"useExtraHeaders": true})"}))
<< message_;
}
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestNewTab) {
ASSERT_TRUE(StartEmbeddedTestServer());
// Wait for the extension to set itself up and return control to us.
- ASSERT_TRUE(RunExtensionTest("webrequest", {.page_url = "test_newTab.html"}))
- << message_;
+ ASSERT_TRUE(RunExtensionTest("webrequest/test_new_tab")) << message_;
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(content::WaitForLoadStop(tab));
@@ -774,24 +1007,28 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestNewTab) {
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}
-// This test times out regularly on MSAN trybots. See https://crbug.com/733395.
-// Also flaky. See https://crbug.com/846555.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
- DISABLED_WebRequestDeclarative1) {
+IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestDeclarative1) {
ASSERT_TRUE(StartEmbeddedTestServer());
- ASSERT_TRUE(
- RunExtensionTest("webrequest", {.page_url = "test_declarative1.html"}))
+ ASSERT_TRUE(RunExtensionTest("webrequest",
+ {.page_url = "test_declarative1.html",
+ .custom_arg = R"({"testSuite": "normal"})"}))
<< message_;
}
-// This test times out regularly on MSAN trybots. See https://crbug.com/733395.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_WebRequestDeclarative2 DISABLED_WebRequestDeclarative2
-#else
-#define MAYBE_WebRequestDeclarative2 WebRequestDeclarative2
-#endif
+// This test fixture runs all of the broken and flaky tests. It's disabled
+// until these tests are fixed and moved to the set of tests that aren't
+// broken or flaky. Should tests become flaky, they can be moved here.
+// See https://crbug.com/846555.
IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
- MAYBE_WebRequestDeclarative2) {
+ DISABLED_WebRequestDeclarative1Broken) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ ASSERT_TRUE(RunExtensionTest("webrequest",
+ {.page_url = "test_declarative1.html",
+ .custom_arg = R"({"testSuite": "broken"})"}))
+ << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestDeclarative2) {
ASSERT_TRUE(StartEmbeddedTestServer());
ASSERT_TRUE(
RunExtensionTest("webrequest", {.page_url = "test_declarative2.html"}))
@@ -803,7 +1040,8 @@ void ExtensionWebRequestApiTest::RunPermissionTest(
bool load_extension_with_incognito_permission,
bool wait_for_extension_loaded_in_incognito,
const char* expected_content_regular_window,
- const char* exptected_content_incognito_window) {
+ const char* exptected_content_incognito_window,
+ ContextType context_type) {
ResultCatcher catcher;
catcher.RestrictToBrowserContext(browser()->profile());
ResultCatcher catcher_incognito;
@@ -816,7 +1054,8 @@ void ExtensionWebRequestApiTest::RunPermissionTest(
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("webrequest_permissions")
.AppendASCII(extension_directory),
- {.allow_in_incognito = load_extension_with_incognito_permission}));
+ {.allow_in_incognito = load_extension_with_incognito_permission,
+ .context_type = context_type}));
// Test that navigation in regular window is properly redirected.
EXPECT_TRUE(listener.WaitUntilSatisfied());
@@ -855,33 +1094,55 @@ void ExtensionWebRequestApiTest::RunPermissionTest(
EXPECT_EQ(exptected_content_incognito_window, body);
}
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+class ExtensionWebRequestApiTestWithContextType
+ : public ExtensionWebRequestApiTest,
+ public testing::WithParamInterface<ContextType> {
+ public:
+ ExtensionWebRequestApiTestWithContextType()
+ : ExtensionWebRequestApiTest(GetParam()) {}
+ ExtensionWebRequestApiTestWithContextType(
+ const ExtensionWebRequestApiTestWithContextType&) = delete;
+ ExtensionWebRequestApiTestWithContextType& operator=(
+ const ExtensionWebRequestApiTestWithContextType&) = delete;
+ ~ExtensionWebRequestApiTestWithContextType() override = default;
+};
+
+INSTANTIATE_TEST_SUITE_P(PersistentBackground,
+ ExtensionWebRequestApiTestWithContextType,
+ ::testing::Values(ContextType::kPersistentBackground));
+
+INSTANTIATE_TEST_SUITE_P(ServiceWorker,
+ ExtensionWebRequestApiTestWithContextType,
+ ::testing::Values(ContextType::kServiceWorker));
+
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
WebRequestDeclarativePermissionSpanning1) {
// Test spanning with incognito permission.
ASSERT_TRUE(StartEmbeddedTestServer());
- RunPermissionTest("spanning", true, false, "redirected1", "redirected1");
+ RunPermissionTest("spanning", true, false, "redirected1", "redirected1",
+ GetParam());
}
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
WebRequestDeclarativePermissionSpanning2) {
// Test spanning without incognito permission.
ASSERT_TRUE(StartEmbeddedTestServer());
- RunPermissionTest("spanning", false, false, "redirected1", "");
+ RunPermissionTest("spanning", false, false, "redirected1", "", GetParam());
}
-
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
WebRequestDeclarativePermissionSplit1) {
// Test split with incognito permission.
ASSERT_TRUE(StartEmbeddedTestServer());
- RunPermissionTest("split", true, true, "redirected1", "redirected2");
+ RunPermissionTest("split", true, true, "redirected1", "redirected2",
+ GetParam());
}
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
WebRequestDeclarativePermissionSplit2) {
// Test split without incognito permission.
ASSERT_TRUE(StartEmbeddedTestServer());
- RunPermissionTest("split", false, false, "redirected1", "");
+ RunPermissionTest("split", false, false, "redirected1", "", GetParam());
}
// TODO(crbug.com/238179): Cure these flaky tests.
@@ -901,7 +1162,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, DISABLED_PostData2) {
<< message_;
}
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
DeclarativeSendMessage) {
ASSERT_TRUE(StartEmbeddedTestServer());
ASSERT_TRUE(RunExtensionTest("webrequest_sendmessage")) << message_;
@@ -910,7 +1171,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
// 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
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, IncognitoSplitModeReload) {
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
+ IncognitoSplitModeReload) {
ASSERT_TRUE(StartEmbeddedTestServer());
// Wait for rules to be set up.
ExtensionTestMessageListener listener("done");
@@ -936,7 +1198,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, IncognitoSplitModeReload) {
EXPECT_TRUE(listener_incognito2.WaitUntilSatisfied());
}
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, ExtensionRequests) {
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
+ ExtensionRequests) {
ASSERT_TRUE(StartEmbeddedTestServer());
ExtensionTestMessageListener listener_main1("web_request_status1",
ReplyBehavior::kWillReply);
@@ -953,10 +1216,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, ExtensionRequests) {
EXPECT_TRUE(listener_main2.WaitUntilSatisfied());
// Perform some network activity in an app and another extension.
+ ASSERT_TRUE(
+ LoadExtension(test_data_dir_.AppendASCII("webrequest_extensions/app"),
+ {.context_type = ContextType::kFromManifest}));
ASSERT_TRUE(LoadExtension(
- test_data_dir_.AppendASCII("webrequest_extensions/app")));
- ASSERT_TRUE(LoadExtension(
- test_data_dir_.AppendASCII("webrequest_extensions/extension")));
+ test_data_dir_.AppendASCII("webrequest_extensions/extension"),
+ {.context_type = ContextType::kFromManifest}));
EXPECT_TRUE(listener_app.WaitUntilSatisfied());
EXPECT_TRUE(listener_extension.WaitUntilSatisfied());
@@ -1041,7 +1306,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, HostedAppRequest) {
}
// Tests that WebRequest works with runtime host permissions.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
WebRequestWithWithheldPermissions) {
content::SetupCrossSiteRedirector(embedded_test_server());
ASSERT_TRUE(embedded_test_server()->Start());
@@ -1162,7 +1427,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
// Test that extensions with granted runtime host permissions to a tab can
// intercept cross-origin requests from that tab.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
WebRequestWithheldPermissionsCrossOriginRequests) {
content::SetupCrossSiteRedirector(embedded_test_server());
ASSERT_TRUE(embedded_test_server()->Start());
@@ -1212,7 +1477,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
// Tests behavior when an extension has withheld access to a request's URL, but
// not the initiator's (tab's) URL. Regression test for
// https://crbug.com/891586.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
WithheldHostPermissionsForCrossOriginWithoutInitiator) {
content::SetupCrossSiteRedirector(embedded_test_server());
ASSERT_TRUE(embedded_test_server()->Start());
@@ -1226,16 +1491,16 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
"name": "Web Request Withheld Hosts",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["*://b.com:*/*", "webRequest"]
})");
test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
- R"(window.webRequestCount = 0;
- window.requestedHostnames = [];
+ R"(self.webRequestCount = 0;
+ self.requestedHostnames = [];
chrome.webRequest.onBeforeRequest.addListener(function(details) {
- ++window.webRequestCount;
- window.requestedHostnames.push((new URL(details.url)).hostname);
+ ++self.webRequestCount;
+ self.requestedHostnames.push((new URL(details.url)).hostname);
}, {urls:['<all_urls>']});
chrome.test.sendMessage('ready');)");
@@ -1278,7 +1543,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
// Verify that requests to clientsX.google.com are protected properly.
// First test requests from a standard renderer and then a request from the
// browser process.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
WebRequestClientsGoogleComProtection) {
ASSERT_TRUE(embedded_test_server()->Start());
@@ -1292,11 +1557,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
auto get_clients_google_request_count = [this, extension]() {
return GetCountFromBackgroundPage(extension, profile(),
- "window.clientsGoogleWebRequestCount");
+ "self.clientsGoogleWebRequestCount");
};
auto get_yahoo_request_count = [this, extension]() {
return GetCountFromBackgroundPage(extension, profile(),
- "window.yahooWebRequestCount");
+ "self.yahooWebRequestCount");
};
EXPECT_EQ(0, get_clients_google_request_count());
@@ -1370,7 +1635,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
}
// Verify that requests for PAC scripts are protected properly.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
WebRequestPacRequestProtection) {
ASSERT_TRUE(embedded_test_server()->Start());
@@ -1400,11 +1665,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
// The extension should not have seen the PAC request.
EXPECT_EQ(0, GetCountFromBackgroundPage(extension, profile(),
- "window.pacRequestCount"));
+ "self.pacRequestCount"));
// The extension should have seen the request for the main frame.
EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
- "window.title2RequestCount"));
+ "self.title2RequestCount"));
// The PAC request should have succeeded, as should the subsequent URL
// request.
@@ -1418,7 +1683,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
// Checks that the Dice response header is protected for Gaia URLs, but not
// other URLs.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
WebRequestDiceHeaderProtection) {
// Load an extension that registers a listener for webRequest events, and
// wait until it is initialized.
@@ -1497,9 +1762,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
// Check that the Dice header cannot be read by the extension.
EXPECT_EQ(0, GetCountFromBackgroundPage(extension, profile(),
- "window.diceResponseHeaderCount"));
+ "self.diceResponseHeaderCount"));
EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
- "window.controlResponseHeaderCount"));
+ "self.controlResponseHeaderCount"));
// Navigate to a non-Gaia URL intercepted by the extension.
test_webcontents_observer.Clear();
@@ -1517,9 +1782,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
// Check that the Dice header can be read by the extension.
EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
- "window.diceResponseHeaderCount"));
+ "self.diceResponseHeaderCount"));
EXPECT_EQ(2, GetCountFromBackgroundPage(extension, profile(),
- "window.controlResponseHeaderCount"));
+ "self.controlResponseHeaderCount"));
}
// Test that the webRequest events are dispatched for the WebSocket handshake
@@ -1617,7 +1882,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiWebTransportTest, ServiceWorker) {
}
// Test behavior when intercepting requests from a browser-initiated url fetch.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
WebRequestURLLoaderInterception) {
// Create an extension that intercepts (and blocks) requests to example.com.
TestExtensionDir test_dir;
@@ -1628,7 +1893,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
"version": "0.1",
"permissions": ["webRequest", "webRequestBlocking", "*://*/*"],
"manifest_version": 2,
- "background": { "scripts": ["background.js"] }
+ "background": { "scripts": ["background.js"], "persistent": true }
})");
test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
R"(chrome.webRequest.onBeforeRequest.addListener(
@@ -1784,7 +2049,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
// Test that extensions need host permissions to both the request url and
// initiator to intercept a request.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, InitiatorAccessRequired) {
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
+ InitiatorAccessRequired) {
ASSERT_TRUE(StartEmbeddedTestServer());
ExtensionTestMessageListener listener("ready");
@@ -1830,11 +2096,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, InitiatorAccessRequired) {
// Run a script in the extensions background page to ensure that we have
// received the initiator message from the extension.
- ASSERT_EQ(
- std::to_string(expected_requests_intercepted_count),
- ExecuteScriptInBackgroundPage(extension->id(),
- "window.domAutomationController.send("
- "requestsIntercepted.toString());"));
+ ASSERT_EQ(expected_requests_intercepted_count,
+ GetCountFromBackgroundPage(extension, profile(),
+ "self.requestsIntercepted"));
if (testcase.expected_initiator.empty()) {
EXPECT_FALSE(initiator_listener.was_satisfied());
@@ -1947,15 +2211,19 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
}
// Test fixture which sets a custom NTP Page.
-class NTPInterceptionWebRequestAPITest : public ExtensionApiTest {
+class NTPInterceptionWebRequestAPITest
+ : public ExtensionApiTest,
+ public testing::WithParamInterface<ContextType> {
public:
NTPInterceptionWebRequestAPITest()
- : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
+ : ExtensionApiTest(GetParam()),
+ https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
NTPInterceptionWebRequestAPITest(const NTPInterceptionWebRequestAPITest&) =
delete;
NTPInterceptionWebRequestAPITest& operator=(
const NTPInterceptionWebRequestAPITest&) = delete;
+ ~NTPInterceptionWebRequestAPITest() override = default;
// ExtensionApiTest override:
void SetUpOnMainThread() override {
@@ -1978,9 +2246,17 @@ class NTPInterceptionWebRequestAPITest : public ExtensionApiTest {
net::EmbeddedTestServer https_test_server_;
};
+INSTANTIATE_TEST_SUITE_P(PersistentBackground,
+ NTPInterceptionWebRequestAPITest,
+ ::testing::Values(ContextType::kPersistentBackground));
+
+INSTANTIATE_TEST_SUITE_P(ServiceWorker,
+ NTPInterceptionWebRequestAPITest,
+ ::testing::Values(ContextType::kServiceWorker));
+
// Ensures that requests made by the NTP Instant renderer are hidden from the
// Web Request API. Regression test for crbug.com/797461.
-IN_PROC_BROWSER_TEST_F(NTPInterceptionWebRequestAPITest,
+IN_PROC_BROWSER_TEST_P(NTPInterceptionWebRequestAPITest,
NTPRendererRequestsHidden) {
// Loads an extension which tries to intercept requests to
// "fake_ntp_script.js", which will be loaded as part of the NTP renderer.
@@ -1998,12 +2274,11 @@ IN_PROC_BROWSER_TEST_F(NTPInterceptionWebRequestAPITest,
// Returns true if the given extension was able to intercept the request to
// "fake_ntp_script.js".
auto was_script_request_intercepted =
- [this](const std::string& extension_id) {
- const std::string result = ExecuteScriptInBackgroundPage(
- extension_id, "getAndResetRequestIntercepted();");
- EXPECT_TRUE(result == "true" || result == "false")
- << "Unexpected result " << result;
- return result == "true";
+ [this](const ExtensionId& extension_id) {
+ const absl::optional<bool> result = ExecuteScriptAndReturnBool(
+ extension_id, profile(), "getAndResetRequestIntercepted();");
+ DCHECK(result);
+ return *result;
};
// Returns true if the given |web_contents| has window.scriptExecuted set to
@@ -2041,15 +2316,17 @@ IN_PROC_BROWSER_TEST_F(NTPInterceptionWebRequestAPITest,
// the WebUI NTP can't be intercepted by extensions.
class WebUiNtpInterceptionWebRequestAPITest
: public ExtensionApiTest,
- public OneGoogleBarServiceObserver {
+ public OneGoogleBarServiceObserver,
+ public testing::WithParamInterface<ContextType> {
public:
WebUiNtpInterceptionWebRequestAPITest()
- : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
-
+ : ExtensionApiTest(GetParam()),
+ https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
WebUiNtpInterceptionWebRequestAPITest(
const WebUiNtpInterceptionWebRequestAPITest&) = delete;
WebUiNtpInterceptionWebRequestAPITest& operator=(
const WebUiNtpInterceptionWebRequestAPITest&) = delete;
+ ~WebUiNtpInterceptionWebRequestAPITest() override = default;
// ExtensionApiTest override:
void SetUp() override {
@@ -2122,7 +2399,15 @@ class WebUiNtpInterceptionWebRequestAPITest
base::Lock lock_;
};
-IN_PROC_BROWSER_TEST_F(WebUiNtpInterceptionWebRequestAPITest,
+INSTANTIATE_TEST_SUITE_P(PersistentBackground,
+ WebUiNtpInterceptionWebRequestAPITest,
+ ::testing::Values(ContextType::kPersistentBackground));
+
+INSTANTIATE_TEST_SUITE_P(ServiceWorker,
+ WebUiNtpInterceptionWebRequestAPITest,
+ ::testing::Values(ContextType::kServiceWorker));
+
+IN_PROC_BROWSER_TEST_P(WebUiNtpInterceptionWebRequestAPITest,
OneGoogleBarRequestsHidden) {
// Loads an extension which tries to intercept requests to the OneGoogleBar.
ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
@@ -2139,12 +2424,11 @@ IN_PROC_BROWSER_TEST_F(WebUiNtpInterceptionWebRequestAPITest,
// Returns true if the given extension was able to intercept the request to
// |one_google_bar_url()|.
auto was_script_request_intercepted =
- [this](const std::string& extension_id) {
- const std::string result = ExecuteScriptInBackgroundPage(
- extension_id, "getAndResetRequestIntercepted();");
- EXPECT_TRUE(result == "true" || result == "false")
- << "Unexpected result " << result;
- return result == "true";
+ [this](const ExtensionId& extension_id) {
+ absl::optional<bool> result = ExecuteScriptAndReturnBool(
+ extension_id, profile(), "getAndResetRequestIntercepted();");
+ DCHECK(result);
+ return *result;
};
ASSERT_FALSE(GetAndResetOneGoogleBarRequestSeen());
@@ -2175,9 +2459,29 @@ IN_PROC_BROWSER_TEST_F(DevToolsFrontendInWebRequestApiTest, HiddenRequests) {
<< message_;
}
+class WebRequestApiTestWithManagementPolicy
+ : public ExtensionApiTestWithManagementPolicy,
+ public testing::WithParamInterface<ContextType> {
+ public:
+ WebRequestApiTestWithManagementPolicy()
+ : ExtensionApiTestWithManagementPolicy(GetParam()) {}
+ ~WebRequestApiTestWithManagementPolicy() override = default;
+ WebRequestApiTestWithManagementPolicy(
+ const WebRequestApiTestWithManagementPolicy&) = delete;
+ WebRequestApiTestWithManagementPolicy& operator=(
+ const WebRequestApiTestWithManagementPolicy&) = delete;
+};
+
+INSTANTIATE_TEST_SUITE_P(PersistentBackground,
+ WebRequestApiTestWithManagementPolicy,
+ ::testing::Values(ContextType::kPersistentBackground));
+INSTANTIATE_TEST_SUITE_P(ServiceWorker,
+ WebRequestApiTestWithManagementPolicy,
+ ::testing::Values(ContextType::kServiceWorker));
+
// Tests that the webRequest events aren't dispatched when the request initiator
// is protected by policy.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy,
+IN_PROC_BROWSER_TEST_P(WebRequestApiTestWithManagementPolicy,
InitiatorProtectedByPolicy) {
// We expect that no request will be hidden or modification blocked. This
// means that the request to example.com will be seen by the extension.
@@ -2207,7 +2511,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy,
// The number of requests initiated by a protected origin is tracked in
// the extension's background page under this variable name.
- const std::string request_counter_name = "window.protectedOriginCount";
+ const std::string request_counter_name = "self.protectedOriginCount";
EXPECT_EQ(0, GetCountFromBackgroundPage(extension, profile(),
request_counter_name));
@@ -2256,7 +2560,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy,
// Tests that the webRequest events aren't dispatched when the URL of the
// request is protected by policy.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy,
+IN_PROC_BROWSER_TEST_P(WebRequestApiTestWithManagementPolicy,
UrlProtectedByPolicy) {
// Host protected by policy.
const std::string protected_domain = "example.com";
@@ -2309,7 +2613,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy,
// navigation. This replicates most of the tests from
// WebRequestWithWithheldPermissions with a protected host. Granting a tab
// specific permission shouldn't bypass our policy.
-IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy,
+IN_PROC_BROWSER_TEST_P(WebRequestApiTestWithManagementPolicy,
WebRequestProtectedByPolicy) {
// Host protected by policy.
const std::string protected_domain = "example.com";
@@ -2374,7 +2678,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTestWithManagementPolicy,
// A test fixture which mocks the Time::Now() function to ensure that the
// default clock returns monotonically increasing time.
-class ExtensionWebRequestMockedClockTest : public ExtensionWebRequestApiTest {
+class ExtensionWebRequestMockedClockTest
+ : public ExtensionWebRequestApiTestWithContextType {
public:
ExtensionWebRequestMockedClockTest()
: scoped_time_clock_override_(&ExtensionWebRequestMockedClockTest::Now,
@@ -2396,9 +2701,16 @@ class ExtensionWebRequestMockedClockTest : public ExtensionWebRequestApiTest {
base::subtle::ScopedTimeClockOverrides scoped_time_clock_override_;
};
+INSTANTIATE_TEST_SUITE_P(PersistentBackground,
+ ExtensionWebRequestMockedClockTest,
+ ::testing::Values(ContextType::kPersistentBackground));
+INSTANTIATE_TEST_SUITE_P(ServiceWorker,
+ ExtensionWebRequestMockedClockTest,
+ ::testing::Values(ContextType::kServiceWorker));
+
// Tests that we correctly dispatch the OnActionIgnored event on an extension
// if the extension's proposed redirect is ignored.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestMockedClockTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestMockedClockTest,
OnActionIgnored_Redirect) {
ASSERT_TRUE(StartEmbeddedTestServer());
@@ -2480,25 +2792,26 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestMockedClockTest,
}
// Regression test for http://crbug.com/1074282.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, StaleHeadersAfterRedirect) {
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
+ StaleHeadersAfterRedirect) {
TestExtensionDir test_dir;
test_dir.WriteManifest(R"({
"name": "Web Request Stale Headers Test",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
- window.locationCount = 0;
- window.requestCount = 0;
+ self.locationCount = 0;
+ self.requestCount = 0;
chrome.test.sendMessage('ready', function(reply) {
chrome.webRequest.onResponseStarted.addListener(function(details) {
- window.requestCount++;
+ self.requestCount++;
var headers = details.responseHeaders;
for (var i = 0; i < headers.length; i++) {
if (headers[i].name === 'Location') {
- window.locationCount++;
+ self.locationCount++;
}
}
},
@@ -2553,14 +2866,14 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, StaleHeadersAfterRedirect) {
embedded_test_server()->host_port_pair().host(),
embedded_test_server()->port(), "redirect-and-wait");
EXPECT_EQ(
- GetCountFromBackgroundPage(extension, profile(), "window.requestCount"),
- 1);
+ GetCountFromBackgroundPage(extension, profile(), "self.requestCount"), 1);
EXPECT_EQ(
- GetCountFromBackgroundPage(extension, profile(), "window.locationCount"),
+ GetCountFromBackgroundPage(extension, profile(), "self.locationCount"),
0);
}
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, ChangeHeaderUMAs) {
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
+ ChangeHeaderUMAs) {
using RequestHeaderType =
extension_web_request_api_helpers::RequestHeaderType;
using ResponseHeaderType =
@@ -2573,7 +2886,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, ChangeHeaderUMAs) {
"name": "Web Request UMA Test",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
@@ -2656,7 +2969,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, ChangeHeaderUMAs) {
ResponseHeaderType::kNone, 1);
}
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, RemoveHeaderUMAs) {
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
+ RemoveHeaderUMAs) {
using RequestHeaderType =
extension_web_request_api_helpers::RequestHeaderType;
using ResponseHeaderType =
@@ -2669,7 +2983,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, RemoveHeaderUMAs) {
"name": "Web Request UMA Test",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
@@ -2727,12 +3041,29 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, RemoveHeaderUMAs) {
ResponseHeaderType::kNone, 1);
}
-// The parameter is for opt_extraInfoSpec passed to addEventListener.
-// 'blocking' and 'requestHeaders' if it's false, and 'extraHeaders' in addition
-// to them if it's true.
-class ServiceWorkerWebRequestApiTest : public testing::WithParamInterface<bool>,
- public ExtensionApiTest {
+struct SWTestParams {
+ SWTestParams(bool extra_info_spec, ContextType context_type)
+ : extra_info_spec(extra_info_spec), context_type(context_type) {}
+
+ // This parameter is for opt_extraInfoSpec passed to addEventListener.
+ // 'blocking' and 'requestHeaders' if it's false, and 'extraHeaders' in
+ // addition to them if it's true.
+ bool extra_info_spec;
+ ContextType context_type;
+};
+
+class ServiceWorkerWebRequestApiTest
+ : public testing::WithParamInterface<SWTestParams>,
+ public ExtensionApiTest {
public:
+ ServiceWorkerWebRequestApiTest()
+ : ExtensionApiTest(GetParam().context_type) {}
+ ~ServiceWorkerWebRequestApiTest() override = default;
+ ServiceWorkerWebRequestApiTest(const ServiceWorkerWebRequestApiTest&) =
+ delete;
+ ServiceWorkerWebRequestApiTest& operator=(
+ const ServiceWorkerWebRequestApiTest&) = delete;
+
// The options passed as opt_extraInfoSpec to addEventListener.
enum class ExtraInfoSpec {
// 'blocking', 'requestHeaders'
@@ -2742,7 +3073,8 @@ class ServiceWorkerWebRequestApiTest : public testing::WithParamInterface<bool>,
};
static ExtraInfoSpec GetExtraInfoSpec() {
- return GetParam() ? ExtraInfoSpec::kExtraHeaders : ExtraInfoSpec::kDefault;
+ return GetParam().extra_info_spec ? ExtraInfoSpec::kExtraHeaders
+ : ExtraInfoSpec::kDefault;
}
void InstallRequestHeaderModifyingExtension() {
@@ -2751,7 +3083,7 @@ class ServiceWorkerWebRequestApiTest : public testing::WithParamInterface<bool>,
"name": "Web Request Header Modifying Extension",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
@@ -2824,9 +3156,25 @@ class ServiceWorkerWebRequestApiTest : public testing::WithParamInterface<bool>,
}
};
-INSTANTIATE_TEST_SUITE_P(All,
- ServiceWorkerWebRequestApiTest,
- ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(
+ PersistentBackgroundWithExtraHeaders,
+ ServiceWorkerWebRequestApiTest,
+ ::testing::Values(SWTestParams(true, ContextType::kPersistentBackground)));
+
+INSTANTIATE_TEST_SUITE_P(
+ PersistentBackground,
+ ServiceWorkerWebRequestApiTest,
+ ::testing::Values(SWTestParams(false, ContextType::kPersistentBackground)));
+
+INSTANTIATE_TEST_SUITE_P(
+ ServiceWorkerWithExtraHeaders,
+ ServiceWorkerWebRequestApiTest,
+ ::testing::Values(SWTestParams(true, ContextType::kServiceWorker)));
+
+INSTANTIATE_TEST_SUITE_P(
+ ServiceWorker,
+ ServiceWorkerWebRequestApiTest,
+ ::testing::Values(SWTestParams(false, ContextType::kServiceWorker)));
IN_PROC_BROWSER_TEST_P(ServiceWorkerWebRequestApiTest, ServiceWorkerFetch) {
RunServiceWorkerFetchTest("fetch_event_respond_with_fetch.js");
@@ -3148,7 +3496,7 @@ IN_PROC_BROWSER_TEST_P(ServiceWorkerWebRequestApiTest,
// 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.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
Initiator_SpanningIncognito) {
embedded_test_server()->ServeFilesFromSourceDirectory("chrome/test/data");
ASSERT_TRUE(embedded_test_server()->Start());
@@ -3158,7 +3506,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
LoadExtension(test_data_dir_.AppendASCII("webrequest")
.AppendASCII("initiator_spanning"));
ASSERT_TRUE(extension);
- const std::string extension_id = extension->id();
+ // Save the ID because enabling the extension for incognito mode will
+ // invalidate |extension|.
+ const ExtensionId extension_id = extension->id();
EXPECT_TRUE(ready_listener.WaitUntilSatisfied());
Browser* incognito_browser = CreateIncognitoBrowser(profile());
@@ -3169,21 +3519,26 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
GURL url = embedded_test_server()->GetURL("google.com", "/iframe.html");
const std::string url_origin = url::Origin::Create(url).Serialize();
- const char* kScript = R"(
- domAutomationController.send(JSON.stringify(window.initiators));
- window.initiators = [];
+ static constexpr char kScript[] = R"(
+ chrome.test.sendScriptResult(JSON.stringify(self.initiators));
+ self.initiators = [];
)";
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
- EXPECT_EQ(base::StringPrintf("[\"%s\"]", url_origin.c_str()),
- ExecuteScriptInBackgroundPage(extension_id, kScript));
+ absl::optional<std::string> result =
+ ExecuteScriptAndReturnString(extension_id, profile(), kScript);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(base::StringPrintf("[\"%s\"]", url_origin.c_str()), *result);
// The extension isn't enabled in incognito. Se we shouldn't intercept the
// request to |url|.
ASSERT_TRUE(ui_test_utils::NavigateToURL(incognito_browser, url));
- EXPECT_EQ("[]", ExecuteScriptInBackgroundPage(extension_id, kScript));
+ result = ExecuteScriptAndReturnString(extension_id, profile(), kScript);
+ ASSERT_TRUE(result);
+ EXPECT_EQ("[]", *result);
// Now enable the extension in incognito.
+ extension = nullptr;
ready_listener.Reset();
extensions::util::SetIsIncognitoEnabled(extension_id, profile(),
true /* enabled */);
@@ -3191,14 +3546,16 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
// Now we should be able to intercept the incognito request.
ASSERT_TRUE(ui_test_utils::NavigateToURL(incognito_browser, url));
- EXPECT_EQ(base::StringPrintf("[\"%s\"]", url_origin.c_str()),
- ExecuteScriptInBackgroundPage(extension_id, kScript));
+ result = ExecuteScriptAndReturnString(extension_id, profile(), kScript);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(base::StringPrintf("[\"%s\"]", url_origin.c_str()), *result);
}
// 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.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, Initiator_SplitIncognito) {
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
+ Initiator_SplitIncognito) {
embedded_test_server()->ServeFilesFromSourceDirectory("chrome/test/data");
ASSERT_TRUE(embedded_test_server()->Start());
@@ -3224,20 +3581,22 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, Initiator_SplitIncognito) {
const std::string origin_incognito =
url::Origin::Create(url_incognito).Serialize();
- const char* kScript = R"(
- domAutomationController.send(JSON.stringify(window.initiators));
- window.initiators = [];
+ static constexpr char kScript[] = R"(
+ chrome.test.sendScriptResult(JSON.stringify(self.initiators));
+ self.initiators = [];
)";
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url_normal));
ASSERT_TRUE(ui_test_utils::NavigateToURL(incognito_browser, url_incognito));
- EXPECT_EQ(base::StringPrintf("[\"%s\"]", origin_normal.c_str()),
- browsertest_util::ExecuteScriptInBackgroundPage(
- profile(), extension->id(), kScript));
- EXPECT_EQ(base::StringPrintf("[\"%s\"]", origin_incognito.c_str()),
- browsertest_util::ExecuteScriptInBackgroundPage(
- profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true),
- extension->id(), kScript));
+ absl::optional<std::string> result =
+ ExecuteScriptAndReturnString(extension->id(), profile(), kScript);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(base::StringPrintf("[\"%s\"]", origin_normal.c_str()), *result);
+ result = ExecuteScriptAndReturnString(
+ extension->id(),
+ profile()->GetPrimaryOTRProfile(/*create_if_needed=*/true), kScript);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(base::StringPrintf("[\"%s\"]", origin_incognito.c_str()), *result);
}
// A request handler that sets the Access-Control-Allow-Origin header.
@@ -3251,7 +3610,7 @@ std::unique_ptr<net::test_server::HttpResponse> HandleXHRRequest(
// Regression test for http://crbug.com/971206. The responseHeaders should still
// be present in onBeforeRedirect even for HSTS upgrade.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
ExtraHeadersWithHSTSUpgrade) {
net::EmbeddedTestServer https_test_server(
net::EmbeddedTestServer::TYPE_HTTPS);
@@ -3264,12 +3623,12 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
"name": "Web Request HSTS Test",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
chrome.webRequest.onBeforeRedirect.addListener(function(details) {
- window.headerCount = details.responseHeaders.length;
+ self.headerCount = details.responseHeaders.length;
}, {urls: ['<all_urls>']},
['responseHeaders', 'extraHeaders']);
@@ -3299,8 +3658,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
https_test_server.host_port_pair().host(),
https_test_server.port(), "echo");
EXPECT_GT(
- GetCountFromBackgroundPage(extension, profile(), "window.headerCount"),
- 0);
+ GetCountFromBackgroundPage(extension, profile(), "self.headerCount"), 0);
}
// Ensure that when an extension blocks a main-frame request, the resultant
@@ -3324,7 +3682,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
}
// Regression test for https://crbug.com/1019614.
-IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, HSTSUpgradeAfterRedirect) {
+IN_PROC_BROWSER_TEST_P(ExtensionWebRequestApiTestWithContextType,
+ HSTSUpgradeAfterRedirect) {
net::EmbeddedTestServer https_test_server(
net::EmbeddedTestServer::TYPE_HTTPS);
https_test_server.ServeFilesFromDirectory(
@@ -3338,7 +3697,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, HSTSUpgradeAfterRedirect) {
"name": "Web Request HSTS Test",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), R"(
@@ -3375,10 +3734,110 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, HSTSUpgradeAfterRedirect) {
EXPECT_EQ(final_url, web_contents->GetLastCommittedURL());
}
+// Tests registering webRequest events in multiple contexts in the same
+// extension (which will thus be in the same process). Regression test for
+// https://crbug.com/1297276.
+IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest,
+ ListenersInMultipleContexts) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+
+ // Load an extension that has a page with two iframes. Each iframe registers
+ // a listener for the same event.
+ static constexpr char kManifest[] =
+ R"({
+ "name": "ext",
+ "manifest_version": 3,
+ "version": "1",
+ "permissions": ["webRequest"],
+ "host_permissions": ["http://example.com/*"]
+ })";
+ static constexpr char kParentHtml[] =
+ R"(<!doctype html>
+ <html>
+ Hello world
+ <iframe src="iframe.html" name="iframe1"></iframe>
+ <iframe src="iframe.html" name="iframe2"></iframe>
+ </html>)";
+ static constexpr char kIframeHtml[] =
+ R"(<!doctype html>
+ <html>
+ Iframe
+ <script src="iframe.js"></script>
+ </html>)";
+ static constexpr char kIframeJs[] =
+ R"(const frameName = window.name;
+ chrome.webRequest.onBeforeRequest.addListener(
+ (details) => {
+ chrome.test.sendMessage(frameName + ' event');
+ },
+ {urls: ['http://example.com/*'], types: ['main_frame']});
+ chrome.test.sendMessage(frameName + ' ready');)";
+
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("parent.html"), kParentHtml);
+ test_dir.WriteFile(FILE_PATH_LITERAL("iframe.html"), kIframeHtml);
+ test_dir.WriteFile(FILE_PATH_LITERAL("iframe.js"), kIframeJs);
+
+ const Extension* extension = LoadExtension(test_dir.UnpackedPath());
+ ASSERT_TRUE(extension);
+
+ auto* router = ExtensionWebRequestEventRouter::GetInstance();
+ ASSERT_TRUE(router);
+
+ static constexpr char kEventName[] = "webRequest.onBeforeRequest";
+ EXPECT_EQ(0u, router->GetListenerCountForTesting(profile(), kEventName));
+
+ // Load the extension page and wait for it to register its listeners.
+ {
+ ExtensionTestMessageListener listener1("iframe1 ready");
+ ExtensionTestMessageListener listener2("iframe2 ready");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), extension->GetResourceURL("parent.html")));
+ ASSERT_TRUE(listener1.WaitUntilSatisfied());
+ ASSERT_TRUE(listener2.WaitUntilSatisfied());
+ }
+
+ // Two different listeners should be registered.
+ EXPECT_EQ(2u, router->GetListenerCountForTesting(profile(), kEventName));
+
+ // Trigger an event. Both listeners should fire.
+ {
+ ExtensionTestMessageListener listener1("iframe1 event");
+ ExtensionTestMessageListener listener2("iframe2 event");
+ ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
+ browser(),
+ embedded_test_server()->GetURL("example.com", "/title1.html"),
+ WindowOpenDisposition::NEW_FOREGROUND_TAB,
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
+ EXPECT_TRUE(listener1.WaitUntilSatisfied());
+ EXPECT_TRUE(listener2.WaitUntilSatisfied());
+ }
+}
+
+struct SWBTestParams {
+ SWBTestParams(bool extra_info_spec, ContextType context_type)
+ : extra_info_spec(extra_info_spec), context_type(context_type) {}
+
+ // The parameter is for opt_extraInfoSpec passed to addEventListener.
+ // 'blocking' if it's false, and 'extraHeaders' in addition to them
+ // if it's true.
+ bool extra_info_spec;
+ ContextType context_type;
+};
+
class SubresourceWebBundlesWebRequestApiTest
- : public testing::WithParamInterface<bool>,
+ : public testing::WithParamInterface<SWBTestParams>,
public ExtensionApiTest {
public:
+ SubresourceWebBundlesWebRequestApiTest()
+ : ExtensionApiTest(GetParam().context_type) {}
+ ~SubresourceWebBundlesWebRequestApiTest() override = default;
+ SubresourceWebBundlesWebRequestApiTest(
+ const SubresourceWebBundlesWebRequestApiTest&) = delete;
+ SubresourceWebBundlesWebRequestApiTest& operator=(
+ const SubresourceWebBundlesWebRequestApiTest&) = delete;
+
void SetUp() override {
feature_list_.InitWithFeatures({features::kSubresourceWebBundles}, {});
ExtensionApiTest::SetUp();
@@ -3394,7 +3853,8 @@ class SubresourceWebBundlesWebRequestApiTest
};
static ExtraInfoSpec GetExtraInfoSpec() {
- return GetParam() ? ExtraInfoSpec::kExtraHeaders : ExtraInfoSpec::kDefault;
+ return GetParam().extra_info_spec ? ExtraInfoSpec::kExtraHeaders
+ : ExtraInfoSpec::kDefault;
}
bool TryLoadScript(const std::string& script_src) {
@@ -3496,9 +3956,26 @@ class SubresourceWebBundlesWebRequestApiTest
base::test::ScopedFeatureList feature_list_;
};
-INSTANTIATE_TEST_SUITE_P(All,
- SubresourceWebBundlesWebRequestApiTest,
- ::testing::Bool());
+INSTANTIATE_TEST_SUITE_P(
+ PersistentBackgroundWithExtraHeaders,
+ SubresourceWebBundlesWebRequestApiTest,
+ ::testing::Values(SWBTestParams(true, ContextType::kPersistentBackground)));
+
+INSTANTIATE_TEST_SUITE_P(
+ PersistentBackground,
+ SubresourceWebBundlesWebRequestApiTest,
+ ::testing::Values(SWBTestParams(false,
+ ContextType::kPersistentBackground)));
+
+INSTANTIATE_TEST_SUITE_P(
+ ServiceWorkerWithExtraHeaders,
+ SubresourceWebBundlesWebRequestApiTest,
+ ::testing::Values(SWBTestParams(true, ContextType::kServiceWorker)));
+
+INSTANTIATE_TEST_SUITE_P(
+ ServiceWorker,
+ SubresourceWebBundlesWebRequestApiTest,
+ ::testing::Values(SWBTestParams(false, ContextType::kServiceWorker)));
// Ensure web request listeners can intercept requests for a web bundle and its
// subresources.
@@ -3513,7 +3990,7 @@ IN_PROC_BROWSER_TEST_P(SubresourceWebBundlesWebRequestApiTest,
"name": "Web Request Subresource Web Bundles Test",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest"]
})");
@@ -3522,19 +3999,19 @@ IN_PROC_BROWSER_TEST_P(SubresourceWebBundlesWebRequestApiTest,
opt_extra_info_spec += "'extraHeaders'";
test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
base::StringPrintf(R"(
- window.numMainResourceRequests = 0;
- window.numWebBundleRequests = 0;
- window.numScriptRequests = 0;
- window.numUUIDInPackageScriptRequests = 0;
+ self.numMainResourceRequests = 0;
+ self.numWebBundleRequests = 0;
+ self.numScriptRequests = 0;
+ self.numUUIDInPackageScriptRequests = 0;
chrome.webRequest.onBeforeRequest.addListener(function(details) {
if (details.url.includes('test.html'))
- window.numMainResourceRequests++;
+ self.numMainResourceRequests++;
else if (details.url.includes('web_bundle.wbn'))
- window.numWebBundleRequests++;
+ self.numWebBundleRequests++;
else if (details.url.includes('test.js'))
- window.numScriptRequests++;
+ self.numScriptRequests++;
else if (details.url === '%s')
- window.numUUIDInPackageScriptRequests++;
+ self.numUUIDInPackageScriptRequests++;
}, {urls: ['<all_urls>']}, [%s]);
chrome.test.sendMessage('ready');
@@ -3612,14 +4089,14 @@ IN_PROC_BROWSER_TEST_P(SubresourceWebBundlesWebRequestApiTest,
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
- "window.numMainResourceRequests"));
+ "self.numMainResourceRequests"));
EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
- "window.numWebBundleRequests"));
+ "self.numWebBundleRequests"));
EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
- "window.numScriptRequests"));
- EXPECT_EQ(
- 1, GetCountFromBackgroundPage(extension, profile(),
- "window.numUUIDInPackageScriptRequests"));
+ "self.numScriptRequests"));
+ EXPECT_EQ(1,
+ GetCountFromBackgroundPage(extension, profile(),
+ "self.numUUIDInPackageScriptRequests"));
}
// Ensure web request API can block the requests for the subresources inside the
@@ -3632,7 +4109,7 @@ IN_PROC_BROWSER_TEST_P(SubresourceWebBundlesWebRequestApiTest,
"name": "Web Request Subresource Web Bundles Test",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
std::string pass_uuid_in_package_js_url =
@@ -3644,22 +4121,22 @@ IN_PROC_BROWSER_TEST_P(SubresourceWebBundlesWebRequestApiTest,
opt_extra_info_spec += ", 'extraHeaders'";
test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
base::StringPrintf(R"(
- window.numPassScriptRequests = 0;
- window.numCancelScriptRequests = 0;
- window.numUUIDInPackagePassScriptRequests = 0;
- window.numUUIDInPackageCancelScriptRequests = 0;
+ self.numPassScriptRequests = 0;
+ self.numCancelScriptRequests = 0;
+ self.numUUIDInPackagePassScriptRequests = 0;
+ self.numUUIDInPackageCancelScriptRequests = 0;
chrome.webRequest.onBeforeRequest.addListener(function(details) {
if (details.url.includes('pass.js')) {
- window.numPassScriptRequests++;
+ self.numPassScriptRequests++;
return {cancel: false};
} else if (details.url.includes('cancel.js')) {
- window.numCancelScriptRequests++;
+ self.numCancelScriptRequests++;
return {cancel: true};
} else if (details.url === '%s') {
- window.numUUIDInPackagePassScriptRequests++;
+ self.numUUIDInPackagePassScriptRequests++;
return {cancel: false};
} else if (details.url === '%s') {
- window.numUUIDInPackageCancelScriptRequests++;
+ self.numUUIDInPackageCancelScriptRequests++;
return {cancel: true};
}
}, {urls: ['<all_urls>']}, [%s]);
@@ -3757,15 +4234,15 @@ IN_PROC_BROWSER_TEST_P(SubresourceWebBundlesWebRequestApiTest,
EXPECT_FALSE(TryLoadScript(cancel_uuid_in_package_js_url));
EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
- "window.numPassScriptRequests"));
+ "self.numPassScriptRequests"));
EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
- "window.numCancelScriptRequests"));
- EXPECT_EQ(1, GetCountFromBackgroundPage(
- extension, profile(),
- "window.numUUIDInPackagePassScriptRequests"));
+ "self.numCancelScriptRequests"));
+ EXPECT_EQ(
+ 1, GetCountFromBackgroundPage(extension, profile(),
+ "self.numUUIDInPackagePassScriptRequests"));
EXPECT_EQ(1, GetCountFromBackgroundPage(
extension, profile(),
- "window.numUUIDInPackageCancelScriptRequests"));
+ "self.numUUIDInPackageCancelScriptRequests"));
}
// Ensure web request API can change the headers of the subresources inside the
@@ -3778,7 +4255,7 @@ IN_PROC_BROWSER_TEST_P(SubresourceWebBundlesWebRequestApiTest, ChangeHeader) {
"name": "Web Request Subresource Web Bundles Test",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
std::string opt_extra_info_spec = "'blocking', 'responseHeaders'";
@@ -3880,7 +4357,7 @@ IN_PROC_BROWSER_TEST_P(SubresourceWebBundlesWebRequestApiTest,
"name": "Web Request Subresource Web Bundles Test",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
std::string opt_extra_info_spec = "'blocking', 'responseHeaders'";
@@ -3975,7 +4452,7 @@ IN_PROC_BROWSER_TEST_P(SubresourceWebBundlesWebRequestApiTest,
"name": "Web Request Subresource Web Bundles Test",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
std::string opt_extra_info_spec = "'blocking'";
@@ -4116,7 +4593,7 @@ IN_PROC_BROWSER_TEST_P(SubresourceWebBundlesWebRequestApiTest,
"name": "Web Request Subresource Web Bundles Test",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
std::string opt_extra_info_spec = "'blocking'";
@@ -4177,10 +4654,24 @@ enum class RedirectType {
kOnHeadersReceived,
};
+struct RITestParams {
+ RITestParams(RedirectType redirect_type, ContextType context_type)
+ : redirect_type(redirect_type), context_type(context_type) {}
+
+ RedirectType redirect_type;
+ ContextType context_type;
+};
+
class RedirectInfoWebRequestApiTest
- : public testing::WithParamInterface<RedirectType>,
+ : public testing::WithParamInterface<RITestParams>,
public ExtensionApiTest {
public:
+ RedirectInfoWebRequestApiTest() : ExtensionApiTest(GetParam().context_type) {}
+ ~RedirectInfoWebRequestApiTest() override = default;
+ RedirectInfoWebRequestApiTest(const RedirectInfoWebRequestApiTest&) = delete;
+ RedirectInfoWebRequestApiTest& operator=(
+ const RedirectInfoWebRequestApiTest&) = delete;
+
void SetUpOnMainThread() override {
ExtensionApiTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
@@ -4194,12 +4685,11 @@ class RedirectInfoWebRequestApiTest
"name": "Simple Redirect",
"manifest_version": 2,
"version": "0.1",
- "background": { "scripts": ["background.js"] },
+ "background": { "scripts": ["background.js"], "persistent": true },
"permissions": ["<all_urls>", "webRequest", "webRequestBlocking"]
})");
- test_dir.WriteFile(
- FILE_PATH_LITERAL("background.js"),
- base::StringPrintf(R"(
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
+ base::StringPrintf(R"(
chrome.webRequest.%s.addListener(function(details) {
if (details.type == '%s' &&
details.url.includes('hello.html')) {
@@ -4210,10 +4700,11 @@ class RedirectInfoWebRequestApiTest
}, {urls: ['*://original.test/*']}, ['blocking']);
chrome.test.sendMessage('ready');
)",
- GetParam() == RedirectType::kOnBeforeRequest
- ? "onBeforeRequest"
- : "onHeadersReceived",
- resource_type.c_str()));
+ GetParam().redirect_type ==
+ RedirectType::kOnBeforeRequest
+ ? "onBeforeRequest"
+ : "onHeadersReceived",
+ resource_type.c_str()));
ExtensionTestMessageListener listener("ready");
const Extension* extension = LoadExtension(test_dir.UnpackedPath());
ASSERT_TRUE(extension);
@@ -4224,10 +4715,29 @@ class RedirectInfoWebRequestApiTest
TestExtensionDir test_dir_;
};
-INSTANTIATE_TEST_SUITE_P(RedirectMode,
- RedirectInfoWebRequestApiTest,
- ::testing::Values(RedirectType::kOnBeforeRequest,
- RedirectType::kOnHeadersReceived));
+INSTANTIATE_TEST_SUITE_P(
+ PersistentBackgroundOnBeforeRequest,
+ RedirectInfoWebRequestApiTest,
+ ::testing::Values(RITestParams(RedirectType::kOnBeforeRequest,
+ ContextType::kPersistentBackground)));
+
+INSTANTIATE_TEST_SUITE_P(
+ PersistentBackgroundOnHeadersReceived,
+ RedirectInfoWebRequestApiTest,
+ ::testing::Values(RITestParams(RedirectType::kOnHeadersReceived,
+ ContextType::kPersistentBackground)));
+
+INSTANTIATE_TEST_SUITE_P(
+ ServiceWorkerOnBeforeRequest,
+ RedirectInfoWebRequestApiTest,
+ ::testing::Values(RITestParams(RedirectType::kOnBeforeRequest,
+ ContextType::kServiceWorker)));
+
+INSTANTIATE_TEST_SUITE_P(
+ ServiceWorkerOnHeadersReceived,
+ RedirectInfoWebRequestApiTest,
+ ::testing::Values(RITestParams(RedirectType::kOnHeadersReceived,
+ ContextType::kServiceWorker)));
// Test that a main frame request redirected by an extension has the correct
// site_for_cookies and network_isolation_key parameters.
@@ -4437,10 +4947,15 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiIdentifiabilityTest,
blink::IdentifiableSurface::Type::kExtensionCancelRequest));
}
-class ProxyCORSWebRequestApiTest : public ExtensionApiTest {
+class ProxyCORSWebRequestApiTest
+ : public ExtensionApiTest,
+ public testing::WithParamInterface<ContextType> {
public:
- ProxyCORSWebRequestApiTest() = default;
+ ProxyCORSWebRequestApiTest() : ExtensionApiTest(GetParam()) {}
~ProxyCORSWebRequestApiTest() override = default;
+ ProxyCORSWebRequestApiTest(const ProxyCORSWebRequestApiTest&) = delete;
+ ProxyCORSWebRequestApiTest& operator=(const ProxyCORSWebRequestApiTest&) =
+ delete;
protected:
class ProceedLoginDialog : public content::NotificationObserver {
@@ -4576,10 +5091,18 @@ class ProxyCORSWebRequestApiTest : public ExtensionApiTest {
net::EmbeddedTestServer proxy_cors_server_;
};
+INSTANTIATE_TEST_SUITE_P(PersistentBackground,
+ ProxyCORSWebRequestApiTest,
+ ::testing::Values(ContextType::kPersistentBackground));
+
+INSTANTIATE_TEST_SUITE_P(ServiceWorker,
+ ProxyCORSWebRequestApiTest,
+ ::testing::Values(ContextType::kServiceWorker));
+
// Regression test for crbug.com/1212625
// Test that CORS preflight request which requires proxy auth completes
// successfully instead of being cancelled after proxy auth required response.
-IN_PROC_BROWSER_TEST_F(ProxyCORSWebRequestApiTest,
+IN_PROC_BROWSER_TEST_P(ProxyCORSWebRequestApiTest,
PreflightCompletesSuccessfully) {
ProceedLoginDialog login_dialog(kCORSProxyUser, kCORSProxyPass);
ExtensionTestMessageListener ready_listener("ready");
@@ -4593,7 +5116,7 @@ IN_PROC_BROWSER_TEST_F(ProxyCORSWebRequestApiTest,
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_contents);
ExtensionTestMessageListener preflight_listener("cors-preflight-succeeded");
- const char kCORSPreflightedRequest[] = R"(
+ static constexpr char kCORSPreflightedRequest[] = R"(
var xhr = new XMLHttpRequest();
xhr.open('GET', '%s');
xhr.setRequestHeader('%s', 'testvalue');
@@ -4608,15 +5131,16 @@ IN_PROC_BROWSER_TEST_F(ProxyCORSWebRequestApiTest,
&success));
EXPECT_TRUE(success);
EXPECT_TRUE(preflight_listener.WaitUntilSatisfied());
- EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
- "preflightHeadersReceivedCount"));
- EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
- "preflightProxyAuthRequiredCount"));
- EXPECT_EQ(1, GetCountFromBackgroundPage(extension, profile(),
- "preflightResponseStartedCount"));
+ EXPECT_EQ(1, GetCountFromBackgroundPage(
+ extension, profile(), "self.preflightHeadersReceivedCount"));
+ EXPECT_EQ(1,
+ GetCountFromBackgroundPage(extension, profile(),
+ "self.preflightProxyAuthRequiredCount"));
+ EXPECT_EQ(1, GetCountFromBackgroundPage(
+ extension, profile(), "self.preflightResponseStartedCount"));
EXPECT_EQ(1, GetCountFromBackgroundPage(
extension, profile(),
- "preflightResponseStartedSuccessfullyCount"));
+ "self.preflightResponseStartedSuccessfullyCount"));
}
class ExtensionWebRequestApiFencedFrameTest
@@ -4659,4 +5183,480 @@ INSTANTIATE_TEST_SUITE_P(ExtensionWebRequestApiFencedFrameTest,
ExtensionWebRequestApiFencedFrameTest,
testing::Bool());
+class ExtensionWebRequestApiPrerenderingTest
+ : public ExtensionWebRequestApiTest {
+ protected:
+ ExtensionWebRequestApiPrerenderingTest() = default;
+ ~ExtensionWebRequestApiPrerenderingTest() override = default;
+
+ private:
+ content::test::ScopedPrerenderFeatureList prerender_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiPrerenderingTest, Load) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ ASSERT_TRUE(
+ RunExtensionTest("webrequest", {.page_url = "test_prerendering.html"}))
+ << message_;
+}
+
+using ContextType = ExtensionBrowserTest::ContextType;
+
+class WebRequestApiTestWithContextType
+ : public ExtensionWebRequestApiTest,
+ public testing::WithParamInterface<ContextType> {
+ public:
+ WebRequestApiTestWithContextType() = default;
+ ~WebRequestApiTestWithContextType() override = default;
+};
+
+namespace {
+
+constexpr char kGetNumRequests[] =
+ R"((async function() {
+ // Wait for any pending storage writes to complete.
+ await flushStorage();
+ chrome.storage.local.get(
+ {requestCount: -1},
+ (result) => {
+ chrome.test.sendScriptResult(result.requestCount);
+ });
+ })();)";
+
+} // namespace
+
+// Tests that webRequest listeners are persistent across browser restarts.
+IN_PROC_BROWSER_TEST_P(WebRequestApiTestWithContextType,
+ PRE_TestListenersArePersistent) {
+ // Load an extension that listens for webRequest events.
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ const Extension* extension =
+ LoadExtension(test_data_dir_.AppendASCII("webrequest_persistent"));
+ ASSERT_TRUE(extension);
+
+ // Navigate to example.com (a site the extension has access to).
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL("example.com", "/simple.html")));
+
+ // Validate that we have a single request seen by the extension.
+ base::Value request_count = BackgroundScriptExecutor::ExecuteScript(
+ profile(), extension->id(), kGetNumRequests,
+ BackgroundScriptExecutor::ResultCapture::kSendScriptResult);
+ ASSERT_TRUE(request_count.is_int());
+ EXPECT_EQ(1, request_count.GetInt());
+}
+
+IN_PROC_BROWSER_TEST_P(WebRequestApiTestWithContextType,
+ TestListenersArePersistent) {
+ // Find the installed extension and wait for it to fully load.
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ const Extension* extension = nullptr;
+ for (const auto& candidate : extension_registry()->enabled_extensions()) {
+ if (candidate->name() == "Web Request Persistence") {
+ extension = candidate.get();
+ break;
+ }
+ }
+ ASSERT_TRUE(extension);
+ WaitForExtensionViewsToLoad();
+
+ // Navigate once more to example.com.
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL("example.com", "/simple.html")));
+
+ // We should now have two records seen by the extension.
+ base::Value request_count = BackgroundScriptExecutor::ExecuteScript(
+ profile(), extension->id(), kGetNumRequests,
+ BackgroundScriptExecutor::ResultCapture::kSendScriptResult);
+
+ ASSERT_TRUE(request_count.is_int());
+ EXPECT_EQ(2, request_count.GetInt());
+}
+
+INSTANTIATE_TEST_SUITE_P(PersistentBackground,
+ WebRequestApiTestWithContextType,
+ ::testing::Values(ContextType::kPersistentBackground));
+INSTANTIATE_TEST_SUITE_P(ServiceWorker,
+ WebRequestApiTestWithContextType,
+ ::testing::Values(ContextType::kServiceWorker));
+
+class ManifestV3WebRequestApiTest : public ExtensionWebRequestApiTest {
+ public:
+ ManifestV3WebRequestApiTest() = default;
+ ~ManifestV3WebRequestApiTest() override = default;
+
+ // Loads an extension contained within `test_dir` as a policy-installed
+ // extension. This is useful because webRequestBlocking is restricted to
+ // policy-installed extensions in Manifest V3.
+ // This assumes the extension script will send a "ready" message once it's
+ // done setting up.
+ const Extension* LoadPolicyExtension(TestExtensionDir& test_dir) {
+ // We need a "ready"-style listener here because `InstallExtension()`
+ // doesn't automagically wait for the extension to finish setting up.
+ ExtensionTestMessageListener listener("ready");
+ // Since we may programmatically stop the worker, we also need to wait for
+ // the registration to be fully stored.
+ service_worker_test_utils::TestRegistrationObserver registration_observer(
+ profile());
+ base::FilePath packed_path = test_dir.Pack();
+ const Extension* extension = InstallExtension(
+ packed_path, 1, mojom::ManifestLocation::kExternalPolicyDownload);
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(listener.WaitUntilSatisfied());
+ registration_observer.WaitForRegistrationStored();
+
+ return extension;
+ }
+
+ ExtensionWebRequestEventRouter* web_request_router() {
+ return ExtensionWebRequestEventRouter::GetInstance();
+ }
+};
+
+// Tests a service worker-based extension intercepting requests with
+// webRequestBlocking.
+IN_PROC_BROWSER_TEST_F(ManifestV3WebRequestApiTest, WebRequestBlocking) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ static constexpr char kManifest[] =
+ R"({
+ "name": "MV3 WebRequest",
+ "version": "0.1",
+ "manifest_version": 3,
+ "permissions": ["webRequest", "webRequestBlocking"],
+ "host_permissions": [
+ "http://block.example/*",
+ "http://allow.example/*"
+ ],
+ "background": {"service_worker": "background.js"}
+ })";
+ // An extension with a listener that cancels any requests that include
+ // block.example.
+ static constexpr char kBackgroundJs[] =
+ R"(chrome.webRequest.onBeforeRequest.addListener(
+ (details) => {
+ if (details.url.includes('block.example')) {
+ return {cancel: true}
+ }
+ return {};
+ },
+ {urls: ['<all_urls>'], types: ['main_frame']},
+ ['blocking']);
+ chrome.test.sendMessage('ready');)";
+
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundJs);
+ const Extension* extension = LoadPolicyExtension(test_dir);
+ ASSERT_TRUE(extension);
+
+ content::WebContents* web_contents =
+ browser()->tab_strip_model()->GetActiveWebContents();
+
+ // Navigate to allow.example. This should succeed.
+ {
+ content::TestNavigationObserver nav_observer(web_contents);
+ EXPECT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL("allow.example", "/simple.html")));
+ EXPECT_EQ(net::OK, nav_observer.last_net_error_code());
+ }
+
+ // Now, navigate to block.example. This navigation should be blocked.
+ {
+ content::TestNavigationObserver nav_observer(web_contents);
+ EXPECT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL("block.example", "/simple.html")));
+ EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, nav_observer.last_net_error_code());
+ }
+}
+
+// Tests a service worker-based extension registering multiple webRequest events
+// in multiple contexts. This ensures the subevent name logic for service worker
+// extensions doesn't result in any collisions of listener IDs, similar to the
+// issue found in https://crbug.com/1297276.
+IN_PROC_BROWSER_TEST_F(ManifestV3WebRequestApiTest,
+ MultipleListenersAndContexts) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ static constexpr char kManifest[] =
+ R"({
+ "name": "MV3 WebRequest",
+ "version": "0.1",
+ "manifest_version": 3,
+ "permissions": ["webRequest", "storage"],
+ "host_permissions": [
+ "http://first.example/*",
+ "http://second.example/*",
+ "http://third.example/*"
+ ],
+ "background": {"service_worker": "background.js"}
+ })";
+ // The extension has two contexts: the background service worker (which
+ // registers two listeners) and a separate page (which also registers a
+ // listener). This ensures that a) service worker listeners do not conflict
+ // with each other and b) service worker listeners do not conflict with
+ // listeners registered in other contexts.
+ static constexpr char kBackgroundJs[] =
+ R"(self.firstCount = 0;
+ self.secondCount = 0;
+ function firstListener() { ++firstCount; }
+ function secondListener() { ++secondCount; }
+ chrome.webRequest.onBeforeRequest.addListener(
+ firstListener,
+ {urls: ['http://first.example/*'], types: ['main_frame']}, []);
+ chrome.webRequest.onBeforeRequest.addListener(
+ secondListener,
+ {urls: ['http://second.example/*'], types: ['main_frame']}, []);)";
+ static constexpr char kPageHtml[] =
+ R"(<!doctype html>
+ <html>
+ Page
+ <script src="page.js"></script>
+ </html>)";
+ static constexpr char kPageJs[] =
+ R"(self.thirdCount = 0;
+ function thirdListener() { ++thirdCount; }
+ chrome.webRequest.onBeforeRequest.addListener(
+ thirdListener,
+ {urls: ['http://third.example/*'], types: ['main_frame']}, []);)";
+
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundJs);
+ test_dir.WriteFile(FILE_PATH_LITERAL("page.html"), kPageHtml);
+ test_dir.WriteFile(FILE_PATH_LITERAL("page.js"), kPageJs);
+ const Extension* extension = LoadExtension(test_dir.UnpackedPath());
+ ASSERT_TRUE(extension);
+
+ // Load the page with the extension listeners.
+ content::RenderFrameHost* page_host = ui_test_utils::NavigateToURL(
+ browser(), extension->GetResourceURL("page.html"));
+ ASSERT_TRUE(page_host);
+
+ // At this point, 3 listeners should be registered.
+ EXPECT_EQ(3u, web_request_router()->GetListenerCountForTesting(
+ profile(), "webRequest.onBeforeRequest"));
+
+ // Convenience lambdas for checking the count received in each listener.
+ auto get_first_count = [this, extension]() {
+ return GetCountFromBackgroundPage(extension, profile(), "firstCount");
+ };
+ auto get_second_count = [this, extension]() {
+ return GetCountFromBackgroundPage(extension, profile(), "secondCount");
+ };
+ auto get_third_count = [page_host]() {
+ int count = -1;
+ EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
+ page_host, "domAutomationController.send(window.thirdCount);", &count));
+ return count;
+ };
+
+ // No listeners should have fired yet.
+ EXPECT_EQ(0, get_first_count());
+ EXPECT_EQ(0, get_second_count());
+ EXPECT_EQ(0, get_third_count());
+
+ // Navigate to first.example (this first navigation needs to happen in a new
+ // tab so that we don't navigate the extension page).
+ ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
+ browser(),
+ embedded_test_server()->GetURL("first.example", "/title1.html"),
+ WindowOpenDisposition::NEW_FOREGROUND_TAB,
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
+
+ // (Only) the first listener should have fired.
+ EXPECT_EQ(1, get_first_count());
+ EXPECT_EQ(0, get_second_count());
+ EXPECT_EQ(0, get_third_count());
+
+ // Navigate to second.example. The second listener should fire.
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL("second.example", "/title1.html")));
+ EXPECT_EQ(1, get_first_count());
+ EXPECT_EQ(1, get_second_count());
+ EXPECT_EQ(0, get_third_count());
+
+ // Navigate to third.example. The third listener should fire.
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL("third.example", "/title1.html")));
+ EXPECT_EQ(1, get_first_count());
+ EXPECT_EQ(1, get_second_count());
+ EXPECT_EQ(1, get_third_count());
+}
+
+// Tests that a service worker-based extension with webRequestBlocking can
+// intercept requests after the service worker stops.
+IN_PROC_BROWSER_TEST_F(ManifestV3WebRequestApiTest,
+ WebRequestBlocking_AfterWorkerShutdown) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ static constexpr char kManifest[] =
+ R"({
+ "name": "MV3 WebRequest",
+ "version": "0.1",
+ "manifest_version": 3,
+ "permissions": ["webRequest", "webRequestBlocking"],
+ "host_permissions": [
+ "http://block.example/*"
+ ],
+ "background": {"service_worker": "background.js"}
+ })";
+ // An extension with a listener that cancels any requests that include
+ // block.example.
+ static constexpr char kBackgroundJs[] =
+ R"(chrome.webRequest.onBeforeRequest.addListener(
+ (details) => {
+ if (details.url.includes('block.example')) {
+ return {cancel: true}
+ }
+ return {};
+ },
+ {urls: ['<all_urls>'], types: ['main_frame']},
+ ['blocking']);
+ chrome.test.sendMessage('ready');)";
+
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundJs);
+ const Extension* extension = LoadPolicyExtension(test_dir);
+ ASSERT_TRUE(extension);
+
+ // A single webRequest listener should be registered.
+ EXPECT_EQ(1u, web_request_router()->GetListenerCountForTesting(
+ profile(), "webRequest.onBeforeRequest"));
+
+ // Stop the service worker.
+ browsertest_util::StopServiceWorkerForExtensionGlobalScope(profile(),
+ extension->id());
+ // Note: the task to remove listeners from ExtensionWebRequestEventRouter
+ // is async; run to flush the posted task.
+ base::RunLoop().RunUntilIdle();
+
+ // The listener should still be registered.
+ // TODO(https://crbug.com/1024211): This currently fails.
+ // EXPECT_EQ(1u, web_request_router()->GetListenerCountForTesting(
+ // profile(), "webRequest.onBeforeRequest"));
+ EXPECT_EQ(0u, web_request_router()->GetListenerCountForTesting(
+ profile(), "webRequest.onBeforeRequest"));
+
+ // Navigate to block.example. The request should be blocked by the extension.
+ {
+ content::WebContents* web_contents =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ content::TestNavigationObserver nav_observer(web_contents);
+ EXPECT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL("block.example", "/simple.html")));
+ // TODO(https://crbug.com/1024211): This currently fails.
+ // EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT,
+ // nav_observer.last_net_error_code());
+ EXPECT_EQ(net::OK, nav_observer.last_net_error_code());
+ }
+}
+
+// Tests a service worker-based extension using webRequest for observational
+// purposes receives events after the worker stops.
+IN_PROC_BROWSER_TEST_F(ManifestV3WebRequestApiTest,
+ WebRequestObservation_AfterWorkerShutdown) {
+ ASSERT_TRUE(StartEmbeddedTestServer());
+ static constexpr char kManifest[] =
+ R"({
+ "name": "MV3 WebRequest",
+ "version": "0.1",
+ "manifest_version": 3,
+ "permissions": ["webRequest", "storage"],
+ "host_permissions": [
+ "http://example.com/*"
+ ],
+ "background": {"service_worker": "background.js"}
+ })";
+ // An extension that stores the number of matched requests in a count in
+ // extension storage.
+ // This is very similar to the test extension at
+ // chrome/test/data/extensions/api_test/webrequest_persistent, but is
+ // manifest V3. There's enough changes that our loading auto-conversion code
+ // won't quite work (mostly around permissions vs host_permissions), so we
+ // need a bit of a duplication here.
+ static constexpr char kBackgroundJs[] =
+ R"(let storageComplete = undefined;
+ let isUsingStorage = false;
+
+ // Waits for any pending load to complete to avoid raciness in the
+ // test.
+ async function flushStorage() {
+ console.assert(!storageComplete);
+ if (!isUsingStorage)
+ return;
+ await new Promise((resolve) => {
+ storageComplete = resolve;
+ });
+ storageComplete = undefined;
+ }
+
+ chrome.webRequest.onBeforeRequest.addListener(
+ async (details) => {
+ isUsingStorage = true;
+ let {requestCount} =
+ await chrome.storage.local.get({requestCount: 0});
+ requestCount++;
+ await chrome.storage.local.set({requestCount});
+ isUsingStorage = false;
+ if (storageComplete)
+ storageComplete();
+ },
+ {urls: ['<all_urls>'], types: ['main_frame']});)";
+
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(kManifest);
+ test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), kBackgroundJs);
+ const Extension* extension = LoadExtension(
+ test_dir.UnpackedPath(), {.wait_for_registration_stored = true});
+ ASSERT_TRUE(extension);
+
+ // A single listener should be registered.
+ EXPECT_EQ(1u, web_request_router()->GetListenerCountForTesting(
+ profile(), "webRequest.onBeforeRequest"));
+
+ // Navigate to a URL. The request should be seen by the extension.
+ EXPECT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL("example.com", "/simple.html")));
+
+ auto get_request_count = [this, extension]() {
+ base::Value request_count = BackgroundScriptExecutor::ExecuteScript(
+ profile(), extension->id(), kGetNumRequests,
+ BackgroundScriptExecutor::ResultCapture::kSendScriptResult);
+ return request_count.GetInt();
+ };
+
+ EXPECT_EQ(1, get_request_count());
+
+ // Stop the extension's service worker.
+ browsertest_util::StopServiceWorkerForExtensionGlobalScope(profile(),
+ extension->id());
+ // Note: the task to remove listeners from ExtensionWebRequestEventRouter
+ // is async; run to flush the posted task.
+ base::RunLoop().RunUntilIdle();
+
+ // The listener should still be registered.
+ // TODO(https://crbug.com/1024211): This currently fails.
+ // EXPECT_EQ(1u, web_request_router()->GetListenerCountForTesting(
+ // profile(), "webRequest.onBeforeRequest"));
+ EXPECT_EQ(0u, web_request_router()->GetListenerCountForTesting(
+ profile(), "webRequest.onBeforeRequest"));
+
+ // Navigate again. The request should again be seen by the extension.
+ EXPECT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL("example.com", "/simple.html")));
+
+ // TODO(https://crbug.com/1024211): This currently fails. Additionally,
+ // BackgroundScriptExecutor won't wake up a passive service worker, so
+ // we can't even call `get_request_count()`.
+ // EXPECT_EQ(2, get_request_count());
+}
+
} // namespace extensions
diff --git a/chromium/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc b/chromium/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc
index 656354541fb..a3c79d1bf89 100644
--- a/chromium/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc
@@ -17,58 +17,6 @@
namespace extensions {
-TEST(WebRequestEventDetailsTest, AllowlistedCopyForPublicSession) {
- // Create original, and populate it with some values.
- std::unique_ptr<WebRequestEventDetails> orig(new WebRequestEventDetails);
-
- const char* const safe_attributes[] = {
- "method", "requestId", "timeStamp", "type", "tabId", "frameId",
- "parentFrameId", "fromCache", "error", "ip", "statusLine", "statusCode"
- };
-
- orig->render_process_id_ = 1;
- orig->extra_info_spec_ = 3;
-
- orig->request_body_ = std::make_unique<base::DictionaryValue>();
- orig->request_headers_ = std::make_unique<base::ListValue>();
- orig->response_headers_ = std::make_unique<base::ListValue>();
-
- for (const char* safe_attr : safe_attributes) {
- orig->dict_.SetStringKey(safe_attr, safe_attr);
- }
-
- orig->dict_.SetStringKey("url", "http://www.foo.bar/baz");
-
- // Add some extra dict_ values that should be filtered out.
- orig->dict_.SetStringKey("requestBody", "request body value");
- orig->dict_.SetStringKey("requestHeaders", "request headers value");
-
- // Get a filtered copy then check that filtering really works.
- std::unique_ptr<WebRequestEventDetails> copy =
- orig->CreatePublicSessionCopy();
-
- EXPECT_EQ(orig->render_process_id_, copy->render_process_id_);
- EXPECT_EQ(0, copy->extra_info_spec_);
-
- EXPECT_EQ(nullptr, copy->request_body_);
- EXPECT_EQ(nullptr, copy->request_headers_);
- EXPECT_EQ(nullptr, copy->response_headers_);
-
- for (const char* safe_attr : safe_attributes) {
- std::string copy_str;
- copy->dict_.GetString(safe_attr, &copy_str);
- EXPECT_EQ(safe_attr, copy_str);
- }
-
- // URL is stripped down to origin.
- std::string url;
- copy->dict_.GetString("url", &url);
- EXPECT_EQ("http://www.foo.bar/", url);
-
- // Extras are filtered out (+1 for url).
- EXPECT_EQ(std::size(safe_attributes) + 1, copy->dict_.DictSize());
-}
-
TEST(WebRequestEventDetailsTest, SetResponseHeaders) {
const int kFilter =
extension_web_request_api_helpers::ExtraInfoSpec::RESPONSE_HEADERS;
diff --git a/chromium/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc b/chromium/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc
index 25fa8187a1a..74c46ab9f9f 100644
--- a/chromium/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc
@@ -11,7 +11,6 @@
#include "chrome/browser/extensions/extension_service_test_base.h"
#include "chrome/common/extensions/extension_test_util.h"
#include "chrome/common/url_constants.h"
-#include "chromeos/login/login_state/scoped_test_public_session_login_state.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/browser/api/web_request/permission_helper.h"
#include "extensions/browser/api/web_request/web_request_info.h"
@@ -23,10 +22,6 @@
#include "services/network/public/mojom/fetch_api.mojom-shared.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chromeos/login/login_state/login_state.h"
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
-
using extension_test_util::LoadManifestUnchecked;
using extensions::Extension;
using extensions::ExtensionRegistry;
@@ -237,11 +232,8 @@ TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest,
false, // crosses_incognito
WebRequestPermissions::REQUIRE_ALL_URLS, initiator, kWebRequestType));
- // Public Sessions tests.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- const GURL org_url("http://example.org");
-
// com_extension_ doesn't have host permission for .org URLs.
+ const GURL org_url("http://example.org");
EXPECT_EQ(PermissionsData::PageAccess::kDenied,
WebRequestPermissions::CanExtensionAccessURL(
permission_helper_, com_policy_extension_->id(), org_url,
@@ -250,29 +242,8 @@ TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest,
WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL,
absl::nullopt, kWebRequestType));
- chromeos::ScopedTestPublicSessionLoginState login_state;
-
- // Host permission checks are disabled in Public Sessions, instead all URLs
- // are allowlisted.
- EXPECT_EQ(PermissionsData::PageAccess::kAllowed,
- WebRequestPermissions::CanExtensionAccessURL(
- permission_helper_, com_policy_extension_->id(), org_url,
- -1, // No tab id.
- false, // crosses_incognito
- WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL,
- absl::nullopt, kWebRequestType));
-
- EXPECT_EQ(PermissionsData::PageAccess::kAllowed,
- WebRequestPermissions::CanExtensionAccessURL(
- permission_helper_, com_policy_extension_->id(), org_url,
- -1, // No tab id.
- false, // crosses_incognito
- WebRequestPermissions::REQUIRE_ALL_URLS, absl::nullopt,
- kWebRequestType));
-
// Make sure that chrome:// URLs cannot be accessed.
const GURL chrome_url("chrome://version/");
-
EXPECT_EQ(PermissionsData::PageAccess::kDenied,
WebRequestPermissions::CanExtensionAccessURL(
permission_helper_, com_policy_extension_->id(), chrome_url,
@@ -280,5 +251,4 @@ TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest,
false, // crosses_incognito
WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL,
absl::nullopt, kWebRequestType));
-#endif
}
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 875c5a0846d..c0410fc00c5 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
@@ -93,7 +93,7 @@ void WebrtcAudioPrivateEventService::SignalEvent() {
extension->permissions_data()->HasAPIPermission("webrtcAudioPrivate")) {
std::unique_ptr<Event> event =
std::make_unique<Event>(events::WEBRTC_AUDIO_PRIVATE_ON_SINKS_CHANGED,
- kEventName, std::vector<base::Value>());
+ kEventName, base::Value::List());
router->DispatchEventToExtension(extension_id, std::move(event));
}
}
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 5fd89424dae..c250d738ab9 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
@@ -158,9 +158,9 @@ IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetSinks) {
++ix, ++it) {
const base::Value& value = sink_list.GetListDeprecated()[ix];
EXPECT_TRUE(value.is_dict());
- const base::DictionaryValue& dict = base::Value::AsDictionaryValue(value);
- std::string sink_id;
- dict.GetString("sinkId", &sink_id);
+ const base::Value::Dict& dict = value.GetDict();
+ const std::string* sink_id = dict.FindString("sinkId");
+ EXPECT_TRUE(sink_id);
std::string expected_id =
media::AudioDeviceDescription::IsDefaultDevice(it->unique_id)
@@ -170,16 +170,16 @@ IN_PROC_BROWSER_TEST_F(WebrtcAudioPrivateTest, GetSinks) {
url::Origin::Create(source_url_.DeprecatedGetOriginAsURL()),
it->unique_id);
- EXPECT_EQ(expected_id, sink_id);
- std::string sink_label;
- dict.GetString("sinkLabel", &sink_label);
- EXPECT_EQ(it->device_name, sink_label);
+ EXPECT_EQ(expected_id, *sink_id);
+ const std::string* sink_label = dict.FindString("sinkLabel");
+ EXPECT_TRUE(sink_label);
+ EXPECT_EQ(it->device_name, *sink_label);
// TODO(joi): Verify the contents of these once we start actually
// filling them in.
- EXPECT_TRUE(dict.FindKey("isDefault"));
- EXPECT_TRUE(dict.FindKey("isReady"));
- EXPECT_TRUE(dict.FindKey("sampleRate"));
+ EXPECT_TRUE(dict.Find("isDefault"));
+ EXPECT_TRUE(dict.Find("isReady"));
+ EXPECT_TRUE(dict.Find("sampleRate"));
}
}
#endif // BUILDFLAG(IS_MAC)
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 fcfbf296c6b..0d045b7d99a 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
@@ -70,7 +70,10 @@ WebrtcDesktopCapturePrivateChooseDesktopMediaFunction::Run() {
using Sources = std::vector<api::desktop_capture::DesktopCaptureSourceType>;
Sources* sources = reinterpret_cast<Sources*>(&params->sources);
- return Execute(*sources, rfh, origin, target_name);
+
+ // TODO(crbug.com/1329129): Plumb systemAudio through here.
+ return Execute(*sources, /*exclude_system_audio=*/false, rfh, origin,
+ target_name);
}
WebrtcDesktopCapturePrivateCancelChooseDesktopMediaFunction::
diff --git a/chromium/chrome/browser/extensions/api/webstore_private/extension_install_status.cc b/chromium/chrome/browser/extensions/api/webstore_private/extension_install_status.cc
index f550a6735cb..e6c4bfbd714 100644
--- a/chromium/chrome/browser/extensions/api/webstore_private/extension_install_status.cc
+++ b/chromium/chrome/browser/extensions/api/webstore_private/extension_install_status.cc
@@ -134,8 +134,8 @@ ExtensionInstallStatus GetWebstoreExtensionInstallStatus(
return kBlockedByPolicy;
if (profile->GetPrefs()
- ->GetDictionary(prefs::kCloudExtensionRequestIds)
- ->FindKey(extension_id)) {
+ ->GetValueDict(prefs::kCloudExtensionRequestIds)
+ .Find(extension_id)) {
return kRequestPending;
}
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 87bbf05ef0e..695efd4d4bc 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
@@ -40,7 +40,7 @@
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/app_list/app_list_util.h"
-#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/extensions/extensions_dialogs.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
@@ -91,7 +91,6 @@ namespace IsPendingCustodianApproval =
api::webstore_private::IsPendingCustodianApproval;
namespace IsInIncognitoMode = api::webstore_private::IsInIncognitoMode;
namespace LaunchEphemeralApp = api::webstore_private::LaunchEphemeralApp;
-namespace RequestExtension = api::webstore_private::RequestExtension;
namespace SetStoreLogin = api::webstore_private::SetStoreLogin;
namespace {
@@ -243,9 +242,9 @@ void ShowBlockedByParentDialog(const Extension* extension,
return;
}
- chrome::ShowExtensionInstallBlockedByParentDialog(
- chrome::ExtensionInstalledBlockedByParentDialogAction::kAdd, extension,
- contents, std::move(done_callback));
+ extensions::ShowExtensionInstallBlockedByParentDialog(
+ extensions::ExtensionInstalledBlockedByParentDialogAction::kAdd,
+ extension, contents, std::move(done_callback));
}
#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
@@ -871,7 +870,7 @@ bool WebstorePrivateBeginInstallWithManifest3Function::ShouldShowFrictionDialog(
void WebstorePrivateBeginInstallWithManifest3Function::
ShowInstallFrictionDialog(content::WebContents* contents) {
friction_dialog_shown_ = true;
- chrome::ShowExtensionInstallFrictionDialog(
+ ShowExtensionInstallFrictionDialog(
contents,
base::BindOnce(&WebstorePrivateBeginInstallWithManifest3Function::
OnFrictionPromptDone,
@@ -933,9 +932,9 @@ void WebstorePrivateBeginInstallWithManifest3Function::
return;
}
- chrome::ShowExtensionInstallBlockedDialog(
- extension->id(), extension->name(), blocked_by_policy_error_message_,
- image, contents, std::move(done_callback));
+ ShowExtensionInstallBlockedDialog(extension->id(), extension->name(),
+ blocked_by_policy_error_message_, image,
+ contents, std::move(done_callback));
}
WebstorePrivateCompleteInstallFunction::
@@ -1294,7 +1293,7 @@ WebstorePrivateGetExtensionStatusFunction::BuildResponseWithoutManifest(
void WebstorePrivateGetExtensionStatusFunction::OnManifestParsed(
const ExtensionId& extension_id,
data_decoder::DataDecoder::ValueOrError result) {
- if (!result.value || !result.value->is_dict()) {
+ if (!result.has_value() || !result->is_dict()) {
Respond(Error(kWebstoreInvalidManifestError));
return;
}
@@ -1307,7 +1306,7 @@ void WebstorePrivateGetExtensionStatusFunction::OnManifestParsed(
std::string error;
auto dummy_extension =
Extension::Create(base::FilePath(), mojom::ManifestLocation::kInternal,
- base::Value::AsDictionaryValue(*result.value),
+ base::Value::AsDictionaryValue(*result),
Extension::FROM_WEBSTORE, extension_id, &error);
if (!dummy_extension) {
@@ -1323,30 +1322,4 @@ void WebstorePrivateGetExtensionStatusFunction::OnManifestParsed(
Respond(ArgumentList(GetExtensionStatus::Results::Create(api_status)));
}
-WebstorePrivateRequestExtensionFunction::
- WebstorePrivateRequestExtensionFunction() = default;
-WebstorePrivateRequestExtensionFunction::
- ~WebstorePrivateRequestExtensionFunction() = default;
-
-ExtensionFunction::ResponseAction
-WebstorePrivateRequestExtensionFunction::Run() {
- std::unique_ptr<RequestExtension::Params> params(
- RequestExtension::Params::Create(args()));
- EXTENSION_FUNCTION_VALIDATE(params);
-
- const ExtensionId& extension_id = params->id;
-
- if (!crx_file::id_util::IdIsValid(extension_id))
- return RespondNow(Error(kWebstoreInvalidIdError));
-
- Profile* profile = Profile::FromBrowserContext(browser_context());
- ExtensionInstallStatus status =
- AddExtensionToPendingList(extension_id, profile, std::string());
-
- api::webstore_private::ExtensionInstallStatus api_status =
- ConvertExtensionInstallStatusForAPI(status);
- return RespondNow(
- ArgumentList(RequestExtension::Results::Create(api_status)));
-}
-
} // namespace extensions
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 5a760f8490c..d5fc82d75f3 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
@@ -391,24 +391,6 @@ class WebstorePrivateGetExtensionStatusFunction : public ExtensionFunction {
ExtensionFunction::ResponseAction Run() override;
};
-class WebstorePrivateRequestExtensionFunction : public ExtensionFunction {
- public:
- DECLARE_EXTENSION_FUNCTION("webstorePrivate.requestExtension",
- WEBSTOREPRIVATE_REQUESTEXTENSION)
- WebstorePrivateRequestExtensionFunction();
-
- WebstorePrivateRequestExtensionFunction(
- const WebstorePrivateRequestExtensionFunction&) = delete;
- WebstorePrivateRequestExtensionFunction& operator=(
- const WebstorePrivateRequestExtensionFunction&) = delete;
-
- private:
- ~WebstorePrivateRequestExtensionFunction() override;
-
- // Extensionfunction:
- ExtensionFunction::ResponseAction Run() override;
-};
-
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_WEBSTORE_PRIVATE_WEBSTORE_PRIVATE_API_H_
diff --git a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
index 4d99658fb24..fca3f124bc8 100644
--- a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
+++ b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
@@ -598,7 +598,13 @@ class ExtensionWebstoreGetWebGLStatusTest : public InProcessBrowserTest {
};
// Tests getWebGLStatus function when WebGL is allowed.
-IN_PROC_BROWSER_TEST_F(ExtensionWebstoreGetWebGLStatusTest, Allowed) {
+// Flaky on Mac. https://crbug.com/1346413.
+#if BUILDFLAG(IS_MAC)
+#define MAYBE_Allowed DISABLED_Allowed
+#else
+#define MAYBE_Allowed Allowed
+#endif
+IN_PROC_BROWSER_TEST_F(ExtensionWebstoreGetWebGLStatusTest, MAYBE_Allowed) {
bool webgl_allowed = true;
RunTest(webgl_allowed);
}
diff --git a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_unittest.cc b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_unittest.cc
index ef7483b7ab9..67fd9d3319d 100644
--- a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_unittest.cc
+++ b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_unittest.cc
@@ -35,7 +35,6 @@ namespace extensions {
namespace {
constexpr char kInvalidId[] = "Invalid id";
constexpr char kExtensionId[] = "abcdefghijklmnopabcdefghijklmnop";
-constexpr int kFakeTime = 12345;
constexpr char kFakeJustification[] = "I need it!";
constexpr char kExtensionManifest[] = R"({
\"name\" : \"Extension\",
@@ -56,18 +55,6 @@ constexpr char kBlockOneExtensionSettings[] = R"({
}
})";
-constexpr char kAllowedExtensionSettings[] = R"({
- "abcdefghijklmnopabcdefghijklmnop" : {
- "installation_mode": "allowed"
- }
-})";
-
-constexpr char kBlockedExtensionSettings[] = R"({
- "abcdefghijklmnopabcdefghijklmnop" : {
- "installation_mode": "blocked"
- }
-})";
-
constexpr char kBlockedManifestTypeExtensionSettings[] = R"({
"*": {
"allowed_types": ["theme", "hosted_app"]
@@ -90,10 +77,6 @@ constexpr char kWebstoreUserCancelledError[] = "User cancelled install";
constexpr char kWebstoreBlockByPolicy[] =
"Extension installation is blocked by policy";
-base::Time GetFaketime() {
- return base::Time::FromJavaTime(kFakeTime);
-}
-
// Helper test struct used for holding data related to extension requests.
struct ExtensionRequestData {
explicit ExtensionRequestData(base::Time timestamp)
@@ -112,13 +95,12 @@ struct ExtensionRequestData {
void VerifyPendingList(const std::map<ExtensionId, ExtensionRequestData>&
expected_pending_requests,
Profile* profile) {
- const base::Value* actual_pending_requests =
- profile->GetPrefs()->GetDictionary(prefs::kCloudExtensionRequestIds);
- ASSERT_EQ(expected_pending_requests.size(),
- actual_pending_requests->DictSize());
+ const base::Value::Dict& actual_pending_requests =
+ profile->GetPrefs()->GetValueDict(prefs::kCloudExtensionRequestIds);
+ ASSERT_EQ(expected_pending_requests.size(), actual_pending_requests.size());
for (const auto& expected_request : expected_pending_requests) {
auto* actual_pending_request =
- actual_pending_requests->FindKey(expected_request.first);
+ actual_pending_requests.Find(expected_request.first);
ASSERT_NE(nullptr, actual_pending_request);
// All extensions in the pending list are expected to have a timestamp.
@@ -256,106 +238,6 @@ TEST_F(WebstorePrivateGetExtensionStatusTest,
response.get());
}
-class WebstorePrivateRequestExtensionTest
- : public WebstorePrivateExtensionInstallRequestBase {
- public:
- WebstorePrivateRequestExtensionTest() = default;
-
- void SetUp() override {
- WebstorePrivateExtensionInstallRequestBase::SetUp();
- profile()->GetTestingPrefService()->SetManagedPref(
- prefs::kCloudExtensionRequestEnabled,
- std::make_unique<base::Value>(true));
- VerifyPendingList({}, profile());
- }
-
- void SetPendingList(const std::vector<ExtensionId>& ids) {
- std::unique_ptr<base::Value> id_values =
- std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
- for (const auto& id : ids) {
- base::Value request_data(base::Value::Type::DICTIONARY);
- request_data.SetKey(extension_misc::kExtensionRequestTimestamp,
- ::base::TimeToValue(GetFaketime()));
- id_values->SetKey(id, std::move(request_data));
- }
- profile()->GetTestingPrefService()->SetUserPref(
- prefs::kCloudExtensionRequestIds, std::move(id_values));
- }
-
-};
-
-TEST_F(WebstorePrivateRequestExtensionTest, InvalidExtensionId) {
- auto function =
- base::MakeRefCounted<WebstorePrivateRequestExtensionFunction>();
- EXPECT_EQ(kInvalidId,
- RunFunctionAndReturnError(function.get(),
- GenerateArgs("invalid-extension-id")));
- VerifyPendingList({}, profile());
-}
-
-TEST_F(WebstorePrivateRequestExtensionTest, UnrequestableExtension) {
- ExtensionRegistry::Get(profile())->AddEnabled(CreateExtension(kExtensionId));
- auto function =
- base::MakeRefCounted<WebstorePrivateRequestExtensionFunction>();
- std::unique_ptr<base::Value> response =
- RunFunctionAndReturnValue(function.get(), GenerateArgs(kExtensionId));
- VerifyResponse(ExtensionInstallStatus::EXTENSION_INSTALL_STATUS_ENABLED,
- response.get());
- VerifyPendingList({}, profile());
-}
-
-TEST_F(WebstorePrivateRequestExtensionTest, AlreadyApprovedExtension) {
- SetExtensionSettings(kAllowedExtensionSettings, profile());
- auto function =
- base::MakeRefCounted<WebstorePrivateRequestExtensionFunction>();
- std::unique_ptr<base::Value> response =
- RunFunctionAndReturnValue(function.get(), GenerateArgs(kExtensionId));
- VerifyResponse(ExtensionInstallStatus::EXTENSION_INSTALL_STATUS_INSTALLABLE,
- response.get());
- VerifyPendingList({{kExtensionId, ExtensionRequestData(base::Time::Now())}},
- profile());
-}
-
-TEST_F(WebstorePrivateRequestExtensionTest, AlreadyRejectedExtension) {
- SetExtensionSettings(kBlockedExtensionSettings, profile());
- auto function =
- base::MakeRefCounted<WebstorePrivateRequestExtensionFunction>();
- std::unique_ptr<base::Value> response =
- RunFunctionAndReturnValue(function.get(), GenerateArgs(kExtensionId));
- VerifyResponse(
- ExtensionInstallStatus::EXTENSION_INSTALL_STATUS_BLOCKED_BY_POLICY,
- response.get());
- VerifyPendingList({{kExtensionId, ExtensionRequestData(base::Time::Now())}},
- profile());
-}
-
-TEST_F(WebstorePrivateRequestExtensionTest, AlreadyPendingExtension) {
- SetPendingList({kExtensionId});
- VerifyPendingList({{kExtensionId, ExtensionRequestData(GetFaketime())}},
- profile());
- auto function =
- base::MakeRefCounted<WebstorePrivateRequestExtensionFunction>();
- std::unique_ptr<base::Value> response =
- RunFunctionAndReturnValue(function.get(), GenerateArgs(kExtensionId));
- VerifyResponse(
- ExtensionInstallStatus::EXTENSION_INSTALL_STATUS_REQUEST_PENDING,
- response.get());
- VerifyPendingList({{kExtensionId, ExtensionRequestData(GetFaketime())}},
- profile());
-}
-
-TEST_F(WebstorePrivateRequestExtensionTest, RequestExtension) {
- auto function =
- base::MakeRefCounted<WebstorePrivateRequestExtensionFunction>();
- std::unique_ptr<base::Value> response =
- RunFunctionAndReturnValue(function.get(), GenerateArgs(kExtensionId));
- VerifyResponse(
- ExtensionInstallStatus::EXTENSION_INSTALL_STATUS_REQUEST_PENDING,
- response.get());
- VerifyPendingList({{kExtensionId, ExtensionRequestData(base::Time::Now())}},
- profile());
-}
-
class WebstorePrivateBeginInstallWithManifest3Test
: public ExtensionApiUnittest {
public: