• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 // Implements common functionality for the Chrome Extensions Cookies API.
6 
7 #include "chrome/browser/extensions/api/cookies/cookies_helpers.h"
8 
9 #include <vector>
10 
11 #include "base/logging.h"
12 #include "base/memory/linked_ptr.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/values.h"
17 #include "chrome/browser/extensions/api/cookies/cookies_api_constants.h"
18 #include "chrome/browser/extensions/extension_tab_util.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/common/extensions/api/cookies.h"
23 #include "chrome/common/url_constants.h"
24 #include "content/public/browser/web_contents.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/common/permissions/permissions_data.h"
27 #include "net/cookies/canonical_cookie.h"
28 #include "net/cookies/cookie_util.h"
29 #include "url/gurl.h"
30 
31 using extensions::api::cookies::Cookie;
32 using extensions::api::cookies::CookieStore;
33 
34 namespace GetAll = extensions::api::cookies::GetAll;
35 
36 namespace extensions {
37 
38 namespace keys = cookies_api_constants;
39 
40 namespace cookies_helpers {
41 
42 static const char kOriginalProfileStoreId[] = "0";
43 static const char kOffTheRecordProfileStoreId[] = "1";
44 
ChooseProfileFromStoreId(const std::string & store_id,Profile * profile,bool include_incognito)45 Profile* ChooseProfileFromStoreId(const std::string& store_id,
46                                   Profile* profile,
47                                   bool include_incognito) {
48   DCHECK(profile);
49   bool allow_original = !profile->IsOffTheRecord();
50   bool allow_incognito = profile->IsOffTheRecord() ||
51       (include_incognito && profile->HasOffTheRecordProfile());
52   if (store_id == kOriginalProfileStoreId && allow_original)
53     return profile->GetOriginalProfile();
54   if (store_id == kOffTheRecordProfileStoreId && allow_incognito)
55     return profile->GetOffTheRecordProfile();
56   return NULL;
57 }
58 
GetStoreIdFromProfile(Profile * profile)59 const char* GetStoreIdFromProfile(Profile* profile) {
60   DCHECK(profile);
61   return profile->IsOffTheRecord() ?
62       kOffTheRecordProfileStoreId : kOriginalProfileStoreId;
63 }
64 
CreateCookie(const net::CanonicalCookie & canonical_cookie,const std::string & store_id)65 scoped_ptr<Cookie> CreateCookie(
66     const net::CanonicalCookie& canonical_cookie,
67     const std::string& store_id) {
68   scoped_ptr<Cookie> cookie(new Cookie());
69 
70   // A cookie is a raw byte sequence. By explicitly parsing it as UTF-8, we
71   // apply error correction, so the string can be safely passed to the renderer.
72   cookie->name = base::UTF16ToUTF8(base::UTF8ToUTF16(canonical_cookie.Name()));
73   cookie->value =
74       base::UTF16ToUTF8(base::UTF8ToUTF16(canonical_cookie.Value()));
75   cookie->domain = canonical_cookie.Domain();
76   cookie->host_only = net::cookie_util::DomainIsHostOnly(
77       canonical_cookie.Domain());
78   // A non-UTF8 path is invalid, so we just replace it with an empty string.
79   cookie->path = base::IsStringUTF8(canonical_cookie.Path()) ?
80       canonical_cookie.Path() : std::string();
81   cookie->secure = canonical_cookie.IsSecure();
82   cookie->http_only = canonical_cookie.IsHttpOnly();
83   cookie->session = !canonical_cookie.IsPersistent();
84   if (canonical_cookie.IsPersistent()) {
85     cookie->expiration_date.reset(
86         new double(canonical_cookie.ExpiryDate().ToDoubleT()));
87   }
88   cookie->store_id = store_id;
89 
90   return cookie.Pass();
91 }
92 
CreateCookieStore(Profile * profile,base::ListValue * tab_ids)93 scoped_ptr<CookieStore> CreateCookieStore(Profile* profile,
94                                           base::ListValue* tab_ids) {
95   DCHECK(profile);
96   DCHECK(tab_ids);
97   base::DictionaryValue dict;
98   dict.SetString(keys::kIdKey, GetStoreIdFromProfile(profile));
99   dict.Set(keys::kTabIdsKey, tab_ids);
100 
101   CookieStore* cookie_store = new CookieStore();
102   bool rv = CookieStore::Populate(dict, cookie_store);
103   CHECK(rv);
104   return scoped_ptr<CookieStore>(cookie_store);
105 }
106 
GetCookieListFromStore(net::CookieStore * cookie_store,const GURL & url,const net::CookieMonster::GetCookieListCallback & callback)107 void GetCookieListFromStore(
108     net::CookieStore* cookie_store, const GURL& url,
109     const net::CookieMonster::GetCookieListCallback& callback) {
110   DCHECK(cookie_store);
111   net::CookieMonster* monster = cookie_store->GetCookieMonster();
112   if (!url.is_empty()) {
113     DCHECK(url.is_valid());
114     monster->GetAllCookiesForURLAsync(url, callback);
115   } else {
116     monster->GetAllCookiesAsync(callback);
117   }
118 }
119 
GetURLFromCanonicalCookie(const net::CanonicalCookie & cookie)120 GURL GetURLFromCanonicalCookie(const net::CanonicalCookie& cookie) {
121   const std::string& domain_key = cookie.Domain();
122   const std::string scheme =
123       cookie.IsSecure() ? url::kHttpsScheme : url::kHttpScheme;
124   const std::string host =
125       domain_key.find('.') != 0 ? domain_key : domain_key.substr(1);
126   return GURL(scheme + url::kStandardSchemeSeparator + host + "/");
127 }
128 
AppendMatchingCookiesToVector(const net::CookieList & all_cookies,const GURL & url,const GetAll::Params::Details * details,const Extension * extension,LinkedCookieVec * match_vector)129 void AppendMatchingCookiesToVector(const net::CookieList& all_cookies,
130                                    const GURL& url,
131                                    const GetAll::Params::Details* details,
132                                    const Extension* extension,
133                                    LinkedCookieVec* match_vector) {
134   net::CookieList::const_iterator it;
135   for (it = all_cookies.begin(); it != all_cookies.end(); ++it) {
136     // Ignore any cookie whose domain doesn't match the extension's
137     // host permissions.
138     GURL cookie_domain_url = GetURLFromCanonicalCookie(*it);
139     if (!extension->permissions_data()->HasHostPermission(cookie_domain_url))
140       continue;
141     // Filter the cookie using the match filter.
142     cookies_helpers::MatchFilter filter(details);
143     if (filter.MatchesCookie(*it)) {
144       match_vector->push_back(make_linked_ptr(
145           CreateCookie(*it, *details->store_id).release()));
146     }
147   }
148 }
149 
AppendToTabIdList(Browser * browser,base::ListValue * tab_ids)150 void AppendToTabIdList(Browser* browser, base::ListValue* tab_ids) {
151   DCHECK(browser);
152   DCHECK(tab_ids);
153   TabStripModel* tab_strip = browser->tab_strip_model();
154   for (int i = 0; i < tab_strip->count(); ++i) {
155     tab_ids->Append(new base::FundamentalValue(
156         ExtensionTabUtil::GetTabId(tab_strip->GetWebContentsAt(i))));
157   }
158 }
159 
MatchFilter(const GetAll::Params::Details * details)160 MatchFilter::MatchFilter(const GetAll::Params::Details* details)
161     : details_(details) {
162   DCHECK(details_);
163 }
164 
MatchesCookie(const net::CanonicalCookie & cookie)165 bool MatchFilter::MatchesCookie(
166     const net::CanonicalCookie& cookie) {
167   if (details_->name.get() && *details_->name != cookie.Name())
168     return false;
169 
170   if (!MatchesDomain(cookie.Domain()))
171     return false;
172 
173   if (details_->path.get() && *details_->path != cookie.Path())
174     return false;
175 
176   if (details_->secure.get() && *details_->secure != cookie.IsSecure())
177     return false;
178 
179   if (details_->session.get() && *details_->session != !cookie.IsPersistent())
180     return false;
181 
182   return true;
183 }
184 
MatchesDomain(const std::string & domain)185 bool MatchFilter::MatchesDomain(const std::string& domain) {
186   if (!details_->domain.get())
187     return true;
188 
189   // Add a leading '.' character to the filter domain if it doesn't exist.
190   if (net::cookie_util::DomainIsHostOnly(*details_->domain))
191     details_->domain->insert(0, ".");
192 
193   std::string sub_domain(domain);
194   // Strip any leading '.' character from the input cookie domain.
195   if (!net::cookie_util::DomainIsHostOnly(sub_domain))
196     sub_domain = sub_domain.substr(1);
197 
198   // Now check whether the domain argument is a subdomain of the filter domain.
199   for (sub_domain.insert(0, ".");
200        sub_domain.length() >= details_->domain->length();) {
201     if (sub_domain == *details_->domain)
202       return true;
203     const size_t next_dot = sub_domain.find('.', 1);  // Skip over leading dot.
204     sub_domain.erase(0, next_dot);
205   }
206   return false;
207 }
208 
209 }  // namespace cookies_helpers
210 }  // namespace extensions
211