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 30namespace { 31 32const char kKeyId[] = "id"; 33const char kKeyTitle[] = "title"; 34const char kKeyIcon[] = "icon"; 35const char kKeyType[] = "type"; 36const char kKeyHasChildren[] = "hasChildren"; 37 38#if defined(ENABLE_EXTENSIONS) 39const char kKeyAppsProtectingThis[] = "appsProtectingThis"; 40#endif 41const char kKeyName[] = "name"; 42const char kKeyContent[] = "content"; 43const char kKeyDomain[] = "domain"; 44const char kKeyPath[] = "path"; 45const char kKeySendFor[] = "sendfor"; 46const char kKeyAccessibleToScript[] = "accessibleToScript"; 47const char kKeyDesc[] = "desc"; 48const char kKeySize[] = "size"; 49const char kKeyOrigin[] = "origin"; 50const char kKeyManifest[] = "manifest"; 51const char kKeyServerId[] = "serverId"; 52 53const char kKeyAccessed[] = "accessed"; 54const char kKeyCreated[] = "created"; 55const char kKeyExpires[] = "expires"; 56const char kKeyModified[] = "modified"; 57 58const char kKeyPersistent[] = "persistent"; 59const char kKeyTemporary[] = "temporary"; 60 61const char kKeyTotalUsage[] = "totalUsage"; 62const char kKeyTemporaryUsage[] = "temporaryUsage"; 63const char kKeyPersistentUsage[] = "persistentUsage"; 64 65const char kKeyCertType[] = "certType"; 66 67const char kKeyScopes[] = "scopes"; 68 69const int64 kNegligibleUsage = 1024; // 1KiB 70 71std::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 86CookiesTreeModelUtil::CookiesTreeModelUtil() { 87} 88 89CookiesTreeModelUtil::~CookiesTreeModelUtil() { 90} 91 92std::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 102bool 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 317void 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 329const 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