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 "extensions/common/manifest_handlers/background_info.h" 6 7 #include "base/command_line.h" 8 #include "base/files/file_util.h" 9 #include "base/lazy_instance.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "extensions/common/constants.h" 14 #include "extensions/common/error_utils.h" 15 #include "extensions/common/file_util.h" 16 #include "extensions/common/manifest_constants.h" 17 #include "extensions/common/manifest_handlers/permissions_parser.h" 18 #include "extensions/common/permissions/api_permission_set.h" 19 #include "extensions/common/switches.h" 20 #include "grit/extensions_strings.h" 21 #include "ui/base/l10n/l10n_util.h" 22 23 using base::ASCIIToUTF16; 24 using base::DictionaryValue; 25 26 namespace extensions { 27 28 namespace keys = manifest_keys; 29 namespace values = manifest_values; 30 namespace errors = manifest_errors; 31 32 namespace { 33 34 const char kBackground[] = "background"; 35 36 static base::LazyInstance<BackgroundInfo> g_empty_background_info = 37 LAZY_INSTANCE_INITIALIZER; 38 39 const BackgroundInfo& GetBackgroundInfo(const Extension* extension) { 40 BackgroundInfo* info = static_cast<BackgroundInfo*>( 41 extension->GetManifestData(kBackground)); 42 if (!info) 43 return g_empty_background_info.Get(); 44 return *info; 45 } 46 47 } // namespace 48 49 BackgroundInfo::BackgroundInfo() 50 : is_persistent_(true), 51 allow_js_access_(true) { 52 } 53 54 BackgroundInfo::~BackgroundInfo() { 55 } 56 57 // static 58 GURL BackgroundInfo::GetBackgroundURL(const Extension* extension) { 59 const BackgroundInfo& info = GetBackgroundInfo(extension); 60 if (info.background_scripts_.empty()) 61 return info.background_url_; 62 return extension->GetResourceURL(kGeneratedBackgroundPageFilename); 63 } 64 65 // static 66 const std::vector<std::string>& BackgroundInfo::GetBackgroundScripts( 67 const Extension* extension) { 68 return GetBackgroundInfo(extension).background_scripts_; 69 } 70 71 // static 72 bool BackgroundInfo::HasBackgroundPage(const Extension* extension) { 73 return GetBackgroundInfo(extension).has_background_page(); 74 } 75 76 // static 77 bool BackgroundInfo::HasPersistentBackgroundPage(const Extension* extension) { 78 return GetBackgroundInfo(extension).has_persistent_background_page(); 79 } 80 81 // static 82 bool BackgroundInfo::HasLazyBackgroundPage(const Extension* extension) { 83 return GetBackgroundInfo(extension).has_lazy_background_page(); 84 } 85 86 // static 87 bool BackgroundInfo::HasGeneratedBackgroundPage(const Extension* extension) { 88 const BackgroundInfo& info = GetBackgroundInfo(extension); 89 return !info.background_scripts_.empty(); 90 } 91 92 // static 93 bool BackgroundInfo::AllowJSAccess(const Extension* extension) { 94 return GetBackgroundInfo(extension).allow_js_access_; 95 } 96 97 bool BackgroundInfo::Parse(const Extension* extension, base::string16* error) { 98 const std::string& bg_scripts_key = extension->is_platform_app() ? 99 keys::kPlatformAppBackgroundScripts : keys::kBackgroundScripts; 100 if (!LoadBackgroundScripts(extension, bg_scripts_key, error) || 101 !LoadBackgroundPage(extension, error) || 102 !LoadBackgroundPersistent(extension, error) || 103 !LoadAllowJSAccess(extension, error)) { 104 return false; 105 } 106 107 int background_solution_sum = (background_url_.is_valid() ? 1 : 0) + 108 (!background_scripts_.empty() ? 1 : 0); 109 if (background_solution_sum > 1) { 110 *error = ASCIIToUTF16(errors::kInvalidBackgroundCombination); 111 return false; 112 } 113 114 return true; 115 } 116 117 bool BackgroundInfo::LoadBackgroundScripts(const Extension* extension, 118 const std::string& key, 119 base::string16* error) { 120 const base::Value* background_scripts_value = NULL; 121 if (!extension->manifest()->Get(key, &background_scripts_value)) 122 return true; 123 124 CHECK(background_scripts_value); 125 if (background_scripts_value->GetType() != base::Value::TYPE_LIST) { 126 *error = ASCIIToUTF16(errors::kInvalidBackgroundScripts); 127 return false; 128 } 129 130 const base::ListValue* background_scripts = NULL; 131 background_scripts_value->GetAsList(&background_scripts); 132 for (size_t i = 0; i < background_scripts->GetSize(); ++i) { 133 std::string script; 134 if (!background_scripts->GetString(i, &script)) { 135 *error = ErrorUtils::FormatErrorMessageUTF16( 136 errors::kInvalidBackgroundScript, base::IntToString(i)); 137 return false; 138 } 139 background_scripts_.push_back(script); 140 } 141 142 return true; 143 } 144 145 bool BackgroundInfo::LoadBackgroundPage(const Extension* extension, 146 const std::string& key, 147 base::string16* error) { 148 const base::Value* background_page_value = NULL; 149 if (!extension->manifest()->Get(key, &background_page_value)) 150 return true; 151 152 std::string background_str; 153 if (!background_page_value->GetAsString(&background_str)) { 154 *error = ASCIIToUTF16(errors::kInvalidBackground); 155 return false; 156 } 157 158 if (extension->is_hosted_app()) { 159 background_url_ = GURL(background_str); 160 161 if (!PermissionsParser::HasAPIPermission(extension, 162 APIPermission::kBackground)) { 163 *error = ASCIIToUTF16(errors::kBackgroundPermissionNeeded); 164 return false; 165 } 166 // Hosted apps require an absolute URL. 167 if (!background_url_.is_valid()) { 168 *error = ASCIIToUTF16(errors::kInvalidBackgroundInHostedApp); 169 return false; 170 } 171 172 if (!(background_url_.SchemeIs("https") || 173 (CommandLine::ForCurrentProcess()->HasSwitch( 174 switches::kAllowHTTPBackgroundPage) && 175 background_url_.SchemeIs("http")))) { 176 *error = ASCIIToUTF16(errors::kInvalidBackgroundInHostedApp); 177 return false; 178 } 179 } else { 180 background_url_ = extension->GetResourceURL(background_str); 181 } 182 183 return true; 184 } 185 186 bool BackgroundInfo::LoadBackgroundPage(const Extension* extension, 187 base::string16* error) { 188 if (extension->is_platform_app()) { 189 return LoadBackgroundPage( 190 extension, keys::kPlatformAppBackgroundPage, error); 191 } 192 193 if (!LoadBackgroundPage(extension, keys::kBackgroundPage, error)) 194 return false; 195 if (background_url_.is_empty()) 196 return LoadBackgroundPage(extension, keys::kBackgroundPageLegacy, error); 197 return true; 198 } 199 200 bool BackgroundInfo::LoadBackgroundPersistent(const Extension* extension, 201 base::string16* error) { 202 if (extension->is_platform_app()) { 203 is_persistent_ = false; 204 return true; 205 } 206 207 const base::Value* background_persistent = NULL; 208 if (!extension->manifest()->Get(keys::kBackgroundPersistent, 209 &background_persistent)) 210 return true; 211 212 if (!background_persistent->GetAsBoolean(&is_persistent_)) { 213 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistent); 214 return false; 215 } 216 217 if (!has_background_page()) { 218 *error = ASCIIToUTF16(errors::kInvalidBackgroundPersistentNoPage); 219 return false; 220 } 221 222 return true; 223 } 224 225 bool BackgroundInfo::LoadAllowJSAccess(const Extension* extension, 226 base::string16* error) { 227 const base::Value* allow_js_access = NULL; 228 if (!extension->manifest()->Get(keys::kBackgroundAllowJsAccess, 229 &allow_js_access)) 230 return true; 231 232 if (!allow_js_access->IsType(base::Value::TYPE_BOOLEAN) || 233 !allow_js_access->GetAsBoolean(&allow_js_access_)) { 234 *error = ASCIIToUTF16(errors::kInvalidBackgroundAllowJsAccess); 235 return false; 236 } 237 238 return true; 239 } 240 241 BackgroundManifestHandler::BackgroundManifestHandler() { 242 } 243 244 BackgroundManifestHandler::~BackgroundManifestHandler() { 245 } 246 247 bool BackgroundManifestHandler::Parse(Extension* extension, 248 base::string16* error) { 249 scoped_ptr<BackgroundInfo> info(new BackgroundInfo); 250 if (!info->Parse(extension, error)) 251 return false; 252 253 // Platform apps must have background pages. 254 if (extension->is_platform_app() && !info->has_background_page()) { 255 *error = ASCIIToUTF16(errors::kBackgroundRequiredForPlatformApps); 256 return false; 257 } 258 // Lazy background pages are incompatible with the webRequest API. 259 if (info->has_lazy_background_page() && 260 PermissionsParser::HasAPIPermission(extension, 261 APIPermission::kWebRequest)) { 262 *error = ASCIIToUTF16(errors::kWebRequestConflictsWithLazyBackground); 263 return false; 264 } 265 266 extension->SetManifestData(kBackground, info.release()); 267 return true; 268 } 269 270 bool BackgroundManifestHandler::Validate( 271 const Extension* extension, 272 std::string* error, 273 std::vector<InstallWarning>* warnings) const { 274 // Validate that background scripts exist. 275 const std::vector<std::string>& background_scripts = 276 BackgroundInfo::GetBackgroundScripts(extension); 277 for (size_t i = 0; i < background_scripts.size(); ++i) { 278 if (!base::PathExists( 279 extension->GetResource(background_scripts[i]).GetFilePath())) { 280 *error = l10n_util::GetStringFUTF8( 281 IDS_EXTENSION_LOAD_BACKGROUND_SCRIPT_FAILED, 282 base::UTF8ToUTF16(background_scripts[i])); 283 return false; 284 } 285 } 286 287 // Validate background page location, except for hosted apps, which should use 288 // an external URL. Background page for hosted apps are verified when the 289 // extension is created (in Extension::InitFromValue) 290 if (BackgroundInfo::HasBackgroundPage(extension) && 291 !extension->is_hosted_app() && background_scripts.empty()) { 292 base::FilePath page_path = file_util::ExtensionURLToRelativeFilePath( 293 BackgroundInfo::GetBackgroundURL(extension)); 294 const base::FilePath path = extension->GetResource(page_path).GetFilePath(); 295 if (path.empty() || !base::PathExists(path)) { 296 *error = 297 l10n_util::GetStringFUTF8( 298 IDS_EXTENSION_LOAD_BACKGROUND_PAGE_FAILED, 299 page_path.LossyDisplayName()); 300 return false; 301 } 302 } 303 return true; 304 } 305 306 bool BackgroundManifestHandler::AlwaysParseForType(Manifest::Type type) const { 307 return type == Manifest::TYPE_PLATFORM_APP; 308 } 309 310 const std::vector<std::string> BackgroundManifestHandler::Keys() const { 311 static const char* keys[] = { 312 keys::kBackgroundAllowJsAccess, keys::kBackgroundPage, 313 keys::kBackgroundPageLegacy, keys::kBackgroundPersistent, 314 keys::kBackgroundScripts, keys::kPlatformAppBackgroundPage, 315 keys::kPlatformAppBackgroundScripts}; 316 return std::vector<std::string>(keys, keys + arraysize(keys)); 317 } 318 319 } // namespace extensions 320