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