blob: 496c57ea0a94dc324ada69d85c8bfc23b402574f [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/permissions/chrome_permissions_client.h"
#include <optional>
#include <vector>
#include "base/check_deref.h"
#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/functional/callback_helpers.h"
#include "base/no_destructor.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/browser/app_mode/app_mode_utils.h"
#include "chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.h"
#include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/cookie_settings_factory.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/engagement/important_sites_util.h"
#include "chrome/browser/media/webrtc/media_stream_device_permissions.h"
#include "chrome/browser/metrics/ukm_background_recorder_service.h"
#include "chrome/browser/permissions/origin_keyed_permission_action_service_factory.h"
#include "chrome/browser/permissions/permission_actions_history_factory.h"
#include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h"
#include "chrome/browser/permissions/permission_revocation_request.h"
#include "chrome/browser/permissions/prediction_service/prediction_based_permission_ui_selector.h"
#include "chrome/browser/permissions/pref_based_quiet_permission_ui_selector.h"
#include "chrome/browser/permissions/quiet_notification_permission_ui_config.h"
#include "chrome/browser/permissions/system/system_permission_settings.h"
#include "chrome/browser/privacy_sandbox/tracking_protection_settings_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
#include "chrome/browser/serial/serial_chooser_context.h"
#include "chrome/browser/serial/serial_chooser_context_factory.h"
#include "chrome/browser/subresource_filter/subresource_filter_profile_context_factory.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/hats/hats_service.h"
#include "chrome/browser/ui/hats/hats_service_factory.h"
#include "chrome/browser/ui/hats/survey_config.h"
#include "chrome/browser/ui/page_info/page_info_infobar_delegate.h"
#include "chrome/browser/usb/usb_chooser_context.h"
#include "chrome/browser/usb/usb_chooser_context_factory.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/branded_strings.h"
#include "components/content_settings/core/browser/content_settings_type_set.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/google/core/common/google_util.h"
#include "components/infobars/content/content_infobar_manager.h"
#include "components/infobars/core/infobar_manager.h"
#include "components/permissions/constants.h"
#include "components/permissions/contexts/bluetooth_chooser_context.h"
#include "components/permissions/features.h"
#include "components/permissions/permission_hats_trigger_helper.h"
#include "components/permissions/permission_request.h"
#include "components/permissions/permission_uma_util.h"
#include "components/permissions/permission_util.h"
#include "components/permissions/permissions_client.h"
#include "components/permissions/request_type.h"
#include "components/prefs/pref_service.h"
#include "components/privacy_sandbox/tracking_protection_settings.h"
#include "components/site_engagement/content/site_engagement_service.h"
#include "components/subresource_filter/content/browser/subresource_filter_content_settings_manager.h"
#include "components/subresource_filter/content/browser/subresource_filter_profile_context.h"
#include "components/unified_consent/pref_names.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/web_contents.h"
#include "extensions/buildflags/buildflags.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/origin.h"
#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/android/resource_mapper.h"
#include "chrome/browser/android/search_permissions/search_permissions_service.h"
#include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/permissions/permission_blocked_message_delegate_android.h"
#include "chrome/browser/permissions/permission_update_message_controller_android.h"
#include "components/permissions/permission_request_manager.h"
#else
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/permission_bubble/permission_prompt.h"
#include "components/vector_icons/vector_icons.h"
#endif
#if BUILDFLAG(IS_CHROMEOS)
#include "ash/constants/ash_features.h"
#include "chrome/browser/ash/app_mode/isolated_web_app/kiosk_iwa_data.h"
#include "chrome/browser/ash/app_mode/isolated_web_app/kiosk_iwa_manager.h"
#include "chrome/browser/ash/app_mode/web_app/kiosk_web_app_data.h"
#include "chrome/browser/ash/app_mode/web_app/kiosk_web_app_manager.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_types.h"
#include "chromeos/components/kiosk/kiosk_utils.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "extensions/common/constants.h"
#endif
#if BUILDFLAG(SAFE_BROWSING_AVAILABLE)
#include "chrome/browser/permissions/prediction_service/contextual_notification_permission_ui_selector.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#endif
namespace {
using PreviewParametersForHats =
permissions::PermissionHatsTriggerHelper::PreviewParametersForHats;
using permissions::PermissionPromptDisposition;
using permissions::PermissionPromptDispositionReason;
using permissions::PermissionRequest;
using permissions::PermissionRequestGestureType;
#if BUILDFLAG(IS_ANDROID)
bool ShouldUseQuietUI(content::WebContents* web_contents,
ContentSettingsType type) {
auto* manager =
permissions::PermissionRequestManager::FromWebContents(web_contents);
if (type != ContentSettingsType::NOTIFICATIONS &&
type != ContentSettingsType::GEOLOCATION) {
return false;
}
return manager->ShouldCurrentRequestUseQuietUI();
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
std::optional<url::Origin> GetCurrentKioskOrigin() {
if (chromeos::IsWebKioskSession()) {
const AccountId& account_id =
user_manager::UserManager::Get()->GetPrimaryUser()->GetAccountId();
DCHECK(ash::KioskWebAppManager::IsInitialized());
const ash::KioskWebAppData* app_data =
ash::KioskWebAppManager::Get()->GetAppByAccountId(account_id);
DCHECK(app_data);
return url::Origin::Create(app_data->install_url());
}
if (chromeos::IsIwaKioskSession()) {
const AccountId& account_id =
user_manager::UserManager::Get()->GetPrimaryUser()->GetAccountId();
const ash::KioskIwaData* iwa_data =
CHECK_DEREF(ash::KioskIwaManager::Get()).GetApp(account_id);
return CHECK_DEREF(iwa_data).origin();
}
return std::nullopt;
}
#endif
bool IsPermissionSetByAdministator(ContentSetting setting,
const content_settings::SettingInfo& info) {
return ((setting == ContentSetting::CONTENT_SETTING_BLOCK ||
setting == ContentSetting::CONTENT_SETTING_ALLOW) &&
(info.source == content_settings::SettingSource::kPolicy ||
info.source == content_settings::SettingSource::kSupervised));
}
#if !BUILDFLAG(IS_ANDROID)
// TODO(crbug.com/412616723): Support Android
bool ShouldShowInfobarOnPromptResolved(
content::WebContents* web_contents,
const PermissionRequest* request,
std::optional<permissions::PermissionsClient::QuietUiReason>
quiet_ui_reason,
permissions::PermissionAction action) {
if (!quiet_ui_reason ||
(action != permissions::PermissionAction::GRANTED &&
action != permissions::PermissionAction::GRANTED_ONCE) ||
(request->request_type() != permissions::RequestType::kNotifications &&
request->request_type() != permissions::RequestType::kGeolocation)) {
return false;
}
content::PermissionController* permission_controller =
web_contents->GetBrowserContext()->GetPermissionController();
if (!permission_controller) {
return false;
}
if (request->IsSourceSubscribedToPermissionChangeEvent(
permission_controller)) {
return false;
}
return true;
}
void ShowInfobar(content::WebContents* web_contents) {
infobars::ContentInfoBarManager* infobar_manager =
infobars::ContentInfoBarManager::FromWebContents(web_contents);
if (!infobar_manager) {
return;
}
PageInfoInfoBarDelegate::Create(infobar_manager);
}
#endif
} // namespace
// static
ChromePermissionsClient* ChromePermissionsClient::GetInstance() {
static base::NoDestructor<ChromePermissionsClient> instance;
return instance.get();
}
HostContentSettingsMap* ChromePermissionsClient::GetSettingsMap(
content::BrowserContext* browser_context) {
return HostContentSettingsMapFactory::GetForProfile(
Profile::FromBrowserContext(browser_context));
}
scoped_refptr<content_settings::CookieSettings>
ChromePermissionsClient::GetCookieSettings(
content::BrowserContext* browser_context) {
return CookieSettingsFactory::GetForProfile(
Profile::FromBrowserContext(browser_context));
}
privacy_sandbox::TrackingProtectionSettings*
ChromePermissionsClient::GetTrackingProtectionSettings(
content::BrowserContext* browser_context) {
return TrackingProtectionSettingsFactory::GetForProfile(
Profile::FromBrowserContext(browser_context));
}
bool ChromePermissionsClient::IsSubresourceFilterActivated(
content::BrowserContext* browser_context,
const GURL& url) {
return SubresourceFilterProfileContextFactory::GetForProfile(
Profile::FromBrowserContext(browser_context))
->settings_manager()
->GetSiteActivationFromMetadata(url);
}
permissions::ObjectPermissionContextBase*
ChromePermissionsClient::GetChooserContext(
content::BrowserContext* browser_context,
ContentSettingsType type) {
switch (type) {
case ContentSettingsType::USB_CHOOSER_DATA:
return UsbChooserContextFactory::GetForProfile(
Profile::FromBrowserContext(browser_context));
case ContentSettingsType::BLUETOOTH_CHOOSER_DATA:
return BluetoothChooserContextFactory::GetForProfile(
Profile::FromBrowserContext(browser_context));
case ContentSettingsType::SERIAL_CHOOSER_DATA:
return SerialChooserContextFactory::GetForProfile(
Profile::FromBrowserContext(browser_context));
default:
NOTREACHED();
}
}
permissions::OriginKeyedPermissionActionService*
ChromePermissionsClient::GetOriginKeyedPermissionActionService(
content::BrowserContext* browser_context) {
return OriginKeyedPermissionActionServiceFactory::GetForProfile(
Profile::FromBrowserContext(browser_context));
}
permissions::PermissionActionsHistory*
ChromePermissionsClient::GetPermissionActionsHistory(
content::BrowserContext* browser_context) {
return PermissionActionsHistoryFactory::GetForProfile(
Profile::FromBrowserContext(browser_context));
}
permissions::PermissionDecisionAutoBlocker*
ChromePermissionsClient::GetPermissionDecisionAutoBlocker(
content::BrowserContext* browser_context) {
return PermissionDecisionAutoBlockerFactory::GetForProfile(
Profile::FromBrowserContext(browser_context));
}
double ChromePermissionsClient::GetSiteEngagementScore(
content::BrowserContext* browser_context,
const GURL& origin) {
return site_engagement::SiteEngagementService::Get(
Profile::FromBrowserContext(browser_context))
->GetScore(origin);
}
void ChromePermissionsClient::AreSitesImportant(
content::BrowserContext* browser_context,
std::vector<std::pair<url::Origin, bool>>* origins) {
// We need to limit our size due to the algorithm in ImportantSiteUtil,
// but we want to be more on the liberal side here as we're not exposing
// these sites to the user, we're just using them for our 'clear
// unimportant' feature in ManageSpaceActivity.java.
const int kMaxImportantSites = 10;
std::vector<site_engagement::ImportantSitesUtil::ImportantDomainInfo>
important_domains =
site_engagement::ImportantSitesUtil::GetImportantRegisterableDomains(
Profile::FromBrowserContext(browser_context), kMaxImportantSites);
for (auto& entry : *origins) {
const url::Origin& origin = entry.first;
const std::string& host = origin.host();
std::string registerable_domain =
net::registry_controlled_domains::GetDomainAndRegistry(
origin,
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
if (registerable_domain.empty()) {
registerable_domain = host; // IP address or internal hostname.
}
entry.second = base::Contains(important_domains, registerable_domain,
&site_engagement::ImportantSitesUtil::
ImportantDomainInfo::registerable_domain);
}
}
// Some Google-affiliated domains are not allowed to delete cookies for
// supervised accounts.
bool ChromePermissionsClient::IsCookieDeletionDisabled(
content::BrowserContext* browser_context,
const GURL& origin) {
if (!Profile::FromBrowserContext(browser_context)->IsChild()) {
return false;
}
return google_util::IsYoutubeDomainUrl(origin, google_util::ALLOW_SUBDOMAIN,
google_util::ALLOW_NON_STANDARD_PORTS);
}
void ChromePermissionsClient::GetUkmSourceId(
ContentSettingsType permission_type,
content::BrowserContext* browser_context,
content::WebContents* web_contents,
const GURL& requesting_origin,
GetUkmSourceIdCallback callback) {
if (web_contents) {
ukm::SourceId source_id =
web_contents->GetPrimaryMainFrame()->GetPageUkmSourceId();
std::move(callback).Run(source_id);
} else if (permission_type == ContentSettingsType::NOTIFICATIONS) {
ukm::SourceId source_id =
ukm::UkmRecorder::GetSourceIdForNotificationPermission(
base::PassKey<ChromePermissionsClient>(), requesting_origin);
std::move(callback).Run(source_id);
} else {
// We only record a permission change if the origin is in the user's
// history.
ukm::UkmBackgroundRecorderFactory::GetForProfile(
Profile::FromBrowserContext(browser_context))
->GetBackgroundSourceIdIfAllowed(url::Origin::Create(requesting_origin),
std::move(callback));
}
}
permissions::IconId ChromePermissionsClient::GetOverrideIconId(
permissions::RequestType request_type) {
#if BUILDFLAG(IS_CHROMEOS)
// TODO(xhwang): fix this icon, see crbug.com/446263.
if (request_type == permissions::RequestType::kProtectedMediaIdentifier) {
return vector_icons::kProductIcon;
}
#endif
return PermissionsClient::GetOverrideIconId(request_type);
}
// Triggers the prompt HaTS survey if enabled by field trials for this
// combination of prompt parameters.
void ChromePermissionsClient::TriggerPromptHatsSurveyIfEnabled(
content::WebContents* web_contents,
permissions::RequestType request_type,
std::optional<permissions::PermissionAction> action,
PermissionPromptDisposition prompt_disposition,
PermissionPromptDispositionReason prompt_disposition_reason,
PermissionRequestGestureType gesture_type,
std::optional<base::TimeDelta> prompt_display_duration,
bool is_post_prompt,
const GURL& gurl,
std::optional<permissions::feature_params::PermissionElementPromptPosition>
pepc_prompt_position,
ContentSetting initial_permission_status,
base::OnceCallback<void()> hats_shown_callback,
std::optional<PreviewParametersForHats> preview_parameters) {
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
std::optional<GURL> recorded_gurl =
profile->GetPrefs()->GetBoolean(
unified_consent::prefs::kUrlKeyedAnonymizedDataCollectionEnabled)
? std::make_optional(gurl)
: std::nullopt;
auto prompt_parameters =
permissions::PermissionHatsTriggerHelper::PromptParametersForHats(
request_type, action, prompt_disposition, prompt_disposition_reason,
gesture_type,
std::string(version_info::GetChannelString(chrome::GetChannel())),
is_post_prompt ? permissions::kOnPromptResolved
: permissions::kOnPromptAppearing,
prompt_display_duration,
permissions::PermissionHatsTriggerHelper::
GetOneTimePromptsDecidedBucket(profile->GetPrefs()),
recorded_gurl, pepc_prompt_position, initial_permission_status,
preview_parameters);
if (!permissions::PermissionHatsTriggerHelper::
ArePromptTriggerCriteriaSatisfied(prompt_parameters)) {
return;
}
std::optional<
permissions::PermissionHatsTriggerHelper::SurveyParametersForHats>
survey_parameters = permissions::PermissionHatsTriggerHelper::
GetSurveyParametersForRequestType(request_type);
auto* hats_service =
HatsServiceFactory::GetForProfile(profile,
/*create_if_necessary=*/true);
if (!hats_service || !survey_parameters.has_value()) {
return;
}
auto survey_data = permissions::PermissionHatsTriggerHelper::
SurveyProductSpecificData::PopulateFrom(prompt_parameters);
hats_service->LaunchSurvey(
kHatsSurveyTriggerPermissionsPrompt, std::move(hats_shown_callback),
base::DoNothing(), survey_data.survey_bits_data,
survey_data.survey_string_data, survey_parameters->supplied_trigger_id,
HatsService::SurveyOptions(survey_parameters->custom_survey_invitation,
survey_parameters->message_identifier));
}
#if !BUILDFLAG(IS_ANDROID)
permissions::PermissionIgnoredReason
ChromePermissionsClient::DetermineIgnoreReason(
content::WebContents* web_contents) {
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
Browser* browser = chrome::FindLastActiveWithProfile(profile);
if (browser) {
if (browser->tab_strip_model()->empty()) {
return permissions::PermissionIgnoredReason::WINDOW_CLOSED;
} else if (web_contents->IsBeingDestroyed()) {
return permissions::PermissionIgnoredReason::TAB_CLOSED;
} else {
return permissions::PermissionIgnoredReason::NAVIGATION;
}
}
return permissions::PermissionIgnoredReason::UNKNOWN;
}
#endif
std::vector<std::unique_ptr<permissions::PermissionUiSelector>>
ChromePermissionsClient::CreatePermissionUiSelectors(
content::BrowserContext* browser_context) {
std::vector<std::unique_ptr<permissions::PermissionUiSelector>> selectors;
#if BUILDFLAG(SAFE_BROWSING_AVAILABLE)
selectors.emplace_back(
std::make_unique<ContextualNotificationPermissionUiSelector>());
#endif
selectors.emplace_back(std::make_unique<PrefBasedQuietPermissionUiSelector>(
Profile::FromBrowserContext(browser_context)));
selectors.emplace_back(std::make_unique<PredictionBasedPermissionUiSelector>(
Profile::FromBrowserContext(browser_context)));
return selectors;
}
void ChromePermissionsClient::OnPromptResolved(
const PermissionRequest* request,
permissions::PermissionAction action,
PermissionPromptDisposition prompt_disposition,
PermissionPromptDispositionReason prompt_disposition_reason,
std::optional<QuietUiReason> quiet_ui_reason,
base::TimeDelta prompt_display_duration,
std::optional<permissions::feature_params::PermissionElementPromptPosition>
pepc_prompt_position,
ContentSetting initial_permission_status,
content::WebContents* web_contents) {
permissions::RequestType request_type = request->request_type();
const GURL& origin = request->requesting_origin();
PermissionRequestGestureType gesture_type = request->GetGestureType();
std::optional<PreviewParametersForHats> preview_parameters =
request->get_preview_parameters();
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
PermissionActionsHistoryFactory::GetForProfile(profile)->RecordAction(
action, request_type, prompt_disposition);
if (request_type == permissions::RequestType::kNotifications) {
if (action == permissions::PermissionAction::GRANTED &&
quiet_ui_reason.has_value() &&
(quiet_ui_reason.value() ==
QuietUiReason::kTriggeredDueToAbusiveRequests ||
quiet_ui_reason.value() ==
QuietUiReason::kTriggeredDueToAbusiveContent ||
quiet_ui_reason.value() ==
QuietUiReason::kTriggeredDueToDisruptiveBehavior)) {
PermissionRevocationRequest::ExemptOriginFromFutureRevocations(profile,
origin);
}
#if BUILDFLAG(SAFE_BROWSING_AVAILABLE)
if (action == permissions::PermissionAction::GRANTED) {
if (g_browser_process->safe_browsing_service()) {
g_browser_process->safe_browsing_service()
->MaybeSendNotificationsAcceptedReport(
web_contents->GetPrimaryMainFrame(), profile,
web_contents->GetLastCommittedURL(),
web_contents->GetController().GetLastCommittedEntry()->GetURL(),
origin, prompt_display_duration);
}
}
#endif
}
#if !BUILDFLAG(IS_ANDROID)
// TODO(crbug.com/412616723): Support Android
if (base::FeatureList::IsEnabled(
permissions::features::kPermissionPromiseLifetimeModulation)) {
if (ShouldShowInfobarOnPromptResolved(web_contents, request,
quiet_ui_reason, action)) {
ShowInfobar(web_contents);
}
}
#endif
auto content_setting_type = RequestTypeToContentSettingsType(request_type);
if (content_setting_type.has_value()) {
permissions::PermissionHatsTriggerHelper::
IncrementOneTimePermissionPromptsDecidedIfApplicable(
content_setting_type.value(), profile->GetPrefs());
}
TriggerPromptHatsSurveyIfEnabled(
web_contents, request_type, std::make_optional(action),
prompt_disposition, prompt_disposition_reason, gesture_type,
std::make_optional(prompt_display_duration), /*is_post_prompt=*/true,
web_contents->GetPrimaryMainFrame()->GetLastCommittedOrigin().GetURL(),
pepc_prompt_position, initial_permission_status, base::DoNothing(),
preview_parameters);
}
std::optional<bool>
ChromePermissionsClient::HadThreeConsecutiveNotificationPermissionDenies(
content::BrowserContext* browser_context) {
if (!QuietNotificationPermissionUiConfig::
IsAdaptiveActivationDryRunEnabled()) {
return std::nullopt;
}
return Profile::FromBrowserContext(browser_context)
->GetPrefs()
->GetBoolean(prefs::kHadThreeConsecutiveNotificationPermissionDenies);
}
std::optional<bool> ChromePermissionsClient::HasPreviouslyAutoRevokedPermission(
content::BrowserContext* browser_context,
const GURL& origin,
ContentSettingsType permission) {
if (permission != ContentSettingsType::NOTIFICATIONS) {
return std::nullopt;
}
Profile* profile = Profile::FromBrowserContext(browser_context);
return PermissionRevocationRequest::HasPreviouslyRevokedPermission(profile,
origin);
}
std::optional<url::Origin> ChromePermissionsClient::GetAutoApprovalOrigin(
content::BrowserContext* browser_context) {
#if BUILDFLAG(IS_CHROMEOS)
// In kiosk mode for web apps and isolated web apps, all permission requests
// are auto-approved for the origin of the main app.
std::optional<url::Origin> current_kiosk_origin = GetCurrentKioskOrigin();
if (current_kiosk_origin.has_value()) {
return current_kiosk_origin;
}
// In Shimless RMA mode, permission requests are auto-approved during runtime
// since the app has requested all permissions during install time.
if (ash::features::IsShimlessRMA3pDiagnosticsAllowPermissionPolicyEnabled() &&
ash::IsShimlessRmaAppBrowserContext(browser_context)) {
return ash::shimless_rma::DiagnosticsAppProfileHelperDelegate::
GetInstalledDiagnosticsAppOrigin();
}
#endif
return std::nullopt;
}
std::optional<permissions::PermissionAction>
ChromePermissionsClient::GetAutoApprovalStatus(
content::BrowserContext* browser_context,
const GURL& origin) {
if (base::FeatureList::IsEnabled(
permissions::features::kAllowMultipleOriginsForWebKioskPermissions)) {
Profile* profile = Profile::FromBrowserContext(browser_context);
if (IsWebKioskOriginAllowed(profile->GetPrefs(), origin)) {
return permissions::PermissionAction::GRANTED;
}
}
std::optional<url::Origin> auto_approval_origin =
GetAutoApprovalOrigin(browser_context);
if (!auto_approval_origin.has_value()) {
return std::nullopt;
}
if (url::Origin::Create(origin) == auto_approval_origin.value()) {
return permissions::PermissionAction::GRANTED;
}
return permissions::PermissionAction::IGNORED;
}
bool ChromePermissionsClient::CanBypassEmbeddingOriginCheck(
const GURL& requesting_origin,
const GURL& embedding_origin) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
// Extensions are excluded from origin checks as currently they can request
// permission from iframes when embedded in non-secure contexts
// (https://crbug.com/530507).
if (requesting_origin.SchemeIs(extensions::kExtensionScheme)) {
return true;
}
#endif
// The New Tab Page is excluded from origin checks as its effective
// requesting origin may be the Default Search Engine origin.
return embedding_origin ==
GURL(chrome::kChromeUINewTabURL).DeprecatedGetOriginAsURL() ||
embedding_origin ==
GURL(chrome::kChromeUINewTabPageURL).DeprecatedGetOriginAsURL();
}
std::optional<GURL> ChromePermissionsClient::OverrideCanonicalOrigin(
const GURL& requesting_origin,
const GURL& embedding_origin) {
if (embedding_origin.DeprecatedGetOriginAsURL() ==
GURL(chrome::kChromeUINewTabURL).DeprecatedGetOriginAsURL()) {
if (requesting_origin.DeprecatedGetOriginAsURL() ==
GURL(chrome::kChromeUINewTabPageURL).DeprecatedGetOriginAsURL()) {
return GURL(UIThreadSearchTermsData().GoogleBaseURLValue())
.DeprecatedGetOriginAsURL();
}
return requesting_origin;
}
#if BUILDFLAG(ENABLE_EXTENSIONS)
// Note that currently chrome extensions are allowed to use permissions even
// when in embedded in non-secure contexts. This is unfortunate and we
// should remove this at some point, but for now always use the requesting
// origin for embedded extensions. https://crbug.com/530507.
if (requesting_origin.SchemeIs(extensions::kExtensionScheme)) {
return requesting_origin;
}
#endif
return std::nullopt;
}
bool ChromePermissionsClient::DoURLsMatchNewTabPage(
const GURL& requesting_origin,
const GURL& embedding_origin) {
return embedding_origin ==
GURL(chrome::kChromeUINewTabURL).DeprecatedGetOriginAsURL() &&
requesting_origin ==
GURL(chrome::kChromeUINewTabPageURL).DeprecatedGetOriginAsURL();
}
#if BUILDFLAG(IS_ANDROID)
bool ChromePermissionsClient::IsDseOrigin(
content::BrowserContext* browser_context,
const url::Origin& origin) {
SearchPermissionsService* search_helper =
SearchPermissionsService::Factory::GetForBrowserContext(browser_context);
return search_helper && search_helper->IsDseOrigin(origin);
}
std::unique_ptr<ChromePermissionsClient::PermissionMessageDelegate>
ChromePermissionsClient::MaybeCreateMessageUI(
content::WebContents* web_contents,
ContentSettingsType type,
base::WeakPtr<permissions::PermissionPromptAndroid> prompt) {
if (ShouldUseQuietUI(web_contents, type)) {
auto delegate =
std::make_unique<PermissionBlockedMessageDelegate::Delegate>(
std::move(prompt));
return std::make_unique<PermissionBlockedMessageDelegate>(
web_contents, std::move(delegate));
}
return {};
}
void ChromePermissionsClient::RepromptForAndroidPermissions(
content::WebContents* web_contents,
const std::vector<ContentSettingsType>& content_settings_types,
const std::vector<ContentSettingsType>& filtered_content_settings_types,
const std::vector<std::string>& required_permissions,
const std::vector<std::string>& optional_permissions,
PermissionsUpdatedCallback callback) {
PermissionUpdateMessageController::CreateForWebContents(web_contents);
PermissionUpdateMessageController::FromWebContents(web_contents)
->ShowMessage(content_settings_types, filtered_content_settings_types,
required_permissions, optional_permissions,
std::move(callback));
}
int ChromePermissionsClient::MapToJavaDrawableId(int resource_id) {
return ResourceMapper::MapToJavaDrawableId(resource_id);
}
favicon::FaviconService* ChromePermissionsClient::GetFaviconService(
content::BrowserContext* browser_context) {
return FaviconServiceFactory::GetForProfile(
Profile::FromBrowserContext(browser_context),
ServiceAccessType::EXPLICIT_ACCESS);
}
const std::u16string ChromePermissionsClient::GetClientApplicationName() const {
return l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
}
#else
std::unique_ptr<permissions::PermissionPrompt>
ChromePermissionsClient::CreatePrompt(
content::WebContents* web_contents,
permissions::PermissionPrompt::Delegate* delegate) {
return CreatePermissionPrompt(web_contents, delegate);
}
#endif
bool ChromePermissionsClient::HasDevicePermission(
ContentSettingsType type) const {
#if BUILDFLAG(IS_MAC)
return system_permission_settings::IsAllowed(type);
#else
return PermissionsClient::HasDevicePermission(type);
#endif
}
bool ChromePermissionsClient::CanRequestDevicePermission(
ContentSettingsType type) const {
#if BUILDFLAG(IS_MAC)
return system_permission_settings::CanPrompt(type);
#else
return PermissionsClient::CanRequestDevicePermission(type);
#endif
}
// TODO(41014586): Integrate policy-set media permissions into
// SettingsSource.policy. Currently, AudioCaptureAllowed, VideoCaptureAllowed
// are not checked within |IsPermissionSetByAdministrator|, so
// |IsPermissionBlockedByDevicePolicy| and |IsPermissionAllowedByDevicePolicy|
// methods are needed to show the appropriate policy screen.
bool ChromePermissionsClient::IsPermissionBlockedByDevicePolicy(
content::WebContents* web_contents,
ContentSetting setting,
const content_settings::SettingInfo& info,
ContentSettingsType type) const {
if (IsPermissionSetByAdministator(setting, info) &&
setting == CONTENT_SETTING_BLOCK) {
return true;
}
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
if (type == ContentSettingsType::MEDIASTREAM_MIC) {
return GetDevicePolicy(profile, web_contents->GetLastCommittedURL(),
prefs::kAudioCaptureAllowed,
prefs::kAudioCaptureAllowedUrls) ==
MediaStreamDevicePolicy::ALWAYS_DENY;
}
if (type == ContentSettingsType::MEDIASTREAM_CAMERA) {
return GetDevicePolicy(profile, web_contents->GetLastCommittedURL(),
prefs::kVideoCaptureAllowed,
prefs::kVideoCaptureAllowedUrls) ==
MediaStreamDevicePolicy::ALWAYS_DENY;
}
return false;
}
bool ChromePermissionsClient::IsPermissionAllowedByDevicePolicy(
content::WebContents* web_contents,
ContentSetting setting,
const content_settings::SettingInfo& info,
ContentSettingsType type) const {
if (IsPermissionSetByAdministator(setting, info) &&
setting == CONTENT_SETTING_ALLOW) {
return true;
}
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
if (type == ContentSettingsType::MEDIASTREAM_MIC) {
return GetDevicePolicy(profile, web_contents->GetLastCommittedURL(),
prefs::kAudioCaptureAllowed,
prefs::kAudioCaptureAllowedUrls) ==
MediaStreamDevicePolicy::ALWAYS_ALLOW;
}
if (type == ContentSettingsType::MEDIASTREAM_CAMERA) {
return GetDevicePolicy(profile, web_contents->GetLastCommittedURL(),
prefs::kVideoCaptureAllowed,
prefs::kVideoCaptureAllowedUrls) ==
MediaStreamDevicePolicy::ALWAYS_ALLOW;
}
return false;
}
bool ChromePermissionsClient::IsSystemDenied(ContentSettingsType type) const {
return system_permission_settings::IsDenied(type);
}
bool ChromePermissionsClient::CanPromptSystemPermission(
ContentSettingsType type) const {
return system_permission_settings::CanPrompt(type);
}