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