• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 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/extension_cookies_helpers.h"
8 
9 #include "base/logging.h"
10 #include "base/values.h"
11 #include "chrome/browser/extensions/extension_cookies_api_constants.h"
12 #include "chrome/browser/extensions/extension_tabs_module.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/tabs/tab_strip_model.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
17 #include "chrome/common/extensions/extension.h"
18 #include "chrome/common/url_constants.h"
19 #include "googleurl/src/gurl.h"
20 
21 namespace keys = extension_cookies_api_constants;
22 
23 namespace extension_cookies_helpers {
24 
25 static const char kOriginalProfileStoreId[] = "0";
26 static const char kOffTheRecordProfileStoreId[] = "1";
27 
ChooseProfileFromStoreId(const std::string & store_id,Profile * profile,bool include_incognito)28 Profile* ChooseProfileFromStoreId(const std::string& store_id,
29                                   Profile* profile,
30                                   bool include_incognito) {
31   DCHECK(profile);
32   bool allow_original = !profile->IsOffTheRecord();
33   bool allow_incognito = profile->IsOffTheRecord() ||
34       (include_incognito && profile->HasOffTheRecordProfile());
35   if (store_id == kOriginalProfileStoreId && allow_original)
36     return profile->GetOriginalProfile();
37   if (store_id == kOffTheRecordProfileStoreId && allow_incognito)
38     return profile->GetOffTheRecordProfile();
39   return NULL;
40 }
41 
GetStoreIdFromProfile(Profile * profile)42 const char* GetStoreIdFromProfile(Profile* profile) {
43   DCHECK(profile);
44   return profile->IsOffTheRecord() ?
45       kOffTheRecordProfileStoreId : kOriginalProfileStoreId;
46 }
47 
CreateCookieValue(const net::CookieMonster::CanonicalCookie & cookie,const std::string & store_id)48 DictionaryValue* CreateCookieValue(
49     const net::CookieMonster::CanonicalCookie& cookie,
50     const std::string& store_id) {
51   DictionaryValue* result = new DictionaryValue();
52 
53   result->SetString(keys::kNameKey, cookie.Name());
54   result->SetString(keys::kValueKey, cookie.Value());
55   result->SetString(keys::kDomainKey, cookie.Domain());
56   result->SetBoolean(keys::kHostOnlyKey,
57                      net::CookieMonster::DomainIsHostOnly(cookie.Domain()));
58   result->SetString(keys::kPathKey, cookie.Path());
59   result->SetBoolean(keys::kSecureKey, cookie.IsSecure());
60   result->SetBoolean(keys::kHttpOnlyKey, cookie.IsHttpOnly());
61   result->SetBoolean(keys::kSessionKey, !cookie.DoesExpire());
62   if (cookie.DoesExpire()) {
63     result->SetDouble(keys::kExpirationDateKey,
64                       cookie.ExpiryDate().ToDoubleT());
65   }
66   result->SetString(keys::kStoreIdKey, store_id);
67 
68   return result;
69 }
70 
CreateCookieStoreValue(Profile * profile,ListValue * tab_ids)71 DictionaryValue* CreateCookieStoreValue(Profile* profile,
72                                         ListValue* tab_ids) {
73   DCHECK(profile);
74   DCHECK(tab_ids);
75   DictionaryValue* result = new DictionaryValue();
76   result->SetString(keys::kIdKey, GetStoreIdFromProfile(profile));
77   result->Set(keys::kTabIdsKey, tab_ids);
78   return result;
79 }
80 
GetCookieListFromStore(net::CookieStore * cookie_store,const GURL & url)81 net::CookieList GetCookieListFromStore(
82     net::CookieStore* cookie_store, const GURL& url) {
83   DCHECK(cookie_store);
84   net::CookieMonster* monster = cookie_store->GetCookieMonster();
85   if (!url.is_empty()) {
86     DCHECK(url.is_valid());
87     return monster->GetAllCookiesForURL(url);
88   }
89   return monster->GetAllCookies();
90 }
91 
GetURLFromCanonicalCookie(const net::CookieMonster::CanonicalCookie & cookie)92 GURL GetURLFromCanonicalCookie(
93     const net::CookieMonster::CanonicalCookie& cookie) {
94   const std::string& domain_key = cookie.Domain();
95   const std::string scheme =
96       cookie.IsSecure() ? chrome::kHttpsScheme : chrome::kHttpScheme;
97   const std::string host =
98       domain_key.find('.') != 0 ? domain_key : domain_key.substr(1);
99   return GURL(scheme + chrome::kStandardSchemeSeparator + host + "/");
100 }
101 
AppendMatchingCookiesToList(const net::CookieList & all_cookies,const std::string & store_id,const GURL & url,const DictionaryValue * details,const Extension * extension,ListValue * match_list)102 void AppendMatchingCookiesToList(
103     const net::CookieList& all_cookies,
104     const std::string& store_id,
105     const GURL& url, const DictionaryValue* details,
106     const Extension* extension,
107     ListValue* match_list) {
108   net::CookieList::const_iterator it;
109   for (it = all_cookies.begin(); it != all_cookies.end(); ++it) {
110     // Ignore any cookie whose domain doesn't match the extension's
111     // host permissions.
112     GURL cookie_domain_url = GetURLFromCanonicalCookie(*it);
113     if (!extension->HasHostPermission(cookie_domain_url))
114       continue;
115     // Filter the cookie using the match filter.
116     extension_cookies_helpers::MatchFilter filter(details);
117     if (filter.MatchesCookie(*it))
118       match_list->Append(CreateCookieValue(*it, store_id));
119   }
120 }
121 
AppendToTabIdList(Browser * browser,ListValue * tab_ids)122 void AppendToTabIdList(Browser* browser, ListValue* tab_ids) {
123   DCHECK(browser);
124   DCHECK(tab_ids);
125   TabStripModel* tab_strip = browser->tabstrip_model();
126   for (int i = 0; i < tab_strip->count(); ++i) {
127     tab_ids->Append(Value::CreateIntegerValue(
128         ExtensionTabUtil::GetTabId(
129             tab_strip->GetTabContentsAt(i)->tab_contents())));
130   }
131 }
132 
MatchFilter(const DictionaryValue * details)133 MatchFilter::MatchFilter(const DictionaryValue* details)
134     : details_(details) {
135   DCHECK(details_);
136 }
137 
MatchesCookie(const net::CookieMonster::CanonicalCookie & cookie)138 bool MatchFilter::MatchesCookie(
139     const net::CookieMonster::CanonicalCookie& cookie) {
140   return MatchesString(keys::kNameKey, cookie.Name()) &&
141          MatchesDomain(cookie.Domain()) &&
142          MatchesString(keys::kPathKey, cookie.Path()) &&
143          MatchesBoolean(keys::kSecureKey, cookie.IsSecure()) &&
144          MatchesBoolean(keys::kSessionKey, !cookie.DoesExpire());
145 }
146 
MatchesString(const char * key,const std::string & value)147 bool MatchFilter::MatchesString(const char* key, const std::string& value) {
148   if (!details_->HasKey(key))
149     return true;
150   std::string filter_value;
151   return (details_->GetString(key, &filter_value) &&
152           value == filter_value);
153 }
154 
MatchesBoolean(const char * key,bool value)155 bool MatchFilter::MatchesBoolean(const char* key, bool value) {
156   if (!details_->HasKey(key))
157     return true;
158   bool filter_value = false;
159   return (details_->GetBoolean(key, &filter_value) &&
160           value == filter_value);
161 }
162 
MatchesDomain(const std::string & domain)163 bool MatchFilter::MatchesDomain(const std::string& domain) {
164   if (!details_->HasKey(keys::kDomainKey))
165     return true;
166 
167   std::string filter_value;
168   if (!details_->GetString(keys::kDomainKey, &filter_value))
169     return false;
170   // Add a leading '.' character to the filter domain if it doesn't exist.
171   if (net::CookieMonster::DomainIsHostOnly(filter_value))
172     filter_value.insert(0, ".");
173 
174   std::string sub_domain(domain);
175   // Strip any leading '.' character from the input cookie domain.
176   if (!net::CookieMonster::DomainIsHostOnly(sub_domain))
177     sub_domain = sub_domain.substr(1);
178 
179   // Now check whether the domain argument is a subdomain of the filter domain.
180   for (sub_domain.insert(0, ".");
181        sub_domain.length() >= filter_value.length();) {
182     if (sub_domain == filter_value)
183       return true;
184     const size_t next_dot = sub_domain.find('.', 1);  // Skip over leading dot.
185     sub_domain.erase(0, next_dot);
186   }
187   return false;
188 }
189 
190 }  // namespace extension_cookies_helpers
191