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