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 "chrome/common/extensions/extension_messages.h" 13 #include "chrome/common/extensions/permissions/settings_override_permission.h" 14 #include "extensions/common/error_utils.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" 24 #include "url/gurl.h" 25 26 using extensions::api::manifest_types::ChromeSettingsOverrides; 27 28 namespace extensions { 29 namespace { 30 31 const char* kWwwPrefix = "www."; 32 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(); 39 } 40 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); 46 if (!manifest_url) { 47 *error = extensions::ErrorUtils::FormatErrorMessageUTF16( 48 manifest_errors::kInvalidHomepageOverrideURL, *overrides.homepage); 49 } 50 return manifest_url.Pass(); 51 } 52 53 std::vector<GURL> ParseStartupPage(const ChromeSettingsOverrides& overrides, 54 base::string16* error) { 55 std::vector<GURL> urls; 56 if (!overrides.startup_pages) 57 return urls; 58 59 for (std::vector<std::string>::const_iterator i = 60 overrides.startup_pages->begin(); i != overrides.startup_pages->end(); 61 ++i) { 62 scoped_ptr<GURL> manifest_url = CreateManifestURL(*i); 63 if (!manifest_url) { 64 *error = extensions::ErrorUtils::FormatErrorMessageUTF16( 65 manifest_errors::kInvalidStartupOverrideURL, *i); 66 } else { 67 urls.push_back(GURL()); 68 urls.back().Swap(manifest_url.get()); 69 } 70 } 71 return urls; 72 } 73 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>(); 84 } 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>(); 90 } 91 return overrides->search_provider.Pass(); 92 } 93 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)); 99 return url; 100 } 101 102 } // namespace 103 104 // The manifest permission implementation supports a permission for hiding 105 // the bookmark button. 106 class SettingsOverridesHandler::ManifestPermissionImpl 107 : public ManifestPermission { 108 public: 109 explicit ManifestPermissionImpl(bool hide_bookmark_button_permission) 110 : hide_bookmark_button_permission_(hide_bookmark_button_permission) {} 111 112 // extensions::ManifestPermission overrides. 113 virtual std::string name() const OVERRIDE { 114 return manifest_keys::kSettingsOverride; 115 } 116 117 virtual std::string id() const OVERRIDE { 118 return name(); 119 } 120 121 virtual bool HasMessages() const OVERRIDE { 122 return hide_bookmark_button_permission_; 123 } 124 125 virtual PermissionMessages GetMessages() const OVERRIDE { 126 PermissionMessages result; 127 if (hide_bookmark_button_permission_) { 128 result.push_back(PermissionMessage( 129 PermissionMessage::kHideBookmarkButton, 130 l10n_util::GetStringUTF16( 131 IDS_EXTENSION_PROMPT_WARNING_HIDE_BOOKMARK_STAR))); 132 } 133 return result; 134 } 135 136 virtual bool FromValue(const base::Value* value) OVERRIDE { 137 return value && value->GetAsBoolean(&hide_bookmark_button_permission_); 138 } 139 140 virtual scoped_ptr<base::Value> ToValue() const OVERRIDE { 141 return scoped_ptr<base::Value>( 142 new base::FundamentalValue(hide_bookmark_button_permission_)).Pass(); 143 } 144 145 virtual ManifestPermission* Clone() const OVERRIDE { 146 return scoped_ptr<ManifestPermissionImpl>( 147 new ManifestPermissionImpl(hide_bookmark_button_permission_)).release(); 148 } 149 150 virtual ManifestPermission* Diff(const ManifestPermission* rhs) const 151 OVERRIDE { 152 const ManifestPermissionImpl* other = 153 static_cast<const ManifestPermissionImpl*>(rhs); 154 155 return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl( 156 hide_bookmark_button_permission_ && 157 !other->hide_bookmark_button_permission_)).release(); 158 } 159 160 virtual ManifestPermission* Union(const ManifestPermission* rhs) const 161 OVERRIDE { 162 const ManifestPermissionImpl* other = 163 static_cast<const ManifestPermissionImpl*>(rhs); 164 165 return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl( 166 hide_bookmark_button_permission_ || 167 other->hide_bookmark_button_permission_)).release(); 168 } 169 170 virtual ManifestPermission* Intersect(const ManifestPermission* rhs) const 171 OVERRIDE { 172 const ManifestPermissionImpl* other = 173 static_cast<const ManifestPermissionImpl*>(rhs); 174 175 return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl( 176 hide_bookmark_button_permission_ && 177 other->hide_bookmark_button_permission_)).release(); 178 } 179 180 virtual bool Contains(const ManifestPermission* rhs) const OVERRIDE { 181 const ManifestPermissionImpl* other = 182 static_cast<const ManifestPermissionImpl*>(rhs); 183 184 return !other->hide_bookmark_button_permission_ || 185 hide_bookmark_button_permission_; 186 } 187 188 virtual bool Equal(const ManifestPermission* rhs) const OVERRIDE { 189 const ManifestPermissionImpl* other = 190 static_cast<const ManifestPermissionImpl*>(rhs); 191 192 return hide_bookmark_button_permission_ == 193 other->hide_bookmark_button_permission_; 194 } 195 196 virtual void Write(IPC::Message* m) const OVERRIDE { 197 IPC::WriteParam(m, hide_bookmark_button_permission_); 198 } 199 200 virtual bool Read(const IPC::Message* m, PickleIterator* iter) OVERRIDE { 201 return IPC::ReadParam(m, iter, &hide_bookmark_button_permission_); 202 } 203 204 virtual void Log(std::string* log) const OVERRIDE { 205 IPC::LogParam(hide_bookmark_button_permission_, log); 206 } 207 208 private: 209 bool hide_bookmark_button_permission_; 210 }; 211 212 SettingsOverrides::SettingsOverrides() {} 213 214 SettingsOverrides::~SettingsOverrides() {} 215 216 const SettingsOverrides* SettingsOverrides::Get( 217 const Extension* extension) { 218 return static_cast<SettingsOverrides*>( 219 extension->GetManifestData(manifest_keys::kSettingsOverride)); 220 } 221 222 bool SettingsOverrides::RequiresHideBookmarkButtonPermission() const { 223 return bookmarks_ui && bookmarks_ui->hide_bookmark_button && 224 *bookmarks_ui->hide_bookmark_button; 225 } 226 227 SettingsOverridesHandler::SettingsOverridesHandler() {} 228 229 SettingsOverridesHandler::~SettingsOverridesHandler() {} 230 231 bool SettingsOverridesHandler::Parse(Extension* extension, 232 base::string16* error) { 233 const base::Value* dict = NULL; 234 CHECK(extension->manifest()->Get(manifest_keys::kSettingsOverride, &dict)); 235 scoped_ptr<ChromeSettingsOverrides> settings( 236 ChromeSettingsOverrides::FromValue(*dict, error)); 237 if (!settings) 238 return false; 239 240 scoped_ptr<SettingsOverrides> info(new SettingsOverrides); 241 info->bookmarks_ui.swap(settings->bookmarks_ui); 242 info->homepage = ParseHomepage(*settings, error); 243 info->search_engine = ParseSearchEngine(settings.get(), error); 244 info->startup_pages = ParseStartupPage(*settings, error); 245 if (!info->bookmarks_ui && !info->homepage && 246 !info->search_engine && info->startup_pages.empty()) { 247 *error = ASCIIToUTF16(manifest_errors::kInvalidEmptySettingsOverrides); 248 return false; 249 } 250 info->manifest_permission.reset(new ManifestPermissionImpl( 251 info->RequiresHideBookmarkButtonPermission())); 252 253 APIPermissionSet* permission_set = 254 PermissionsData::GetInitialAPIPermissions(extension); 255 DCHECK(permission_set); 256 if (info->search_engine) { 257 permission_set->insert(new SettingsOverrideAPIPermission( 258 PermissionsInfo::GetInstance()->GetByID(APIPermission::kSearchProvider), 259 RemoveWwwPrefix(CreateManifestURL(info->search_engine->search_url)-> 260 GetOrigin().host()))); 261 } 262 if (!info->startup_pages.empty()) { 263 permission_set->insert(new SettingsOverrideAPIPermission( 264 PermissionsInfo::GetInstance()->GetByID(APIPermission::kStartupPages), 265 // We only support one startup page even though the type of the manifest 266 // property is a list, only the first one is used. 267 RemoveWwwPrefix(info->startup_pages[0].GetContent()))); 268 } 269 if (info->homepage) { 270 permission_set->insert(new SettingsOverrideAPIPermission( 271 PermissionsInfo::GetInstance()->GetByID(APIPermission::kHomepage), 272 RemoveWwwPrefix(info->homepage.get()->GetContent()))); 273 } 274 extension->SetManifestData(manifest_keys::kSettingsOverride, 275 info.release()); 276 return true; 277 } 278 279 bool SettingsOverridesHandler::Validate( 280 const Extension* extension, 281 std::string* error, 282 std::vector<InstallWarning>* warnings) const { 283 const SettingsOverrides* settings_overrides = 284 SettingsOverrides::Get(extension); 285 286 if (settings_overrides && settings_overrides->bookmarks_ui && 287 !FeatureSwitch::enable_override_bookmarks_ui()->IsEnabled()) { 288 warnings->push_back(InstallWarning( 289 ErrorUtils::FormatErrorMessage( 290 manifest_errors::kUnrecognizedManifestProperty, 291 manifest_keys::kHideBookmarkButton, 292 manifest_keys::kBookmarkUI))); 293 } 294 295 return true; 296 } 297 298 ManifestPermission* SettingsOverridesHandler::CreatePermission() { 299 return new ManifestPermissionImpl(false); 300 } 301 302 ManifestPermission* SettingsOverridesHandler::CreateInitialRequiredPermission( 303 const Extension* extension) { 304 const SettingsOverrides* data = SettingsOverrides::Get(extension); 305 if (data) 306 return data->manifest_permission->Clone(); 307 return NULL; 308 } 309 const std::vector<std::string> SettingsOverridesHandler::Keys() const { 310 return SingleKey(manifest_keys::kSettingsOverride); 311 } 312 313 } // namespace extensions 314