settings_overrides_handler.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
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/permissions/api_permission_set.h" 17#include "extensions/common/permissions/manifest_permission.h" 18#include "extensions/common/permissions/permissions_data.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 27using extensions::api::manifest_types::ChromeSettingsOverrides; 28 29namespace extensions { 30namespace { 31 32const char* kWwwPrefix = "www."; 33 34scoped_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 42scoped_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 54std::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 75scoped_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->favicon_url)) { 81 *error = extensions::ErrorUtils::FormatErrorMessageUTF16( 82 manifest_errors::kInvalidSearchEngineURL, 83 overrides->search_provider->favicon_url); 84 return scoped_ptr<ChromeSettingsOverrides::Search_provider>(); 85 } 86 if (!CreateManifestURL(overrides->search_provider->search_url)) { 87 *error = extensions::ErrorUtils::FormatErrorMessageUTF16( 88 manifest_errors::kInvalidSearchEngineURL, 89 overrides->search_provider->search_url); 90 return scoped_ptr<ChromeSettingsOverrides::Search_provider>(); 91 } 92 return overrides->search_provider.Pass(); 93} 94 95// A www. prefix is not informative and thus not worth the limited real estate 96// in the permissions UI. 97std::string RemoveWwwPrefix(const std::string& url) { 98 if (StartsWithASCII(url, kWwwPrefix, false)) 99 return url.substr(strlen(kWwwPrefix)); 100 return url; 101} 102 103} // namespace 104 105// The manifest permission implementation supports a permission for overriding 106// the bookmark UI. 107class SettingsOverridesHandler::ManifestPermissionImpl 108 : public ManifestPermission { 109 public: 110 explicit ManifestPermissionImpl(bool override_bookmarks_ui_permission) 111 : override_bookmarks_ui_permission_(override_bookmarks_ui_permission) {} 112 113 // extensions::ManifestPermission overrides. 114 virtual std::string name() const OVERRIDE { 115 return manifest_keys::kSettingsOverride; 116 } 117 118 virtual std::string id() const OVERRIDE { 119 return name(); 120 } 121 122 virtual bool HasMessages() const OVERRIDE { 123 return override_bookmarks_ui_permission_; 124 } 125 126 virtual PermissionMessages GetMessages() const OVERRIDE { 127 PermissionMessages result; 128 if (override_bookmarks_ui_permission_) { 129 result.push_back(PermissionMessage( 130 PermissionMessage::kOverrideBookmarksUI, 131 l10n_util::GetStringUTF16( 132 IDS_EXTENSION_PROMPT_WARNING_OVERRIDE_BOOKMARKS_UI))); 133 } 134 return result; 135 } 136 137 virtual bool FromValue(const base::Value* value) OVERRIDE { 138 return value && value->GetAsBoolean(&override_bookmarks_ui_permission_); 139 } 140 141 virtual scoped_ptr<base::Value> ToValue() const OVERRIDE { 142 return scoped_ptr<base::Value>( 143 new base::FundamentalValue(override_bookmarks_ui_permission_)).Pass(); 144 } 145 146 virtual ManifestPermission* Clone() const OVERRIDE { 147 return scoped_ptr<ManifestPermissionImpl>( 148 new ManifestPermissionImpl( 149 override_bookmarks_ui_permission_)).release(); 150 } 151 152 virtual ManifestPermission* Diff(const ManifestPermission* rhs) const 153 OVERRIDE { 154 const ManifestPermissionImpl* other = 155 static_cast<const ManifestPermissionImpl*>(rhs); 156 157 return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl( 158 override_bookmarks_ui_permission_ && 159 !other->override_bookmarks_ui_permission_)).release(); 160 } 161 162 virtual ManifestPermission* Union(const ManifestPermission* rhs) const 163 OVERRIDE { 164 const ManifestPermissionImpl* other = 165 static_cast<const ManifestPermissionImpl*>(rhs); 166 167 return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl( 168 override_bookmarks_ui_permission_ || 169 other->override_bookmarks_ui_permission_)).release(); 170 } 171 172 virtual ManifestPermission* Intersect(const ManifestPermission* rhs) const 173 OVERRIDE { 174 const ManifestPermissionImpl* other = 175 static_cast<const ManifestPermissionImpl*>(rhs); 176 177 return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl( 178 override_bookmarks_ui_permission_ && 179 other->override_bookmarks_ui_permission_)).release(); 180 } 181 182 virtual bool Contains(const ManifestPermission* rhs) const OVERRIDE { 183 const ManifestPermissionImpl* other = 184 static_cast<const ManifestPermissionImpl*>(rhs); 185 186 return !other->override_bookmarks_ui_permission_ || 187 override_bookmarks_ui_permission_; 188 } 189 190 virtual bool Equal(const ManifestPermission* rhs) const OVERRIDE { 191 const ManifestPermissionImpl* other = 192 static_cast<const ManifestPermissionImpl*>(rhs); 193 194 return override_bookmarks_ui_permission_ == 195 other->override_bookmarks_ui_permission_; 196 } 197 198 virtual void Write(IPC::Message* m) const OVERRIDE { 199 IPC::WriteParam(m, override_bookmarks_ui_permission_); 200 } 201 202 virtual bool Read(const IPC::Message* m, PickleIterator* iter) OVERRIDE { 203 return IPC::ReadParam(m, iter, &override_bookmarks_ui_permission_); 204 } 205 206 virtual void Log(std::string* log) const OVERRIDE { 207 IPC::LogParam(override_bookmarks_ui_permission_, log); 208 } 209 210 private: 211 bool override_bookmarks_ui_permission_; 212}; 213 214SettingsOverrides::SettingsOverrides() {} 215 216SettingsOverrides::~SettingsOverrides() {} 217 218// static 219const SettingsOverrides* SettingsOverrides::Get( 220 const Extension* extension) { 221 return static_cast<SettingsOverrides*>( 222 extension->GetManifestData(manifest_keys::kSettingsOverride)); 223} 224 225// static 226bool SettingsOverrides::RemovesBookmarkButton( 227 const SettingsOverrides& settings_overrides) { 228 return settings_overrides.bookmarks_ui && 229 settings_overrides.bookmarks_ui->remove_button && 230 *settings_overrides.bookmarks_ui->remove_button; 231} 232 233// static 234bool SettingsOverrides::RemovesBookmarkShortcut( 235 const SettingsOverrides& settings_overrides) { 236 return settings_overrides.bookmarks_ui && 237 settings_overrides.bookmarks_ui->remove_bookmark_shortcut && 238 *settings_overrides.bookmarks_ui->remove_bookmark_shortcut; 239} 240 241bool SettingsOverrides::RemovesBookmarkOpenPagesShortcut( 242 const SettingsOverrides& settings_overrides) { 243 return settings_overrides.bookmarks_ui && 244 settings_overrides.bookmarks_ui->remove_bookmark_open_pages_shortcut && 245 *settings_overrides.bookmarks_ui->remove_bookmark_open_pages_shortcut; 246} 247 248SettingsOverridesHandler::SettingsOverridesHandler() {} 249 250SettingsOverridesHandler::~SettingsOverridesHandler() {} 251 252bool SettingsOverridesHandler::Parse(Extension* extension, 253 base::string16* error) { 254 const base::Value* dict = NULL; 255 CHECK(extension->manifest()->Get(manifest_keys::kSettingsOverride, &dict)); 256 scoped_ptr<ChromeSettingsOverrides> settings( 257 ChromeSettingsOverrides::FromValue(*dict, error)); 258 if (!settings) 259 return false; 260 261 scoped_ptr<SettingsOverrides> info(new SettingsOverrides); 262 info->bookmarks_ui.swap(settings->bookmarks_ui); 263 // Support backward compatibility for deprecated key 264 // chrome_settings_overrides.bookmarks_ui.hide_bookmark_button. 265 if (info->bookmarks_ui && !info->bookmarks_ui->remove_button && 266 info->bookmarks_ui->hide_bookmark_button) { 267 info->bookmarks_ui->remove_button.reset( 268 new bool(*info->bookmarks_ui->hide_bookmark_button)); 269 } 270 info->homepage = ParseHomepage(*settings, error); 271 info->search_engine = ParseSearchEngine(settings.get(), error); 272 info->startup_pages = ParseStartupPage(*settings, error); 273 if (!info->bookmarks_ui && !info->homepage && 274 !info->search_engine && info->startup_pages.empty()) { 275 *error = ErrorUtils::FormatErrorMessageUTF16( 276 manifest_errors::kInvalidEmptyDictionary, 277 manifest_keys::kSettingsOverride); 278 return false; 279 } 280 info->manifest_permission.reset(new ManifestPermissionImpl( 281 SettingsOverrides::RemovesBookmarkButton(*info))); 282 283 APIPermissionSet* permission_set = 284 PermissionsData::GetInitialAPIPermissions(extension); 285 DCHECK(permission_set); 286 if (info->search_engine) { 287 permission_set->insert(new SettingsOverrideAPIPermission( 288 PermissionsInfo::GetInstance()->GetByID(APIPermission::kSearchProvider), 289 RemoveWwwPrefix(CreateManifestURL(info->search_engine->search_url)-> 290 GetOrigin().host()))); 291 } 292 if (!info->startup_pages.empty()) { 293 permission_set->insert(new SettingsOverrideAPIPermission( 294 PermissionsInfo::GetInstance()->GetByID(APIPermission::kStartupPages), 295 // We only support one startup page even though the type of the manifest 296 // property is a list, only the first one is used. 297 RemoveWwwPrefix(info->startup_pages[0].GetContent()))); 298 } 299 if (info->homepage) { 300 permission_set->insert(new SettingsOverrideAPIPermission( 301 PermissionsInfo::GetInstance()->GetByID(APIPermission::kHomepage), 302 RemoveWwwPrefix(info->homepage.get()->GetContent()))); 303 } 304 extension->SetManifestData(manifest_keys::kSettingsOverride, 305 info.release()); 306 return true; 307} 308 309bool SettingsOverridesHandler::Validate( 310 const Extension* extension, 311 std::string* error, 312 std::vector<InstallWarning>* warnings) const { 313 const SettingsOverrides* settings_overrides = 314 SettingsOverrides::Get(extension); 315 316 if (settings_overrides && settings_overrides->bookmarks_ui) { 317 if (!FeatureSwitch::enable_override_bookmarks_ui()->IsEnabled()) { 318 warnings->push_back(InstallWarning( 319 ErrorUtils::FormatErrorMessage( 320 manifest_errors::kUnrecognizedManifestProperty, 321 manifest_keys::kBookmarkUI, 322 manifest_keys::kSettingsOverride))); 323 } else if (settings_overrides->bookmarks_ui->hide_bookmark_button) { 324 warnings->push_back(InstallWarning( 325 ErrorUtils::FormatErrorMessage( 326 manifest_errors::kKeyIsDeprecatedWithReplacement, 327 manifest_keys::kHideBookmarkButton, 328 manifest_keys::kRemoveButton))); 329 } 330 } 331 332 return true; 333} 334 335ManifestPermission* SettingsOverridesHandler::CreatePermission() { 336 return new ManifestPermissionImpl(false); 337} 338 339ManifestPermission* SettingsOverridesHandler::CreateInitialRequiredPermission( 340 const Extension* extension) { 341 const SettingsOverrides* data = SettingsOverrides::Get(extension); 342 if (data) 343 return data->manifest_permission->Clone(); 344 return NULL; 345} 346const std::vector<std::string> SettingsOverridesHandler::Keys() const { 347 return SingleKey(manifest_keys::kSettingsOverride); 348} 349 350} // namespace extensions 351