Home | History | Annotate | Download | only in cookies
      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 
     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 
     59 const char* GetStoreIdFromProfile(Profile* profile) {
     60   DCHECK(profile);
     61   return profile->IsOffTheRecord() ?
     62       kOffTheRecordProfileStoreId : kOriginalProfileStoreId;
     63 }
     64 
     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 
     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 
    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 
    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 
    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 
    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 
    160 MatchFilter::MatchFilter(const GetAll::Params::Details* details)
    161     : details_(details) {
    162   DCHECK(details_);
    163 }
    164 
    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 
    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