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