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.
5 #include "chrome/browser/managed_mode/managed_mode_site_list.h"
7 #include "base/json/json_file_value_serializer.h"
8 #include "base/logging.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "extensions/common/extension.h"
13 using base::DictionaryValue
;
14 using base::ListValue
;
17 const int kSitelistFormatVersion
= 1;
19 const char kCategoriesKey
[] = "categories";
20 const char kHostnameHashesKey
[] = "hostname_hashes";
21 const char kNameKey
[] = "name";
22 const char kSitesKey
[] = "sites";
23 const char kSitelistFormatVersionKey
[] = "version";
24 const char kThumbnailKey
[] = "thumbnail";
25 const char kThumbnailUrlKey
[] = "thumbnail_url";
26 const char kUrlKey
[] = "url";
27 const char kWhitelistKey
[] = "whitelist";
32 const char* identifier
;
36 // These are placeholders for now.
37 CategoryInfo g_categories
[] = {
38 {"com.google.chrome.animals", "Animals and Plants"},
39 {"com.google.chrome.arts", "Arts"},
40 {"com.google.chrome.business", "Business"},
41 {"com.google.chrome.computers", "Computers"},
42 {"com.google.chrome.education", "Education"},
43 {"com.google.chrome.entertainment", "Entertainment"},
44 {"com.google.chrome.games", "Games"},
45 {"com.google.chrome.health", "Health"},
46 {"com.google.chrome.home", "Home"},
47 {"com.google.chrome.international", "International"},
48 {"com.google.chrome.news", "News"},
49 {"com.google.chrome.people", "People and Society"},
50 {"com.google.chrome.places", "Places"},
51 {"com.google.chrome.pre-school", "Pre-School"},
52 {"com.google.chrome.reference", "Reference"},
53 {"com.google.chrome.science", "Science"},
54 {"com.google.chrome.shopping", "Shopping"},
55 {"com.google.chrome.sports", "Sports and Hobbies"},
56 {"com.google.chrome.teens", "Teens"}
59 // Category 0 is "not listed"; actual category IDs start at 1.
60 int GetCategoryId(const std::string
& category
) {
61 for (size_t i
= 0; i
< arraysize(g_categories
); ++i
) {
62 if (g_categories
[i
].identifier
== category
)
68 // Takes a DictionaryValue entry from the JSON file and fills the whitelist
69 // (via URL patterns or hostname hashes) and the URL in the corresponding Site
71 void AddWhitelistEntries(const base::DictionaryValue
* site_dict
,
72 ManagedModeSiteList::Site
* site
) {
73 std::vector
<std::string
>* patterns
= &site
->patterns
;
76 const base::ListValue
* whitelist
= NULL
;
77 if (site_dict
->GetList(kWhitelistKey
, &whitelist
)) {
79 for (base::ListValue::const_iterator whitelist_it
= whitelist
->begin();
80 whitelist_it
!= whitelist
->end(); ++whitelist_it
) {
82 if (!(*whitelist_it
)->GetAsString(&pattern
)) {
83 LOG(ERROR
) << "Invalid whitelist entry";
87 patterns
->push_back(pattern
);
91 std::vector
<std::string
>* hashes
= &site
->hostname_hashes
;
92 const base::ListValue
* hash_list
= NULL
;
93 if (site_dict
->GetList(kHostnameHashesKey
, &hash_list
)) {
95 for (base::ListValue::const_iterator hash_list_it
= hash_list
->begin();
96 hash_list_it
!= hash_list
->end(); ++hash_list_it
) {
98 if (!(*hash_list_it
)->GetAsString(&hash
)) {
99 LOG(ERROR
) << "Invalid whitelist entry";
103 hashes
->push_back(hash
);
110 // Fall back to using a whitelist based on the URL.
112 if (!site_dict
->GetString(kUrlKey
, &url_str
)) {
113 LOG(ERROR
) << "Whitelist is invalid";
118 if (!url
.is_valid()) {
119 LOG(ERROR
) << "URL " << url_str
<< " is invalid";
123 patterns
->push_back(url
.host());
128 ManagedModeSiteList::Site::Site(const base::string16
& name
,
131 category_id(category_id
) {}
133 ManagedModeSiteList::Site::~Site() {}
135 ManagedModeSiteList::ManagedModeSiteList(
136 const std::string
& extension_id
,
137 const base::FilePath
& path
)
138 : extension_id_(extension_id
),
142 ManagedModeSiteList::~ManagedModeSiteList() {
145 ManagedModeSiteList
* ManagedModeSiteList::Clone() {
146 return new ManagedModeSiteList(extension_id_
, path_
);
150 void ManagedModeSiteList::GetCategoryNames(
151 std::vector
<base::string16
>* categories
) {
152 // TODO(bauerb): Collect custom categories from extensions.
153 for (size_t i
= 0; i
< arraysize(g_categories
); ++i
) {
154 categories
->push_back(base::ASCIIToUTF16(g_categories
[i
].name
));
158 void ManagedModeSiteList::GetSites(std::vector
<Site
>* sites
) {
162 for (base::ListValue::iterator entry_it
= sites_
->begin();
163 entry_it
!= sites_
->end(); ++entry_it
) {
164 base::DictionaryValue
* entry
= NULL
;
165 if (!(*entry_it
)->GetAsDictionary(&entry
)) {
166 LOG(ERROR
) << "Entry is invalid";
171 entry
->GetString(kNameKey
, &name
);
173 // TODO(bauerb): We need to distinguish between "no category assigned" and
174 // "not on any site list".
176 const base::ListValue
* categories
= NULL
;
177 if (entry
->GetList(kCategoriesKey
, &categories
)) {
178 for (base::ListValue::const_iterator it
= categories
->begin();
179 it
!= categories
->end(); ++it
) {
180 std::string category
;
181 if (!(*it
)->GetAsString(&category
)) {
182 LOG(ERROR
) << "Invalid category";
185 category_id
= GetCategoryId(category
);
189 sites
->push_back(Site(name
, category_id
));
190 AddWhitelistEntries(entry
, &sites
->back());
194 bool ManagedModeSiteList::LazyLoad() {
198 JSONFileValueSerializer
serializer(path_
);
200 scoped_ptr
<base::Value
> value(serializer
.Deserialize(NULL
, &error
));
202 LOG(ERROR
) << "Couldn't load site list " << path_
.value() << ": "
207 base::DictionaryValue
* dict
= NULL
;
208 if (!value
->GetAsDictionary(&dict
)) {
209 LOG(ERROR
) << "Site list " << path_
.value() << " is invalid";
214 if (!dict
->GetInteger(kSitelistFormatVersionKey
, &version
)) {
215 LOG(ERROR
) << "Site list " << path_
.value() << " has invalid version";
219 if (version
> kSitelistFormatVersion
) {
220 LOG(ERROR
) << "Site list " << path_
.value() << " has a too new format";
224 base::ListValue
* sites
= NULL
;
225 if (dict
->GetList(kSitesKey
, &sites
))
226 sites_
.reset(sites
->DeepCopy());
228 base::DictionaryValue
* categories
= NULL
;
229 if (dict
->GetDictionary(kCategoriesKey
, &categories
))
230 categories_
.reset(categories
->DeepCopy());
235 void ManagedModeSiteList::CopyThumbnailUrl(const base::DictionaryValue
* source
,
236 base::DictionaryValue
* dest
) {
237 if (!source
->HasKey(kThumbnailKey
))
240 std::string thumbnail
;
241 if (!source
->GetString(kThumbnailKey
, &thumbnail
)) {
242 LOG(ERROR
) << "Invalid thumbnail";
247 extensions::Extension::GetBaseURLFromExtensionId(extension_id_
);
248 GURL thumbnail_url
= base_url
.Resolve(thumbnail
);
249 if (!thumbnail_url
.is_valid()) {
250 LOG(ERROR
) << "Invalid thumbnail";
254 dest
->SetString(kThumbnailUrlKey
, thumbnail_url
.spec());