mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	Add "cef/" prefix for CEF #includes in libcef/ directory. Sort #includes by following https://google.github.io/styleguide/cppguide.html#Names_and_Order_of_Includes
		
			
				
	
	
		
			311 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (c) 2011 The Chromium Embedded Framework 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 "cef/libcef/browser/origin_whitelist_impl.h"
 | |
| 
 | |
| #include <string>
 | |
| #include <vector>
 | |
| 
 | |
| #include "base/functional/bind.h"
 | |
| #include "base/lazy_instance.h"
 | |
| #include "base/synchronization/lock.h"
 | |
| #include "cef/include/cef_origin_whitelist.h"
 | |
| #include "cef/libcef/browser/browser_manager.h"
 | |
| #include "cef/libcef/browser/context.h"
 | |
| #include "cef/libcef/browser/thread_util.h"
 | |
| #include "cef/libcef/common/mojom/cef.mojom.h"
 | |
| #include "chrome/common/webui_url_constants.h"
 | |
| #include "content/public/browser/render_process_host.h"
 | |
| #include "content/public/common/url_constants.h"
 | |
| #include "extensions/common/constants.h"
 | |
| #include "url/gurl.h"
 | |
| #include "url/origin.h"
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| // Class that manages cross-origin whitelist registrations.
 | |
