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 #include "chrome/browser/ui/webui/cookies_tree_model_util.h" 6 7 #include <vector> 8 9 #include "base/i18n/time_formatting.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/stl_util.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_split.h" 14 #include "base/strings/string_util.h" 15 #include "base/values.h" 16 #include "chrome/browser/browsing_data/cookies_tree_model.h" 17 #include "chrome/grit/generated_resources.h" 18 #include "content/public/browser/indexed_db_context.h" 19 #include "content/public/browser/service_worker_context.h" 20 #include "net/cookies/canonical_cookie.h" 21 #include "net/ssl/ssl_client_cert_type.h" 22 #include "storage/common/fileapi/file_system_types.h" 23 #include "ui/base/l10n/l10n_util.h" 24 #include "ui/base/text/bytes_formatting.h" 25 26 #if defined(ENABLE_EXTENSIONS) 27 #include "extensions/common/extension_set.h" 28 #endif 29 30 namespace { 31 32 const char kKeyId[] = "id"; 33 const char kKeyTitle[] = "title"; 34 const char kKeyIcon[] = "icon"; 35 const char kKeyType[] = "type"; 36 const char kKeyHasChildren[] = "hasChildren"; 37 38 #if defined(ENABLE_EXTENSIONS) 39 const char kKeyAppsProtectingThis[] = "appsProtectingThis"; 40 #endif 41 const char kKeyName[] = "name"; 42 const char kKeyContent[] = "content"; 43 const char kKeyDomain[] = "domain"; 44 const char kKeyPath[] = "path"; 45 const char kKeySendFor[] = "sendfor"; 46 const char kKeyAccessibleToScript[] = "accessibleToScript"; 47 const char kKeyDesc[] = "desc"; 48 const char kKeySize[] = "size"; 49 const char kKeyOrigin[] = "origin"; 50 const char kKeyManifest[] = "manifest"; 51 const char kKeyServerId[] = "serverId"; 52 53 const char kKeyAccessed[] = "accessed"; 54 const char kKeyCreated[] = "created"; 55 const char kKeyExpires[] = "expires"; 56 const char kKeyModified[] = "modified"; 57 58 const char kKeyPersistent[] = "persistent"; 59 const char kKeyTemporary[] = "temporary"; 60 61 const char kKeyTotalUsage[] = "totalUsage"; 62 const char kKeyTemporaryUsage[] = "temporaryUsage"; 63 const char kKeyPersistentUsage[] = "persistentUsage"; 64 65 const char kKeyCertType[] = "certType"; 66 67 const char kKeyScopes[] = "scopes"; 68 69 const int64 kNegligibleUsage = 1024; // 1KiB 70 71 std::string ClientCertTypeToString(net::SSLClientCertType type) { 72 switch (type) { 73 case net::CLIENT_CERT_RSA_SIGN: 74 return l10n_util::GetStringUTF8(IDS_CLIENT_CERT_RSA_SIGN); 75 case net::CLIENT_CERT_DSS_SIGN: 76 return l10n_util::GetStringUTF8(IDS_CLIENT_CERT_DSS_SIGN); 77 case net::CLIENT_CERT_ECDSA_SIGN: 78 return l10n_util::GetStringUTF8(IDS_CLIENT_CERT_ECDSA_SIGN); 79 default: 80 return base::IntToString(type); 81 } 82 } 83 84 } // namespace 85 86 CookiesTreeModelUtil::CookiesTreeModelUtil() { 87 } 88 89 CookiesTreeModelUtil::~CookiesTreeModelUtil() { 90 } 91 92 std::string CookiesTreeModelUtil::GetTreeNodeId(const CookieTreeNode* node) { 93 CookieTreeNodeMap::const_iterator iter = node_map_.find(node); 94 if (iter != node_map_.end()) 95 return base::IntToString(iter->second); 96 97 int32 new_id = id_map_.Add(node); 98 node_map_[node] = new_id; 99 return base::IntToString(new_id); 100 } 101 102 bool CookiesTreeModelUtil::GetCookieTreeNodeDictionary( 103 const CookieTreeNode& node, 104 base::DictionaryValue* dict) { 105 // Use node's address as an id for WebUI to look it up. 106 dict->SetString(kKeyId, GetTreeNodeId(&node)); 107 dict->SetString(kKeyTitle, node.GetTitle()); 108 dict->SetBoolean(kKeyHasChildren, !node.empty()); 109 110 switch (node.GetDetailedInfo().node_type) { 111 case CookieTreeNode::DetailedInfo::TYPE_HOST: { 112 dict->SetString(kKeyType, "origin"); 113 #if defined(OS_MACOSX) 114 dict->SetString(kKeyIcon, "chrome://theme/IDR_BOOKMARK_BAR_FOLDER"); 115 #endif 116 break; 117 } 118 case CookieTreeNode::DetailedInfo::TYPE_COOKIE: { 119 dict->SetString(kKeyType, "cookie"); 120 dict->SetString(kKeyIcon, "chrome://theme/IDR_COOKIE_ICON"); 121 122 const net::CanonicalCookie& cookie = *node.GetDetailedInfo().cookie; 123 124 dict->SetString(kKeyName, cookie.Name()); 125 dict->SetString(kKeyContent, cookie.Value()); 126 dict->SetString(kKeyDomain, cookie.Domain()); 127 dict->SetString(kKeyPath, cookie.Path()); 128 dict->SetString(kKeySendFor, cookie.IsSecure() ? 129 l10n_util::GetStringUTF8(IDS_COOKIES_COOKIE_SENDFOR_SECURE) : 130 l10n_util::GetStringUTF8(IDS_COOKIES_COOKIE_SENDFOR_ANY)); 131 std::string accessible = cookie.IsHttpOnly() ? 132 l10n_util::GetStringUTF8(IDS_COOKIES_COOKIE_ACCESSIBLE_TO_SCRIPT_NO) : 133 l10n_util::GetStringUTF8(IDS_COOKIES_COOKIE_ACCESSIBLE_TO_SCRIPT_YES); 134 dict->SetString(kKeyAccessibleToScript, accessible); 135 dict->SetString(kKeyCreated, base::UTF16ToUTF8( 136 base::TimeFormatFriendlyDateAndTime(cookie.CreationDate()))); 137 dict->SetString(kKeyExpires, cookie.IsPersistent() ? base::UTF16ToUTF8( 138 base::TimeFormatFriendlyDateAndTime(cookie.ExpiryDate())) : 139 l10n_util::GetStringUTF8(IDS_COOKIES_COOKIE_EXPIRES_SESSION)); 140 141 break; 142 } 143 case CookieTreeNode::DetailedInfo::TYPE_DATABASE: { 144 dict->SetString(kKeyType, "database"); 145 dict->SetString(kKeyIcon, "chrome://theme/IDR_COOKIE_STORAGE_ICON"); 146 147 const BrowsingDataDatabaseHelper::DatabaseInfo& database_info = 148 *node.GetDetailedInfo().database_info; 149 150 dict->SetString(kKeyName, database_info.database_name.empty() ? 151 l10n_util::GetStringUTF8(IDS_COOKIES_WEB_DATABASE_UNNAMED_NAME) : 152 database_info.database_name); 153 dict->SetString(kKeyDesc, database_info.description); 154 dict->SetString(kKeySize, ui::FormatBytes(database_info.size)); 155 dict->SetString(kKeyModified, base::UTF16ToUTF8( 156 base::TimeFormatFriendlyDateAndTime(database_info.last_modified))); 157 158 break; 159 } 160 case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE: { 161 dict->SetString(kKeyType, "local_storage"); 162 dict->SetString(kKeyIcon, "chrome://theme/IDR_COOKIE_STORAGE_ICON"); 163 164 const BrowsingDataLocalStorageHelper::LocalStorageInfo& 165 local_storage_info = *node.GetDetailedInfo().local_storage_info; 166 167 dict->SetString(kKeyOrigin, local_storage_info.origin_url.spec()); 168 dict->SetString(kKeySize, ui::FormatBytes(local_storage_info.size)); 169 dict->SetString(kKeyModified, base::UTF16ToUTF8( 170 base::TimeFormatFriendlyDateAndTime( 171 local_storage_info.last_modified))); 172 173 break; 174 } 175 case CookieTreeNode::DetailedInfo::TYPE_APPCACHE: { 176 dict->SetString(kKeyType, "app_cache"); 177 dict->SetString(kKeyIcon, "chrome://theme/IDR_COOKIE_STORAGE_ICON"); 178 179 const content::AppCacheInfo& appcache_info = 180 *node.GetDetailedInfo().appcache_info; 181 182 dict->SetString(kKeyManifest, appcache_info.manifest_url.spec()); 183 dict->SetString(kKeySize, ui::FormatBytes(appcache_info.size)); 184 dict->SetString(kKeyCreated, base::UTF16ToUTF8( 185 base::TimeFormatFriendlyDateAndTime(appcache_info.creation_time))); 186 dict->SetString(kKeyAccessed, base::UTF16ToUTF8( 187 base::TimeFormatFriendlyDateAndTime(appcache_info.last_access_time))); 188 189 break; 190 } 191 case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB: { 192 dict->SetString(kKeyType, "indexed_db"); 193 dict->SetString(kKeyIcon, "chrome://theme/IDR_COOKIE_STORAGE_ICON"); 194 195 const content::IndexedDBInfo& indexed_db_info = 196 *node.GetDetailedInfo().indexed_db_info; 197 198 dict->SetString(kKeyOrigin, indexed_db_info.origin_.spec()); 199 dict->SetString(kKeySize, ui::FormatBytes(indexed_db_info.size_)); 200 dict->SetString(kKeyModified, base::UTF16ToUTF8( 201 base::TimeFormatFriendlyDateAndTime(indexed_db_info.last_modified_))); 202 203 break; 204 } 205 case CookieTreeNode::DetailedInfo::TYPE_FILE_SYSTEM: { 206 dict->SetString(kKeyType, "file_system"); 207 dict->SetString(kKeyIcon, "chrome://theme/IDR_COOKIE_STORAGE_ICON"); 208 209 const BrowsingDataFileSystemHelper::FileSystemInfo& file_system_info = 210 *node.GetDetailedInfo().file_system_info; 211 const storage::FileSystemType kPerm = storage::kFileSystemTypePersistent; 212 const storage::FileSystemType kTemp = storage::kFileSystemTypeTemporary; 213 214 dict->SetString(kKeyOrigin, file_system_info.origin.spec()); 215 dict->SetString(kKeyPersistent, 216 ContainsKey(file_system_info.usage_map, kPerm) ? 217 base::UTF16ToUTF8(ui::FormatBytes( 218 file_system_info.usage_map.find(kPerm)->second)) : 219 l10n_util::GetStringUTF8( 220 IDS_COOKIES_FILE_SYSTEM_USAGE_NONE)); 221 dict->SetString(kKeyTemporary, 222 ContainsKey(file_system_info.usage_map, kTemp) ? 223 base::UTF16ToUTF8(ui::FormatBytes( 224 file_system_info.usage_map.find(kTemp)->second)) : 225 l10n_util::GetStringUTF8( 226 IDS_COOKIES_FILE_SYSTEM_USAGE_NONE)); 227 break; 228 } 229 case CookieTreeNode::DetailedInfo::TYPE_QUOTA: { 230 dict->SetString(kKeyType, "quota"); 231 dict->SetString(kKeyIcon, "chrome://theme/IDR_COOKIE_STORAGE_ICON"); 232 233 const BrowsingDataQuotaHelper::QuotaInfo& quota_info = 234 *node.GetDetailedInfo().quota_info; 235 if (quota_info.temporary_usage + quota_info.persistent_usage <= 236 kNegligibleUsage) 237 return false; 238 239 dict->SetString(kKeyOrigin, quota_info.host); 240 dict->SetString(kKeyTotalUsage, 241 base::UTF16ToUTF8(ui::FormatBytes( 242 quota_info.temporary_usage + 243 quota_info.persistent_usage))); 244 dict->SetString(kKeyTemporaryUsage, 245 base::UTF16ToUTF8(ui::FormatBytes( 246 quota_info.temporary_usage))); 247 dict->SetString(kKeyPersistentUsage, 248 base::UTF16ToUTF8(ui::FormatBytes( 249 quota_info.persistent_usage))); 250 break; 251 } 252 case CookieTreeNode::DetailedInfo::TYPE_CHANNEL_ID: { 253 dict->SetString(kKeyType, "channel_id"); 254 dict->SetString(kKeyIcon, "chrome://theme/IDR_COOKIE_ICON"); 255 256 const net::ChannelIDStore::ChannelID& channel_id = 257 *node.GetDetailedInfo().channel_id; 258 259 dict->SetString(kKeyServerId, channel_id.server_identifier()); 260 dict->SetString(kKeyCertType, 261 ClientCertTypeToString(net::CLIENT_CERT_ECDSA_SIGN)); 262 dict->SetString(kKeyCreated, base::UTF16ToUTF8( 263 base::TimeFormatFriendlyDateAndTime( 264 channel_id.creation_time()))); 265 break; 266 } 267 case CookieTreeNode::DetailedInfo::TYPE_SERVICE_WORKER: { 268 dict->SetString(kKeyType, "service_worker"); 269 dict->SetString(kKeyIcon, "chrome://theme/IDR_COOKIE_STORAGE_ICON"); 270 271 const content::ServiceWorkerUsageInfo& service_worker_info = 272 *node.GetDetailedInfo().service_worker_info; 273 274 dict->SetString(kKeyOrigin, service_worker_info.origin.spec()); 275 base::ListValue* scopes = new base::ListValue; 276 for (std::vector<GURL>::const_iterator it = 277 service_worker_info.scopes.begin(); 278 it != service_worker_info.scopes.end(); 279 ++it) { 280 scopes->AppendString(it->spec()); 281 } 282 dict->Set(kKeyScopes, scopes); 283 break; 284 } 285 case CookieTreeNode::DetailedInfo::TYPE_FLASH_LSO: { 286 dict->SetString(kKeyType, "flash_lso"); 287 dict->SetString(kKeyIcon, "chrome://theme/IDR_COOKIE_ICON"); 288 289 dict->SetString(kKeyDomain, node.GetDetailedInfo().flash_lso_domain); 290 } 291 default: 292 #if defined(OS_MACOSX) 293 dict->SetString(kKeyIcon, "chrome://theme/IDR_BOOKMARK_BAR_FOLDER"); 294 #endif 295 break; 296 } 297 298 #if defined(ENABLE_EXTENSIONS) 299 const extensions::ExtensionSet* protecting_apps = 300 node.GetModel()->ExtensionsProtectingNode(node); 301 if (protecting_apps && !protecting_apps->is_empty()) { 302 base::ListValue* app_infos = new base::ListValue; 303 for (extensions::ExtensionSet::const_iterator it = protecting_apps->begin(); 304 it != protecting_apps->end(); ++it) { 305 base::DictionaryValue* app_info = new base::DictionaryValue(); 306 app_info->SetString(kKeyId, (*it)->id()); 307 app_info->SetString(kKeyName, (*it)->name()); 308 app_infos->Append(app_info); 309 } 310 dict->Set(kKeyAppsProtectingThis, app_infos); 311 } 312 #endif 313 314 return true; 315 } 316 317 void CookiesTreeModelUtil::GetChildNodeList(const CookieTreeNode* parent, 318 int start, 319 int count, 320 base::ListValue* nodes) { 321 for (int i = 0; i < count; ++i) { 322 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue); 323 const CookieTreeNode* child = parent->GetChild(start + i); 324 if (GetCookieTreeNodeDictionary(*child, dict.get())) 325 nodes->Append(dict.release()); 326 } 327 } 328 329 const CookieTreeNode* CookiesTreeModelUtil::GetTreeNodeFromPath( 330 const CookieTreeNode* root, 331 const std::string& path) { 332 std::vector<std::string> node_ids; 333 base::SplitString(path, ',', &node_ids); 334 335 const CookieTreeNode* child = NULL; 336 const CookieTreeNode* parent = root; 337 int child_index = -1; 338 339 // Validate the tree path and get the node pointer. 340 for (size_t i = 0; i < node_ids.size(); ++i) { 341 int32 node_id = 0; 342 if (!base::StringToInt(node_ids[i], &node_id)) 343 break; 344 345 child = id_map_.Lookup(node_id); 346 child_index = parent->GetIndexOf(child); 347 if (child_index == -1) 348 break; 349 350 parent = child; 351 } 352 353 return child_index >= 0 ? child : NULL; 354 } 355