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