• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetBackgroundInfo(const Extension * extension)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 
BackgroundInfo()48 BackgroundInfo::BackgroundInfo()
49     : is_persistent_(true),
50       allow_js_access_(true) {
51 }
52 
~BackgroundInfo()53 BackgroundInfo::~BackgroundInfo() {
54 }
55 
56 // static
GetBackgroundURL(const Extension * extension)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
HasGeneratedBackgroundPage(const Extension * extension)65 bool BackgroundInfo::HasGeneratedBackgroundPage(const Extension* extension) {
66   const BackgroundInfo& info = GetBackgroundInfo(extension);
67   return !info.background_scripts_.empty();
68 }
69 
70 // static
GetBackgroundScripts(const Extension * extension)71 const std::vector<std::string>& BackgroundInfo::GetBackgroundScripts(
72     const Extension* extension) {
73   return GetBackgroundInfo(extension).background_scripts_;
74 }
75 
76 // static
HasBackgroundPage(const Extension * extension)77 bool BackgroundInfo::HasBackgroundPage(const Extension* extension) {
78   return GetBackgroundInfo(extension).has_background_page();
79 }
80 
81 // static
AllowJSAccess(const Extension * extension)82 bool BackgroundInfo::AllowJSAccess(const Extension* extension) {
83   return GetBackgroundInfo(extension).allow_js_access_;
84 }
85 
86 // static
HasPersistentBackgroundPage(const Extension * extension)87 bool BackgroundInfo::HasPersistentBackgroundPage(const Extension* extension)  {
88   return GetBackgroundInfo(extension).has_persistent_background_page();
89 }
90 
91 // static
HasLazyBackgroundPage(const Extension * extension)92 bool BackgroundInfo::HasLazyBackgroundPage(const Extension* extension) {
93   return GetBackgroundInfo(extension).has_lazy_background_page();
94 }
95 
Parse(const Extension * extension,string16 * error)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 
LoadBackgroundScripts(const Extension * extension,const std::string & key,string16 * error)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 
LoadBackgroundPage(const Extension * extension,const std::string & key,string16 * error)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 
LoadBackgroundPage(const Extension * extension,string16 * error)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 
LoadBackgroundPersistent(const Extension * extension,string16 * error)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 
LoadAllowJSAccess(const Extension * extension,string16 * error)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 
BackgroundManifestHandler()237 BackgroundManifestHandler::BackgroundManifestHandler() {
238 }
239 
~BackgroundManifestHandler()240 BackgroundManifestHandler::~BackgroundManifestHandler() {
241 }
242 
Parse(Extension * extension,string16 * error)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 
Validate(const Extension * extension,std::string * error,std::vector<InstallWarning> * warnings) const265 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 
AlwaysParseForType(Manifest::Type type) const301 bool BackgroundManifestHandler::AlwaysParseForType(Manifest::Type type) const {
302   return type == Manifest::TYPE_PLATFORM_APP;
303 }
304 
Keys() const305 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