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