2012-04-03 03:34:16 +02:00
|
|
|
// 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 "libcef/browser/origin_whitelist_impl.h"
|
|
|
|
|
|
|
|
#include <string>
|
2012-11-20 21:08:36 +01:00
|
|
|
#include <vector>
|
2012-04-03 03:34:16 +02:00
|
|
|
|
|
|
|
#include "include/cef_origin_whitelist.h"
|
|
|
|
#include "libcef/browser/context.h"
|
|
|
|
#include "libcef/browser/thread_util.h"
|
|
|
|
#include "libcef/common/cef_messages.h"
|
|
|
|
|
|
|
|
#include "base/bind.h"
|
|
|
|
#include "base/lazy_instance.h"
|
2012-11-20 21:08:36 +01:00
|
|
|
#include "base/synchronization/lock.h"
|
2020-08-14 21:28:23 +02:00
|
|
|
#include "chrome/common/webui_url_constants.h"
|
2012-04-03 03:34:16 +02:00
|
|
|
#include "content/public/browser/render_process_host.h"
|
2020-08-14 21:28:23 +02:00
|
|
|
#include "content/public/common/url_constants.h"
|
|
|
|
#include "extensions/common/constants.h"
|
2013-07-24 22:15:18 +02:00
|
|
|
#include "url/gurl.h"
|
2020-08-14 21:28:23 +02:00
|
|
|
#include "url/origin.h"
|
2012-04-03 03:34:16 +02:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// Class that manages cross-origin whitelist registrations.
|
|
|
|
class CefOriginWhitelistManager {
|
|
|
|
public:
|
|
|
|
CefOriginWhitelistManager() {}
|
|
|
|
|
|
|
|
// 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) {
|
2012-11-20 21:08:36 +01:00
|
|
|
Cef_CrossOriginWhiteListEntry_Params info;
|
2012-04-03 03:34:16 +02:00
|
|
|
info.source_origin = source_origin;
|
|
|
|
info.target_protocol = target_protocol;
|
|
|
|
info.target_domain = target_domain;
|
|
|
|
info.allow_target_subdomains = allow_target_subdomains;
|
|
|
|
|
2012-11-20 21:08:36 +01:00
|
|
|
{
|
|
|
|
base::AutoLock lock_scope(lock_);
|
2012-04-03 03:34:16 +02:00
|
|
|
|
2012-11-20 21:08:36 +01:00
|
|
|
// Verify that the origin entry doesn't already exist.
|
|
|
|
OriginList::const_iterator it = origin_list_.begin();
|
|
|
|
for (; it != origin_list_.end(); ++it) {
|
|
|
|
if (IsEqual(*it, info))
|
|
|
|
return false;
|
|
|
|
}
|
2012-04-03 03:34:16 +02:00
|
|
|
|
2012-11-20 21:08:36 +01:00
|
|
|
origin_list_.push_back(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
SendModifyCrossOriginWhitelistEntry(true, info);
|
2012-04-03 03:34:16 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RemoveOriginEntry(const std::string& source_origin,
|
|
|
|
const std::string& target_protocol,
|
|
|
|
const std::string& target_domain,
|
|
|
|
bool allow_target_subdomains) {
|
2012-11-20 21:08:36 +01:00
|
|
|
Cef_CrossOriginWhiteListEntry_Params info;
|
2012-04-03 03:34:16 +02:00
|
|
|
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;
|
|
|
|
|
2012-11-20 21:08:36 +01:00
|
|
|
{
|
|
|
|
base::AutoLock lock_scope(lock_);
|
|
|
|
|
|
|
|
OriginList::iterator it = origin_list_.begin();
|
|
|
|
for (; it != origin_list_.end(); ++it) {
|
|
|
|
if (IsEqual(*it, info)) {
|
|
|
|
origin_list_.erase(it);
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
return false;
|
|
|
|
|
2012-11-20 21:08:36 +01:00
|
|
|
SendModifyCrossOriginWhitelistEntry(false, info);
|
2012-04-03 03:34:16 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClearOrigins() {
|
2012-11-20 21:08:36 +01:00
|
|
|
{
|
|
|
|
base::AutoLock lock_scope(lock_);
|
|
|
|
origin_list_.clear();
|
|
|
|
}
|
2012-04-03 03:34:16 +02:00
|
|
|
|
|
|
|
SendClearCrossOriginWhitelist();
|
|
|
|
}
|
|
|
|
|
2012-11-20 21:08:36 +01:00
|
|
|
void GetCrossOriginWhitelistEntries(
|
|
|
|
std::vector<Cef_CrossOriginWhiteListEntry_Params>* entries) {
|
|
|
|
base::AutoLock lock_scope(lock_);
|
2012-04-03 03:34:16 +02:00
|
|
|
|
|
|
|
if (origin_list_.empty())
|
|
|
|
return;
|
2012-11-20 21:08:36 +01:00
|
|
|
entries->insert(entries->end(), origin_list_.begin(), origin_list_.end());
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Send the modify cross-origin whitelist entry message to all currently
|
|
|
|
// existing hosts.
|
2012-11-20 21:08:36 +01:00
|
|
|
static void SendModifyCrossOriginWhitelistEntry(
|
|
|
|
bool add,
|
|
|
|
Cef_CrossOriginWhiteListEntry_Params& params) {
|
2012-04-03 03:34:16 +02:00
|
|
|
CEF_REQUIRE_UIT();
|
|
|
|
|
|
|
|
content::RenderProcessHost::iterator i(
|
|
|
|
content::RenderProcessHost::AllHostsIterator());
|
|
|
|
for (; !i.IsAtEnd(); i.Advance()) {
|
|
|
|
i.GetCurrentValue()->Send(
|
2012-11-20 21:08:36 +01:00
|
|
|
new CefProcessMsg_ModifyCrossOriginWhitelistEntry(add, params));
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the clear cross-origin whitelists message to all currently existing
|
|
|
|
// hosts.
|
2012-11-20 21:08:36 +01:00
|
|
|
static void SendClearCrossOriginWhitelist() {
|
2012-04-03 03:34:16 +02:00
|
|
|
CEF_REQUIRE_UIT();
|
|
|
|
|
|
|
|
content::RenderProcessHost::iterator i(
|
|
|
|
content::RenderProcessHost::AllHostsIterator());
|
|
|
|
for (; !i.IsAtEnd(); i.Advance()) {
|
|
|
|
i.GetCurrentValue()->Send(new CefProcessMsg_ClearCrossOriginWhitelist);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-20 21:08:36 +01:00
|
|
|
static bool IsEqual(const Cef_CrossOriginWhiteListEntry_Params& param1,
|
|
|
|
const Cef_CrossOriginWhiteListEntry_Params& param2) {
|
|
|
|
return (param1.source_origin == param2.source_origin &&
|
|
|
|
param1.target_protocol == param2.target_protocol &&
|
|
|
|
param1.target_domain == param2.target_domain &&
|
|
|
|
param1.allow_target_subdomains == param2.allow_target_subdomains);
|
|
|
|
}
|
|
|
|
|
|
|
|
base::Lock lock_;
|
2012-04-03 03:34:16 +02:00
|
|
|
|
2012-11-20 21:08:36 +01:00
|
|
|
// List of registered origins. Access must be protected by |lock_|.
|
|
|
|
typedef std::vector<Cef_CrossOriginWhiteListEntry_Params> OriginList;
|
2012-04-03 03:34:16 +02:00
|
|
|
OriginList origin_list_;
|
|
|
|
|
2015-12-09 17:10:16 +01:00
|
|
|
DISALLOW_COPY_AND_ASSIGN(CefOriginWhitelistManager);
|
2012-04-03 03:34:16 +02:00
|
|
|
};
|
|
|
|
|
2017-04-20 21:28:17 +02:00
|
|
|
base::LazyInstance<CefOriginWhitelistManager>::Leaky g_manager =
|
2012-04-03 03:34:16 +02:00
|
|
|
LAZY_INSTANCE_INITIALIZER;
|
|
|
|
|
|
|
|
CefOriginWhitelistManager* CefOriginWhitelistManager::GetInstance() {
|
|
|
|
return g_manager.Pointer();
|
|
|
|
}
|
|
|
|
|
2020-08-14 21:28:23 +02:00
|
|
|
bool IsMatch(const url::Origin& source_origin,
|
|
|
|
const url::Origin& target_origin,
|
2013-04-18 19:58:23 +02:00
|
|
|
const Cef_CrossOriginWhiteListEntry_Params& param) {
|
2020-08-14 21:28:23 +02:00
|
|
|
if (!source_origin.IsSameOriginWith(
|
|
|
|
url::Origin::Create(GURL(param.source_origin)))) {
|
2013-04-18 19:58:23 +02:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-03 03:34:16 +02:00
|
|
|
} // 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()) {
|
|
|
|
NOTREACHED();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string source_url = source_origin;
|
|
|
|
GURL gurl = GURL(source_url);
|
|
|
|
if (gurl.is_empty() || !gurl.is_valid()) {
|
|
|
|
NOTREACHED() << "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 {
|
2017-05-17 11:29:28 +02:00
|
|
|
CEF_POST_TASK(
|
|
|
|
CEF_UIT,
|
2012-04-03 03:34:16 +02:00
|
|
|
base::Bind(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()) {
|
|
|
|
NOTREACHED();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string source_url = source_origin;
|
|
|
|
GURL gurl = GURL(source_url);
|
|
|
|
if (gurl.is_empty() || !gurl.is_valid()) {
|
|
|
|
NOTREACHED() << "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 {
|
2017-05-17 11:29:28 +02:00
|
|
|
CEF_POST_TASK(
|
|
|
|
CEF_UIT,
|
2012-04-03 03:34:16 +02:00
|
|
|
base::Bind(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()) {
|
|
|
|
NOTREACHED();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CEF_CURRENTLY_ON_UIT()) {
|
|
|
|
CefOriginWhitelistManager::GetInstance()->ClearOrigins();
|
|
|
|
} else {
|
2017-05-17 11:29:28 +02:00
|
|
|
CEF_POST_TASK(
|
|
|
|
CEF_UIT, base::Bind(base::IgnoreResult(&CefClearCrossOriginWhitelist)));
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-11-20 21:08:36 +01:00
|
|
|
void GetCrossOriginWhitelistEntries(
|
|
|
|
std::vector<Cef_CrossOriginWhiteListEntry_Params>* entries) {
|
|
|
|
CefOriginWhitelistManager::GetInstance()->GetCrossOriginWhitelistEntries(
|
|
|
|
entries);
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
2013-04-18 19:58:23 +02:00
|
|
|
|
2020-08-14 21:28:23 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-04-18 19:58:23 +02:00
|
|
|
std::vector<Cef_CrossOriginWhiteListEntry_Params> params;
|
|
|
|
CefOriginWhitelistManager::GetInstance()->GetCrossOriginWhitelistEntries(
|
|
|
|
¶ms);
|
|
|
|
|
|
|
|
if (params.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::vector<Cef_CrossOriginWhiteListEntry_Params>::const_iterator it =
|
|
|
|
params.begin();
|
|
|
|
for (; it != params.end(); ++it) {
|
|
|
|
if (IsMatch(source, target, *it))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|