Home | History | Annotate | Download | only in extensions
      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 
     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 
     42 const char* GetStoreIdFromProfile(Profile* profile) {
     43   DCHECK(profile);
     44   return profile->IsOffTheRecord() ?
     45       kOffTheRecordProfileStoreId : kOriginalProfileStoreId;
     46 }
     47 
     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 
     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 
     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 
     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 
    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 
    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 
    133 MatchFilter::MatchFilter(const DictionaryValue* details)
    134     : details_(details) {
    135   DCHECK(details_);
    136 }
    137 
    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 
    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 
    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 
    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