| OLD | NEW |
| (Empty) |
| 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/permissions/permissions_data.h" | |
| 16 #include "extensions/common/constants.h" | |
| 17 #include "extensions/common/error_utils.h" | |
| 18 #include "extensions/common/manifest_constants.h" | |
| 19 #include "extensions/common/permissions/api_permission_set.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 extensions::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 (extensions::BackgroundInfo::HasBackgroundPage(extension) && | |
| 286 !extension->is_hosted_app() && background_scripts.empty()) { | |
| 287 base::FilePath page_path = | |
| 288 extension_file_util::ExtensionURLToRelativeFilePath( | |
| 289 extensions::BackgroundInfo::GetBackgroundURL(extension)); | |
| 290 const base::FilePath path = extension->GetResource(page_path).GetFilePath(); | |
| 291 if (path.empty() || !base::PathExists(path)) { | |
| 292 *error = | |
| 293 l10n_util::GetStringFUTF8( | |
| 294 IDS_EXTENSION_LOAD_BACKGROUND_PAGE_FAILED, | |
| 295 page_path.LossyDisplayName()); | |
| 296 return false; | |
| 297 } | |
| 298 } | |
| 299 return true; | |
| 300 } | |
| 301 | |
| 302 bool BackgroundManifestHandler::AlwaysParseForType(Manifest::Type type) const { | |
| 303 return type == Manifest::TYPE_PLATFORM_APP; | |
| 304 } | |
| 305 | |
| 306 const std::vector<std::string> BackgroundManifestHandler::Keys() const { | |
| 307 static const char* keys[] = { | |
| 308 keys::kBackgroundAllowJsAccess, | |
| 309 keys::kBackgroundPage, | |
| 310 keys::kBackgroundPageLegacy, | |
| 311 keys::kBackgroundPersistent, | |
| 312 keys::kBackgroundScripts, | |
| 313 keys::kPlatformAppBackgroundPage, | |
| 314 keys::kPlatformAppBackgroundScripts | |
| 315 }; | |
| 316 return std::vector<std::string>(keys, keys + arraysize(keys)); | |
| 317 } | |
| 318 | |
| 319 } // namespace extensions | |
| OLD | NEW |