1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/browsing_data/browsing_data_filter_builder_impl.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
13 #include "url/origin.h"
14
15 using net::registry_controlled_domains::GetDomainAndRegistry;
16 using net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES;
17
18 namespace content {
19
20 namespace {
21
22 // Whether this is a subdomain of a registrable domain.
IsSubdomainOfARegistrableDomain(const std::string & domain)23 bool IsSubdomainOfARegistrableDomain(const std::string& domain) {
24 std::string registrable_domain =
25 GetDomainAndRegistry(domain, INCLUDE_PRIVATE_REGISTRIES);
26 return registrable_domain != domain && registrable_domain != "";
27 }
28
29 // Note that for every domain, exactly one of the following holds:
30 // 1. GetDomainAndRegistry(domain, _) == "" - e.g. localhost, 127.0.0.1
31 // 2. GetDomainAndRegistry(domain, _) == domain - e.g. google.com
32 // 3. IsSubdomainOfARegistrableDomain(domain) - e.g. www.google.com
33 // Types 1 and 2 are supported by RegistrableDomainFilterBuilder. Type 3 is not.
34
35
36 // True if the domain of |url| is in the whitelist, or isn't in the blacklist.
37 // The whitelist or blacklist is represented as |origins|,
38 // |registerable_domains|, and |mode|.
MatchesURL(const std::set<url::Origin> & origins,const std::set<std::string> & registerable_domains,BrowsingDataFilterBuilder::Mode mode,const GURL & url)39 bool MatchesURL(
40 const std::set<url::Origin>& origins,
41 const std::set<std::string>& registerable_domains,
42 BrowsingDataFilterBuilder::Mode mode,
43 const GURL& url) {
44 std::string url_registerable_domain =
45 GetDomainAndRegistry(url, INCLUDE_PRIVATE_REGISTRIES);
46 bool found_domain =
47 (registerable_domains.find(
48 url_registerable_domain != "" ? url_registerable_domain
49 : url.host()) !=
50 registerable_domains.end());
51
52 bool found_origin = (origins.find(url::Origin::Create(url)) != origins.end());
53
54 return ((found_domain || found_origin) ==
55 (mode == BrowsingDataFilterBuilder::WHITELIST));
56 }
57
58 // True if none of the supplied domains matches this plugin's |site| and we're
59 // a blacklist, or one of them does and we're a whitelist. The whitelist or
60 // blacklist is represented by |domains_and_ips| and |mode|.
MatchesPluginSiteForRegisterableDomainsAndIPs(const std::set<std::string> & domains_and_ips,BrowsingDataFilterBuilder::Mode mode,const std::string & site)61 bool MatchesPluginSiteForRegisterableDomainsAndIPs(
62 const std::set<std::string>& domains_and_ips,
63 BrowsingDataFilterBuilder::Mode mode,
64 const std::string& site) {
65 // If |site| is a third- or lower-level domain, find the corresponding eTLD+1.
66 std::string domain_or_ip =
67 GetDomainAndRegistry(site, INCLUDE_PRIVATE_REGISTRIES);
68 if (domain_or_ip.empty())
69 domain_or_ip = site;
70
71 return ((mode == BrowsingDataFilterBuilder::WHITELIST) ==
72 (domains_and_ips.find(domain_or_ip) != domains_and_ips.end()));
73 }
74
75 } // namespace
76
77 // static
78 std::unique_ptr<BrowsingDataFilterBuilder>
Create(Mode mode)79 BrowsingDataFilterBuilder::Create(Mode mode) {
80 return std::make_unique<BrowsingDataFilterBuilderImpl>(mode);
81 }
82
83 // static
84 base::RepeatingCallback<bool(const GURL&)>
BuildNoopFilter()85 BrowsingDataFilterBuilder::BuildNoopFilter() {
86 return base::BindRepeating([](const GURL&) { return true; });
87 }
88
BrowsingDataFilterBuilderImpl(Mode mode)89 BrowsingDataFilterBuilderImpl::BrowsingDataFilterBuilderImpl(Mode mode)
90 : mode_(mode) {}
91
~BrowsingDataFilterBuilderImpl()92 BrowsingDataFilterBuilderImpl::~BrowsingDataFilterBuilderImpl() {}
93
AddOrigin(const url::Origin & origin)94 void BrowsingDataFilterBuilderImpl::AddOrigin(const url::Origin& origin) {
95 // TODO(msramek): Optimize OriginFilterBuilder for larger filters if needed.
96 DCHECK_LE(origins_.size(), 10U) << "OriginFilterBuilder is only suitable "
97 "for creating small filters.";
98
99 // By limiting the filter to non-unique origins, we can guarantee that
100 // origin1 < origin2 && origin1 > origin2 <=> origin1.isSameOrigin(origin2).
101 // This means that std::set::find() will use the same semantics for
102 // origin comparison as Origin::IsSameOriginWith(). Furthermore, this
103 // means that two filters are equal iff they are equal element-wise.
104 DCHECK(!origin.opaque()) << "Invalid origin passed into OriginFilter.";
105
106 // TODO(msramek): All urls with file scheme currently map to the same
107 // origin. This is currently not a problem, but if it becomes one,
108 // consider recognizing the URL path.
109
110 origins_.insert(origin);
111 }
112
AddRegisterableDomain(const std::string & domain)113 void BrowsingDataFilterBuilderImpl::AddRegisterableDomain(
114 const std::string& domain) {
115 // We check that the domain we're given is actually a eTLD+1, an IP address,
116 // or an internal hostname.
117 DCHECK(!IsSubdomainOfARegistrableDomain(domain));
118 domains_.insert(domain);
119 }
120
IsEmptyBlacklist()121 bool BrowsingDataFilterBuilderImpl::IsEmptyBlacklist() {
122 return mode_ == Mode::BLACKLIST && origins_.empty() && domains_.empty();
123 }
124
125 base::RepeatingCallback<bool(const GURL&)>
BuildGeneralFilter()126 BrowsingDataFilterBuilderImpl::BuildGeneralFilter() {
127 return base::BindRepeating(&MatchesURL, origins_, domains_, mode_);
128 }
129
130 network::mojom::ClearDataFilterPtr
BuildNetworkServiceFilter()131 BrowsingDataFilterBuilderImpl::BuildNetworkServiceFilter() {
132 if (IsEmptyBlacklist())
133 return nullptr;
134 network::mojom::ClearDataFilterPtr filter =
135 network::mojom::ClearDataFilter::New();
136 filter->type = (mode_ == Mode::WHITELIST)
137 ? network::mojom::ClearDataFilter::Type::DELETE_MATCHES
138 : network::mojom::ClearDataFilter::Type::KEEP_MATCHES;
139 filter->origins.insert(filter->origins.begin(), origins_.begin(),
140 origins_.end());
141 filter->domains.insert(filter->domains.begin(), domains_.begin(),
142 domains_.end());
143 return filter;
144 }
145
146 network::mojom::CookieDeletionFilterPtr
BuildCookieDeletionFilter()147 BrowsingDataFilterBuilderImpl::BuildCookieDeletionFilter() {
148 DCHECK(origins_.empty())
149 << "Origin-based deletion is not suitable for cookies. Please use "
150 "different scoping, such as RegistrableDomainFilterBuilder.";
151 auto deletion_filter = network::mojom::CookieDeletionFilter::New();
152
153 switch (mode_) {
154 case WHITELIST:
155 deletion_filter->including_domains.emplace(domains_.begin(),
156 domains_.end());
157 break;
158 case BLACKLIST:
159 deletion_filter->excluding_domains.emplace(domains_.begin(),
160 domains_.end());
161 break;
162 }
163 return deletion_filter;
164 }
165
166 base::RepeatingCallback<bool(const std::string& site)>
BuildPluginFilter()167 BrowsingDataFilterBuilderImpl::BuildPluginFilter() {
168 DCHECK(origins_.empty()) <<
169 "Origin-based deletion is not suitable for plugins. Please use "
170 "different scoping, such as RegistrableDomainFilterBuilder.";
171 return base::BindRepeating(&MatchesPluginSiteForRegisterableDomainsAndIPs,
172 domains_, mode_);
173 }
174
GetMode()175 BrowsingDataFilterBuilderImpl::Mode BrowsingDataFilterBuilderImpl::GetMode() {
176 return mode_;
177 }
178
179 std::unique_ptr<BrowsingDataFilterBuilder>
Copy()180 BrowsingDataFilterBuilderImpl::Copy() {
181 std::unique_ptr<BrowsingDataFilterBuilderImpl> copy =
182 std::make_unique<BrowsingDataFilterBuilderImpl>(mode_);
183 copy->origins_ = origins_;
184 copy->domains_ = domains_;
185 return std::move(copy);
186 }
187
operator ==(const BrowsingDataFilterBuilder & other)188 bool BrowsingDataFilterBuilderImpl::operator==(
189 const BrowsingDataFilterBuilder& other) {
190 // This is the only implementation of BrowsingDataFilterBuilder, so we can
191 // downcast |other|.
192 const BrowsingDataFilterBuilderImpl* other_impl =
193 static_cast<const BrowsingDataFilterBuilderImpl*>(&other);
194
195 return origins_ == other_impl->origins_ &&
196 domains_ == other_impl->domains_ &&
197 mode_ == other_impl->mode_;
198 }
199
200 } // namespace content
201