// Copyright 2020 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 "ui/webui/webui_allowlist.h" #include #include "base/memory/scoped_refptr.h" #include "base/sequence_checker.h" #include "base/supports_user_data.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/url_constants.h" #include "content/public/common/url_utils.h" #include "ui/webui/webui_allowlist_provider.h" #include "url/gurl.h" const char kWebUIAllowlistKeyName[] = "WebUIAllowlist"; namespace { struct WebUIAllowlistHolder : base::SupportsUserData::Data { explicit WebUIAllowlistHolder(scoped_refptr list) : allow_list(std::move(list)) {} const scoped_refptr allow_list; }; } // namespace // static WebUIAllowlist* WebUIAllowlist::GetOrCreate( content::BrowserContext* browser_context) { if (!browser_context->GetUserData(kWebUIAllowlistKeyName)) { auto list = base::MakeRefCounted(); browser_context->SetUserData( kWebUIAllowlistKeyName, std::make_unique(std::move(list))); } return static_cast( browser_context->GetUserData(kWebUIAllowlistKeyName)) ->allow_list.get(); } WebUIAllowlist::WebUIAllowlist() = default; WebUIAllowlist::~WebUIAllowlist() = default; void WebUIAllowlist::RegisterAutoGrantedPermission(const url::Origin& origin, ContentSettingsType type, ContentSetting setting) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(content::HasWebUIOrigin(origin)); // It doesn't make sense to grant a default content setting. DCHECK_NE(CONTENT_SETTING_DEFAULT, setting); SetContentSettingsAndNotifyProvider( ContentSettingsPattern::FromURLNoWildcard(origin.GetURL()), ContentSettingsPattern::Wildcard(), type, setting); } void WebUIAllowlist::RegisterAutoGrantedPermissions( const url::Origin& origin, std::initializer_list types) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); for (const ContentSettingsType& type : types) RegisterAutoGrantedPermission(origin, type); } void WebUIAllowlist::RegisterAutoGrantedThirdPartyCookies( const url::Origin& top_level_origin, const std::vector& origin_patterns) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(content::HasWebUIOrigin(top_level_origin)); const auto top_level_origin_pattern = ContentSettingsPattern::FromURLNoWildcard(top_level_origin.GetURL()); for (const auto& pattern : origin_patterns) { // For COOKIES content setting, |primary_pattern| is the origin setting the // cookie, |secondary_pattern| is the top-level document's origin. SetContentSettingsAndNotifyProvider(pattern, top_level_origin_pattern, ContentSettingsType::COOKIES, CONTENT_SETTING_ALLOW); } } void WebUIAllowlist::SetWebUIAllowlistProvider( WebUIAllowlistProvider* provider) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); provider_ = provider; } void WebUIAllowlist::ResetWebUIAllowlistProvider() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); provider_ = nullptr; } std::unique_ptr WebUIAllowlist::GetRuleIterator( ContentSettingsType content_type) const NO_THREAD_SAFETY_ANALYSIS { // NO_THREAD_SAFETY_ANALYSIS: GetRuleIterator immediately locks the lock. return value_map_.GetRuleIterator(content_type, &lock_); } void WebUIAllowlist::SetContentSettingsAndNotifyProvider( const ContentSettingsPattern& primary_pattern, const ContentSettingsPattern& secondary_pattern, ContentSettingsType type, ContentSetting setting) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); { base::AutoLock auto_lock(lock_); value_map_.SetValue(primary_pattern, secondary_pattern, type, base::Time(), base::Value(setting), /* constraints */ {}); } // Notify the provider. |provider_| can be nullptr if // HostContentSettingsRegistry is shutting down i.e. when Chrome shuts down. // // It's okay to notify the provider multiple times even if the setting isn't // changed. if (provider_) { provider_->NotifyContentSettingChange(primary_pattern, secondary_pattern, type); } }