| class CefOriginWhitelistManager {
 | |
|  public:
 | |
|   CefOriginWhitelistManager() = default;
 | |
| 
 | |
|   CefOriginWhitelistManager(const CefOriginWhitelistManager&) = delete;
 | |
|   CefOriginWhitelistManager& operator=(const CefOriginWhitelistManager&) =
 | |
|       delete;
 | |
| 
 | |
|   // Retrieve the singleton instance.
 | |
|   static CefOriginWhitelistManager* GetInstance();
 | |
| 
 | |
|   bool AddOriginEntry(const std::string& source_origin,
 | |
|                       const std::string& target_protocol,
 | |
|                       const std::string& target_domain,
 | |
|                       bool allow_target_subdomains) {
 | |
|     auto info = cef::mojom::CrossOriginWhiteListEntry::New();
 | |
|     info->source_origin = source_origin;
 | |
|     info->target_protocol = target_protocol;
 | |
|     info->target_domain = target_domain;
 | |
|     info->allow_target_subdomains = allow_target_subdomains;
 | |
| 
 | |
|     {
 | |
|       base::AutoLock lock_scope(lock_);
 | |
| 
 | |
|       // Verify that the origin entry doesn't already exist.
 | |
|       for (const auto& entry : origin_list_) {
 | |
|         if (entry == info) {
 | |
|           return false;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       origin_list_.push_back(info->Clone());
 | |
|     }
 | |
| 
 | |
|     SendModifyCrossOriginWhitelistEntry(true, info);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool RemoveOriginEntry(const std::string& source_origin,
 | |
|                          const std::string& target_protocol,
 | |
|                          const std::string& target_domain,
 | |
|                          bool allow_target_subdomains) {
 | |
|     auto info = cef::mojom::CrossOriginWhiteListEntry::New();
 | |
|     info->source_origin = source_origin;
 | |
|     info->target_protocol = target_protocol;
 | |
|     info->target_domain = target_domain;
 | |
|     info->allow_target_subdomains = allow_target_subdomains;
 | |
| 
 | |
|     bool found = false;
 | |
| 
 | |
|     {
 | |
|       base::AutoLock lock_scope(lock_);
 | |
| 
 | |
|       CrossOriginWhiteList::iterator it = origin_list_.begin();
 | |
|       for (; it != origin_list_.end(); ++it) {
 | |
|         if (*it == info) {
 | |
|           origin_list_.erase(it);
 | |
|           found = true;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (!found) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     SendModifyCrossOriginWhitelistEntry(false, info);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   void ClearOrigins() {
 | |
|     {
 | |
|       base::AutoLock lock_scope(lock_);
 | |
|       origin_list_.clear();
 | |
|     }
 | |
| 
 | |
|     SendClearCrossOriginWhitelist();
 | |
|   }
 | |
| 
 | |
|   void GetCrossOriginWhitelistEntries(
 | |
|       std::optional<CrossOriginWhiteList>* entries) const {
 | |
|     base::AutoLock lock_scope(lock_);
 | |
| 
 | |
|     if (!origin_list_.empty()) {
 | |
|       CrossOriginWhiteList vec;
 | |
|       for (const auto& entry : origin_list_) {
 | |
|         vec.push_back(entry->Clone());
 | |
|       }
 | |
|       *entries = std::move(vec);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   bool HasCrossOriginWhitelistEntry(const url::Origin& source,
 | |
|                                     const url::Origin& target) const {
 | |
|     base::AutoLock lock_scope(lock_);
 | |
| 
 | |
|     if (!origin_list_.empty()) {
 | |
|       for (const auto& entry : origin_list_) {
 | |
|         if (IsMatch(source, target, entry)) {
 | |
|           return true;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   // Send the modify cross-origin whitelist entry message to all currently
 | |
|   // existing hosts.
 | |
|   static void SendModifyCrossOriginWhitelistEntry(
 | |
|       bool add,
 | |
|       const cef::mojom::CrossOriginWhiteListEntryPtr& info) {
 | |
|     CEF_REQUIRE_UIT();
 | |
| 
 | |
|     content::RenderProcessHost::iterator i(
 | |
|         content::RenderProcessHost::AllHostsIterator());
 | |
|     for (; !i.IsAtEnd(); i.Advance()) {
 | |
|       auto render_manager =
 | |
|           CefBrowserManager::GetRenderManagerForProcess(i.GetCurrentValue());
 | |
|       render_manager->ModifyCrossOriginWhitelistEntry(add, info->Clone());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Send the clear cross-origin whitelists message to all currently existing
 | |
|   // hosts.
 | |
|   static void SendClearCrossOriginWhitelist() {
 | |
|     CEF_REQUIRE_UIT();
 | |
| 
 | |
|     content::RenderProcessHost::iterator i(
 | |
|         content::RenderProcessHost::AllHostsIterator());
 | |
|     for (; !i.IsAtEnd(); i.Advance()) {
 | |
|       auto render_manager =
 | |
|           CefBrowserManager::GetRenderManagerForProcess(i.GetCurrentValue());
 | |
|       render_manager->ClearCrossOriginWhitelist();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   static bool IsMatch(const url::Origin& source_origin,
 | |
|                       const url::Origin& target_origin,
 | |
|                       const cef::mojom::CrossOriginWhiteListEntryPtr& param) {
 | |
|     if (!source_origin.IsSameOriginWith(
 | |
|             url::Origin::Create(GURL(param->source_origin)))) {
 | |
|       // Source origin does not match.
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     if (target_origin.scheme() != param->target_protocol) {
 | |
|       // Target scheme does not match.
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     if (param->allow_target_subdomains) {
 | |
|       if (param->target_domain.empty()) {
 | |
|         // Any domain will match.
 | |
|         return true;
 | |
|       } else {
 | |
|         // Match sub-domains.
 | |
|         return target_origin.DomainIs(param->target_domain.c_str());
 | |
|       }
 | |
|     } else {
 | |
|       // Match full domain.
 | |
|       return (target_origin.host() == param->target_domain);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   mutable base::Lock lock_;
 | |
| 
 | |
|   // List of registered origins. Access must be protected by |lock_|.
 | |
|   CrossOriginWhiteList origin_list_;
 | |
| };
 | |
| 
 | |
| base::LazyInstance<CefOriginWhitelistManager>::Leaky g_manager =
 | |
|     LAZY_INSTANCE_INITIALIZER;
 | |
| 
 | |
| CefOriginWhitelistManager* CefOriginWhitelistManager::GetInstance() {
 | |
|   return g_manager.Pointer();
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| bool CefAddCrossOriginWhitelistEntry(const CefString& source_origin,
 | |
|                                      const CefString& target_protocol,
 | |
|                                      const CefString& target_domain,
 | |
|                                      bool allow_target_subdomains) {
 | |
|   // Verify that the context is in a valid state.
 | |
|   if (!CONTEXT_STATE_VALID()) {
 | |
|     DCHECK(false);
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   std::string source_url = source_origin;
 | |
|   GURL gurl = GURL(source_url);
 | |
|   if (gurl.is_empty() || !gurl.is_valid()) {
 | |
|     DCHECK(false) << "Invalid source_origin URL: " << source_url;
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (CEF_CURRENTLY_ON_UIT()) {
 | |
|     return CefOriginWhitelistManager::GetInstance()->AddOriginEntry(
 | |
|         source_origin, target_protocol, target_domain, allow_target_subdomains);
 | |
|   } else {
 | |
|     CEF_POST_TASK(
 | |
|         CEF_UIT,
 | |
|         base::BindOnce(base::IgnoreResult(&CefAddCrossOriginWhitelistEntry),
 | |
|                        source_origin, target_protocol, target_domain,
 | |
|                        allow_target_subdomains));
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool CefRemoveCrossOriginWhitelistEntry(const CefString& source_origin,
 | |
|                                         const CefString& target_protocol,
 | |
|                                         const CefString& target_domain,
 | |
|                                         bool allow_target_subdomains) {
 | |
|   // Verify that the context is in a valid state.
 | |
|   if (!CONTEXT_STATE_VALID()) {
 | |
|     DCHECK(false);
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   std::string source_url = source_origin;
 | |
|   GURL gurl = GURL(source_url);
 | |
|   if (gurl.is_empty() || !gurl.is_valid()) {
 | |
|     DCHECK(false) << "Invalid source_origin URL: " << source_url;
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (CEF_CURRENTLY_ON_UIT()) {
 | |
|     return CefOriginWhitelistManager::GetInstance()->RemoveOriginEntry(
 | |
|         source_origin, target_protocol, target_domain, allow_target_subdomains);
 | |
|   } else {
 | |
|     CEF_POST_TASK(
 | |
|         CEF_UIT,
 | |
|         base::BindOnce(base::IgnoreResult(&CefRemoveCrossOriginWhitelistEntry),
 | |
|                        source_origin, target_protocol, target_domain,
 | |
|                        allow_target_subdomains));
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool CefClearCrossOriginWhitelist() {
 | |
|   // Verify that the context is in a valid state.
 | |
|   if (!CONTEXT_STATE_VALID()) {
 | |
|     DCHECK(false);
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (CEF_CURRENTLY_ON_UIT()) {
 | |
|     CefOriginWhitelistManager::GetInstance()->ClearOrigins();
 | |
|   } else {
 | |
|     CEF_POST_TASK(
 | |
|         CEF_UIT,
 | |
|         base::BindOnce(base::IgnoreResult(&CefClearCrossOriginWhitelist)));
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void GetCrossOriginWhitelistEntries(
 | |
|     std::optional<CrossOriginWhiteList>* entries) {
 | |
|   CefOriginWhitelistManager::GetInstance()->GetCrossOriginWhitelistEntries(
 | |
|       entries);
 | |
| }
 | |
| 
 | |
| bool HasCrossOriginWhitelistEntry(const url::Origin& source,
 | |
|                                   const url::Origin& target) {
 | |
|   // Components of chrome that are implemented as extensions or platform apps
 | |
|   // are allowed to use chrome://resources/ and chrome://theme/ URLs.
 | |
|   // See also RegisterNonNetworkSubresourceURLLoaderFactories.
 | |
|   if (source.scheme() == extensions::kExtensionScheme &&
 | |
|       target.scheme() == content::kChromeUIScheme &&
 | |
|       (target.host() == chrome::kChromeUIThemeHost ||
 | |
|        target.host() == content::kChromeUIResourcesHost)) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   return CefOriginWhitelistManager::GetInstance()->HasCrossOriginWhitelistEntry(
 | |
|       source, target);
 | |
| }
 |