Home | History | Annotate | Download | only in manifest_handlers
      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