1 // Copyright 2013 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/common/extensions/manifest_handlers/settings_overrides_handler.h"
6
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "extensions/common/error_utils.h"
13 #include "extensions/common/extension_set.h"
14 #include "extensions/common/feature_switch.h"
15 #include "extensions/common/manifest_constants.h"
16 #include "extensions/common/manifest_handlers/permissions_parser.h"
17 #include "extensions/common/permissions/api_permission_set.h"
18 #include "extensions/common/permissions/manifest_permission.h"
19 #include "extensions/common/permissions/permissions_info.h"
20 #include "extensions/common/permissions/settings_override_permission.h"
21 #include "grit/generated_resources.h"
22 #include "ipc/ipc_message.h"
23 #include "ipc/ipc_message_utils.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "url/gurl.h"
26
27 using extensions::api::manifest_types::ChromeSettingsOverrides;
28
29 namespace extensions {
30 namespace {
31
32 const char* kWwwPrefix = "www.";
33
CreateManifestURL(const std::string & url)34 scoped_ptr<GURL> CreateManifestURL(const std::string& url) {
35 scoped_ptr<GURL> manifest_url(new GURL(url));
36 if (!manifest_url->is_valid() ||
37 !manifest_url->SchemeIsHTTPOrHTTPS())
38 return scoped_ptr<GURL>();
39 return manifest_url.Pass();
40 }
41
ParseHomepage(const ChromeSettingsOverrides & overrides,base::string16 * error)42 scoped_ptr<GURL> ParseHomepage(const ChromeSettingsOverrides& overrides,
43 base::string16* error) {
44 if (!overrides.homepage)
45 return scoped_ptr<GURL>();
46 scoped_ptr<GURL> manifest_url = CreateManifestURL(*overrides.homepage);
47 if (!manifest_url) {
48 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
49 manifest_errors::kInvalidHomepageOverrideURL, *overrides.homepage);
50 }
51 return manifest_url.Pass();
52 }
53
ParseStartupPage(const ChromeSettingsOverrides & overrides,base::string16 * error)54 std::vector<GURL> ParseStartupPage(const ChromeSettingsOverrides& overrides,
55 base::string16* error) {
56 std::vector<GURL> urls;
57 if (!overrides.startup_pages)
58 return urls;
59
60 for (std::vector<std::string>::const_iterator i =
61 overrides.startup_pages->begin(); i != overrides.startup_pages->end();
62 ++i) {
63 scoped_ptr<GURL> manifest_url = CreateManifestURL(*i);
64 if (!manifest_url) {
65 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
66 manifest_errors::kInvalidStartupOverrideURL, *i);
67 } else {
68 urls.push_back(GURL());
69 urls.back().Swap(manifest_url.get());
70 }
71 }
72 return urls;
73 }
74
ParseSearchEngine(ChromeSettingsOverrides * overrides,base::string16 * error)75 scoped_ptr<ChromeSettingsOverrides::Search_provider> ParseSearchEngine(
76 ChromeSettingsOverrides* overrides,
77 base::string16* error) {
78 if (!overrides->search_provider)
79 return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
80 if (!CreateManifestURL(overrides->search_provider->search_url)) {
81 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
82 manifest_errors::kInvalidSearchEngineURL,
83 overrides->search_provider->search_url);
84 return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
85 }
86 if (overrides->search_provider->prepopulated_id)
87 return overrides->search_provider.Pass();
88 if (!overrides->search_provider->name ||
89 !overrides->search_provider->keyword ||
90 !overrides->search_provider->encoding ||
91 !overrides->search_provider->favicon_url) {
92 *error =
93 base::ASCIIToUTF16(manifest_errors::kInvalidSearchEngineMissingKeys);
94 return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
95 }
96 if (!CreateManifestURL(*overrides->search_provider->favicon_url)) {
97 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
98 manifest_errors::kInvalidSearchEngineURL,
99 *overrides->search_provider->favicon_url);
100 return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
101 }
102 return overrides->search_provider.Pass();
103 }
104
105 // A www. prefix is not informative and thus not worth the limited real estate
106 // in the permissions UI.
RemoveWwwPrefix(const std::string & url)107 std::string RemoveWwwPrefix(const std::string& url) {
108 if (StartsWithASCII(url, kWwwPrefix, false))
109 return url.substr(strlen(kWwwPrefix));
110 return url;
111 }
112
113 } // namespace
114
SettingsOverrides()115 SettingsOverrides::SettingsOverrides() {}
116
~SettingsOverrides()117 SettingsOverrides::~SettingsOverrides() {}
118
119 // static
Get(const Extension * extension)120 const SettingsOverrides* SettingsOverrides::Get(
121 const Extension* extension) {
122 return static_cast<SettingsOverrides*>(
123 extension->GetManifestData(manifest_keys::kSettingsOverride));
124 }
125
SettingsOverridesHandler()126 SettingsOverridesHandler::SettingsOverridesHandler() {}
127
~SettingsOverridesHandler()128 SettingsOverridesHandler::~SettingsOverridesHandler() {}
129
Parse(Extension * extension,base::string16 * error)130 bool SettingsOverridesHandler::Parse(Extension* extension,
131 base::string16* error) {
132 const base::Value* dict = NULL;
133 CHECK(extension->manifest()->Get(manifest_keys::kSettingsOverride, &dict));
134 scoped_ptr<ChromeSettingsOverrides> settings(
135 ChromeSettingsOverrides::FromValue(*dict, error));
136 if (!settings)
137 return false;
138
139 scoped_ptr<SettingsOverrides> info(new SettingsOverrides);
140 info->homepage = ParseHomepage(*settings, error);
141 info->search_engine = ParseSearchEngine(settings.get(), error);
142 info->startup_pages = ParseStartupPage(*settings, error);
143 if (!info->homepage && !info->search_engine && info->startup_pages.empty()) {
144 *error = ErrorUtils::FormatErrorMessageUTF16(
145 manifest_errors::kInvalidEmptyDictionary,
146 manifest_keys::kSettingsOverride);
147 return false;
148 }
149
150 if (info->search_engine) {
151 PermissionsParser::AddAPIPermission(
152 extension,
153 new SettingsOverrideAPIPermission(
154 PermissionsInfo::GetInstance()->GetByID(
155 APIPermission::kSearchProvider),
156 RemoveWwwPrefix(CreateManifestURL(info->search_engine->search_url)
157 ->GetOrigin()
158 .host())));
159 }
160 if (!info->startup_pages.empty()) {
161 PermissionsParser::AddAPIPermission(
162 extension,
163 new SettingsOverrideAPIPermission(
164 PermissionsInfo::GetInstance()->GetByID(
165 APIPermission::kStartupPages),
166 // We only support one startup page even though the type of the
167 // manifest
168 // property is a list, only the first one is used.
169 RemoveWwwPrefix(info->startup_pages[0].GetContent())));
170 }
171 if (info->homepage) {
172 PermissionsParser::AddAPIPermission(
173 extension,
174 new SettingsOverrideAPIPermission(
175 PermissionsInfo::GetInstance()->GetByID(APIPermission::kHomepage),
176 RemoveWwwPrefix(info->homepage.get()->GetContent())));
177 }
178 extension->SetManifestData(manifest_keys::kSettingsOverride,
179 info.release());
180 return true;
181 }
182
Keys() const183 const std::vector<std::string> SettingsOverridesHandler::Keys() const {
184 return SingleKey(manifest_keys::kSettingsOverride);
185 }
186
187 } // namespace extensions
188