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 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 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 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 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. 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 115 SettingsOverrides::SettingsOverrides() {} 116 117 SettingsOverrides::~SettingsOverrides() {} 118 119 // static 120 const SettingsOverrides* SettingsOverrides::Get( 121 const Extension* extension) { 122 return static_cast<SettingsOverrides*>( 123 extension->GetManifestData(manifest_keys::kSettingsOverride)); 124 } 125 126 SettingsOverridesHandler::SettingsOverridesHandler() {} 127 128 SettingsOverridesHandler::~SettingsOverridesHandler() {} 129 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 183 const std::vector<std::string> SettingsOverridesHandler::Keys() const { 184 return SingleKey(manifest_keys::kSettingsOverride); 185 } 186 187 } // namespace extensions 188