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