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.
5 #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
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 "chrome/common/extensions/permissions/settings_override_permission.h"
13 #include "extensions/common/error_utils.h"
14 #include "extensions/common/extension_messages.h"
15 #include "extensions/common/feature_switch.h"
16 #include "extensions/common/manifest_constants.h"
17 #include "extensions/common/permissions/api_permission_set.h"
18 #include "extensions/common/permissions/manifest_permission.h"
19 #include "extensions/common/permissions/permissions_data.h"
20 #include "extensions/common/permissions/permissions_info.h"
21 #include "grit/generated_resources.h"
22 #include "ipc/ipc_message.h"
23 #include "ui/base/l10n/l10n_util.h"
26 using extensions::api::manifest_types::ChromeSettingsOverrides
;
28 namespace extensions
{
31 const char* kWwwPrefix
= "www.";
33 scoped_ptr
<GURL
> CreateManifestURL(const std::string
& url
) {
34 scoped_ptr
<GURL
> manifest_url(new GURL(url
));
35 if (!manifest_url
->is_valid() ||
36 !manifest_url
->SchemeIsHTTPOrHTTPS())
37 return scoped_ptr
<GURL
>();
38 return manifest_url
.Pass();
41 scoped_ptr
<GURL
> ParseHomepage(const ChromeSettingsOverrides
& overrides
,
42 base::string16
* error
) {
43 if (!overrides
.homepage
)
44 return scoped_ptr
<GURL
>();
45 scoped_ptr
<GURL
> manifest_url
= CreateManifestURL(*overrides
.homepage
);
47 *error
= extensions::ErrorUtils::FormatErrorMessageUTF16(
48 manifest_errors::kInvalidHomepageOverrideURL
, *overrides
.homepage
);
50 return manifest_url
.Pass();
53 std::vector
<GURL
> ParseStartupPage(const ChromeSettingsOverrides
& overrides
,
54 base::string16
* error
) {
55 std::vector
<GURL
> urls
;
56 if (!overrides
.startup_pages
)
59 for (std::vector
<std::string
>::const_iterator i
=
60 overrides
.startup_pages
->begin(); i
!= overrides
.startup_pages
->end();
62 scoped_ptr
<GURL
> manifest_url
= CreateManifestURL(*i
);
64 *error
= extensions::ErrorUtils::FormatErrorMessageUTF16(
65 manifest_errors::kInvalidStartupOverrideURL
, *i
);
67 urls
.push_back(GURL());
68 urls
.back().Swap(manifest_url
.get());
74 scoped_ptr
<ChromeSettingsOverrides::Search_provider
> ParseSearchEngine(
75 ChromeSettingsOverrides
* overrides
,
76 base::string16
* error
) {
77 if (!overrides
->search_provider
)
78 return scoped_ptr
<ChromeSettingsOverrides::Search_provider
>();
79 if (!CreateManifestURL(overrides
->search_provider
->favicon_url
)) {
80 *error
= extensions::ErrorUtils::FormatErrorMessageUTF16(
81 manifest_errors::kInvalidSearchEngineURL
,
82 overrides
->search_provider
->favicon_url
);
83 return scoped_ptr
<ChromeSettingsOverrides::Search_provider
>();
85 if (!CreateManifestURL(overrides
->search_provider
->search_url
)) {
86 *error
= extensions::ErrorUtils::FormatErrorMessageUTF16(
87 manifest_errors::kInvalidSearchEngineURL
,
88 overrides
->search_provider
->search_url
);
89 return scoped_ptr
<ChromeSettingsOverrides::Search_provider
>();
91 return overrides
->search_provider
.Pass();
94 // A www. prefix is not informative and thus not worth the limited real estate
95 // in the permissions UI.
96 std::string
RemoveWwwPrefix(const std::string
& url
) {
97 if (StartsWithASCII(url
, kWwwPrefix
, false))
98 return url
.substr(strlen(kWwwPrefix
));
104 // The manifest permission implementation supports a permission for overriding
106 class SettingsOverridesHandler::ManifestPermissionImpl
107 : public ManifestPermission
{
109 explicit ManifestPermissionImpl(bool override_bookmarks_ui_permission
)
110 : override_bookmarks_ui_permission_(override_bookmarks_ui_permission
) {}
112 // extensions::ManifestPermission overrides.
113 virtual std::string
name() const OVERRIDE
{
114 return manifest_keys::kSettingsOverride
;
117 virtual std::string
id() const OVERRIDE
{
121 virtual bool HasMessages() const OVERRIDE
{
122 return override_bookmarks_ui_permission_
;
125 virtual PermissionMessages
GetMessages() const OVERRIDE
{
126 PermissionMessages result
;
127 if (override_bookmarks_ui_permission_
) {
128 result
.push_back(PermissionMessage(
129 PermissionMessage::kOverrideBookmarksUI
,
130 l10n_util::GetStringUTF16(
131 IDS_EXTENSION_PROMPT_WARNING_OVERRIDE_BOOKMARKS_UI
)));
136 virtual bool FromValue(const base::Value
* value
) OVERRIDE
{
137 return value
&& value
->GetAsBoolean(&override_bookmarks_ui_permission_
);
140 virtual scoped_ptr
<base::Value
> ToValue() const OVERRIDE
{
141 return scoped_ptr
<base::Value
>(
142 new base::FundamentalValue(override_bookmarks_ui_permission_
)).Pass();
145 virtual ManifestPermission
* Clone() const OVERRIDE
{
146 return scoped_ptr
<ManifestPermissionImpl
>(
147 new ManifestPermissionImpl(
148 override_bookmarks_ui_permission_
)).release();
151 virtual ManifestPermission
* Diff(const ManifestPermission
* rhs
) const
153 const ManifestPermissionImpl
* other
=
154 static_cast<const ManifestPermissionImpl
*>(rhs
);
156 return scoped_ptr
<ManifestPermissionImpl
>(new ManifestPermissionImpl(
157 override_bookmarks_ui_permission_
&&
158 !other
->override_bookmarks_ui_permission_
)).release();
161 virtual ManifestPermission
* Union(const ManifestPermission
* rhs
) const
163 const ManifestPermissionImpl
* other
=
164 static_cast<const ManifestPermissionImpl
*>(rhs
);
166 return scoped_ptr
<ManifestPermissionImpl
>(new ManifestPermissionImpl(
167 override_bookmarks_ui_permission_
||
168 other
->override_bookmarks_ui_permission_
)).release();
171 virtual ManifestPermission
* Intersect(const ManifestPermission
* rhs
) const
173 const ManifestPermissionImpl
* other
=
174 static_cast<const ManifestPermissionImpl
*>(rhs
);
176 return scoped_ptr
<ManifestPermissionImpl
>(new ManifestPermissionImpl(
177 override_bookmarks_ui_permission_
&&
178 other
->override_bookmarks_ui_permission_
)).release();
181 virtual bool Contains(const ManifestPermission
* rhs
) const OVERRIDE
{
182 const ManifestPermissionImpl
* other
=
183 static_cast<const ManifestPermissionImpl
*>(rhs
);
185 return !other
->override_bookmarks_ui_permission_
||
186 override_bookmarks_ui_permission_
;
189 virtual bool Equal(const ManifestPermission
* rhs
) const OVERRIDE
{
190 const ManifestPermissionImpl
* other
=
191 static_cast<const ManifestPermissionImpl
*>(rhs
);
193 return override_bookmarks_ui_permission_
==
194 other
->override_bookmarks_ui_permission_
;
197 virtual void Write(IPC::Message
* m
) const OVERRIDE
{
198 IPC::WriteParam(m
, override_bookmarks_ui_permission_
);
201 virtual bool Read(const IPC::Message
* m
, PickleIterator
* iter
) OVERRIDE
{
202 return IPC::ReadParam(m
, iter
, &override_bookmarks_ui_permission_
);
205 virtual void Log(std::string
* log
) const OVERRIDE
{
206 IPC::LogParam(override_bookmarks_ui_permission_
, log
);
210 bool override_bookmarks_ui_permission_
;
213 SettingsOverrides::SettingsOverrides() {}
215 SettingsOverrides::~SettingsOverrides() {}
217 const SettingsOverrides
* SettingsOverrides::Get(
218 const Extension
* extension
) {
219 return static_cast<SettingsOverrides
*>(
220 extension
->GetManifestData(manifest_keys::kSettingsOverride
));
223 bool SettingsOverrides::RemovesBookmarkButton(
224 const SettingsOverrides
& settings_overrides
) {
225 return settings_overrides
.bookmarks_ui
&&
226 settings_overrides
.bookmarks_ui
->remove_button
&&
227 *settings_overrides
.bookmarks_ui
->remove_button
;
230 bool SettingsOverrides::RemovesBookmarkShortcut(
231 const SettingsOverrides
& settings_overrides
) {
232 return settings_overrides
.bookmarks_ui
&&
233 settings_overrides
.bookmarks_ui
->remove_bookmark_shortcut
&&
234 *settings_overrides
.bookmarks_ui
->remove_bookmark_shortcut
;
237 SettingsOverridesHandler::SettingsOverridesHandler() {}
239 SettingsOverridesHandler::~SettingsOverridesHandler() {}
241 bool SettingsOverridesHandler::Parse(Extension
* extension
,
242 base::string16
* error
) {
243 const base::Value
* dict
= NULL
;
244 CHECK(extension
->manifest()->Get(manifest_keys::kSettingsOverride
, &dict
));
245 scoped_ptr
<ChromeSettingsOverrides
> settings(
246 ChromeSettingsOverrides::FromValue(*dict
, error
));
250 scoped_ptr
<SettingsOverrides
> info(new SettingsOverrides
);
251 info
->bookmarks_ui
.swap(settings
->bookmarks_ui
);
252 // Support backward compatibility for deprecated key
253 // chrome_settings_overrides.bookmarks_ui.hide_bookmark_button.
254 if (info
->bookmarks_ui
&& !info
->bookmarks_ui
->remove_button
&&
255 info
->bookmarks_ui
->hide_bookmark_button
) {
256 info
->bookmarks_ui
->remove_button
.reset(
257 new bool(*info
->bookmarks_ui
->hide_bookmark_button
));
259 info
->homepage
= ParseHomepage(*settings
, error
);
260 info
->search_engine
= ParseSearchEngine(settings
.get(), error
);
261 info
->startup_pages
= ParseStartupPage(*settings
, error
);
262 if (!info
->bookmarks_ui
&& !info
->homepage
&&
263 !info
->search_engine
&& info
->startup_pages
.empty()) {
264 *error
= ErrorUtils::FormatErrorMessageUTF16(
265 manifest_errors::kInvalidEmptyDictionary
,
266 manifest_keys::kSettingsOverride
);
269 info
->manifest_permission
.reset(new ManifestPermissionImpl(
270 SettingsOverrides::RemovesBookmarkButton(*info
)));
272 APIPermissionSet
* permission_set
=
273 PermissionsData::GetInitialAPIPermissions(extension
);
274 DCHECK(permission_set
);
275 if (info
->search_engine
) {
276 permission_set
->insert(new SettingsOverrideAPIPermission(
277 PermissionsInfo::GetInstance()->GetByID(APIPermission::kSearchProvider
),
278 RemoveWwwPrefix(CreateManifestURL(info
->search_engine
->search_url
)->
279 GetOrigin().host())));
281 if (!info
->startup_pages
.empty()) {
282 permission_set
->insert(new SettingsOverrideAPIPermission(
283 PermissionsInfo::GetInstance()->GetByID(APIPermission::kStartupPages
),
284 // We only support one startup page even though the type of the manifest
285 // property is a list, only the first one is used.
286 RemoveWwwPrefix(info
->startup_pages
[0].GetContent())));
288 if (info
->homepage
) {
289 permission_set
->insert(new SettingsOverrideAPIPermission(
290 PermissionsInfo::GetInstance()->GetByID(APIPermission::kHomepage
),
291 RemoveWwwPrefix(info
->homepage
.get()->GetContent())));
293 extension
->SetManifestData(manifest_keys::kSettingsOverride
,
298 bool SettingsOverridesHandler::Validate(
299 const Extension
* extension
,
301 std::vector
<InstallWarning
>* warnings
) const {
302 const SettingsOverrides
* settings_overrides
=
303 SettingsOverrides::Get(extension
);
305 if (settings_overrides
&& settings_overrides
->bookmarks_ui
) {
306 if (!FeatureSwitch::enable_override_bookmarks_ui()->IsEnabled()) {
307 warnings
->push_back(InstallWarning(
308 ErrorUtils::FormatErrorMessage(
309 manifest_errors::kUnrecognizedManifestKey
,
310 manifest_keys::kBookmarkUI
)));
311 } else if (settings_overrides
->bookmarks_ui
->hide_bookmark_button
) {
312 warnings
->push_back(InstallWarning(
313 ErrorUtils::FormatErrorMessage(
314 manifest_errors::kKeyIsDeprecatedWithReplacement
,
315 manifest_keys::kHideBookmarkButton
,
316 manifest_keys::kRemoveButton
)));
323 ManifestPermission
* SettingsOverridesHandler::CreatePermission() {
324 return new ManifestPermissionImpl(false);
327 ManifestPermission
* SettingsOverridesHandler::CreateInitialRequiredPermission(
328 const Extension
* extension
) {
329 const SettingsOverrides
* data
= SettingsOverrides::Get(extension
);
331 return data
->manifest_permission
->Clone();
334 const std::vector
<std::string
> SettingsOverridesHandler::Keys() const {
335 return SingleKey(manifest_keys::kSettingsOverride
);
338 } // namespace extensions