1// Copyright 2014 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/browser/extensions/extension_system_impl.h"
6
7#include "base/base_switches.h"
8#include "base/bind.h"
9#include "base/command_line.h"
10#include "base/files/file_path.h"
11#include "base/memory/weak_ptr.h"
12#include "base/strings/string_tokenizer.h"
13#include "chrome/browser/browser_process.h"
14#include "chrome/browser/content_settings/cookie_settings.h"
15#include "chrome/browser/extensions/blacklist.h"
16#include "chrome/browser/extensions/component_loader.h"
17#include "chrome/browser/extensions/error_console/error_console.h"
18#include "chrome/browser/extensions/extension_error_reporter.h"
19#include "chrome/browser/extensions/extension_service.h"
20#include "chrome/browser/extensions/extension_system_factory.h"
21#include "chrome/browser/extensions/extension_util.h"
22#include "chrome/browser/extensions/extension_warning_badge_service.h"
23#include "chrome/browser/extensions/extension_warning_set.h"
24#include "chrome/browser/extensions/install_verifier.h"
25#include "chrome/browser/extensions/navigation_observer.h"
26#include "chrome/browser/extensions/shared_module_service.h"
27#include "chrome/browser/extensions/standard_management_policy_provider.h"
28#include "chrome/browser/extensions/state_store.h"
29#include "chrome/browser/extensions/unpacked_installer.h"
30#include "chrome/browser/extensions/updater/manifest_fetch_data.h"
31#include "chrome/browser/extensions/user_script_master.h"
32#include "chrome/browser/profiles/profile.h"
33#include "chrome/browser/profiles/profile_manager.h"
34#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
35#include "chrome/common/chrome_switches.h"
36#include "chrome/common/chrome_version_info.h"
37#include "chrome/common/extensions/extension_constants.h"
38#include "chrome/common/extensions/extension_file_util.h"
39#include "chrome/common/extensions/features/feature_channel.h"
40#include "chrome/common/extensions/manifest_url_handler.h"
41#include "content/public/browser/browser_thread.h"
42#include "content/public/browser/url_data_source.h"
43#include "extensions/browser/content_verifier.h"
44#include "extensions/browser/content_verifier_delegate.h"
45#include "extensions/browser/event_router.h"
46#include "extensions/browser/extension_pref_store.h"
47#include "extensions/browser/extension_pref_value_map.h"
48#include "extensions/browser/extension_pref_value_map_factory.h"
49#include "extensions/browser/extension_prefs.h"
50#include "extensions/browser/extension_registry.h"
51#include "extensions/browser/info_map.h"
52#include "extensions/browser/lazy_background_task_queue.h"
53#include "extensions/browser/management_policy.h"
54#include "extensions/browser/process_manager.h"
55#include "extensions/browser/quota_service.h"
56#include "extensions/browser/runtime_data.h"
57#include "extensions/common/constants.h"
58#include "extensions/common/extension.h"
59#include "extensions/common/manifest.h"
60#include "net/base/escape.h"
61
62#if defined(ENABLE_NOTIFICATIONS)
63#include "chrome/browser/notifications/desktop_notification_service.h"
64#include "chrome/browser/notifications/desktop_notification_service_factory.h"
65#include "ui/message_center/notifier_settings.h"
66#endif
67
68#if defined(OS_CHROMEOS)
69#include "chrome/browser/app_mode/app_mode_utils.h"
70#include "chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.h"
71#include "chrome/browser/chromeos/login/users/user.h"
72#include "chrome/browser/chromeos/login/users/user_manager.h"
73#include "chrome/browser/chromeos/policy/device_local_account.h"
74#include "chromeos/chromeos_switches.h"
75#include "chromeos/login/login_state.h"
76#endif
77
78using content::BrowserThread;
79
80namespace extensions {
81
82//
83// ExtensionSystemImpl::Shared
84//
85
86ExtensionSystemImpl::Shared::Shared(Profile* profile)
87    : profile_(profile) {
88}
89
90ExtensionSystemImpl::Shared::~Shared() {
91}
92
93void ExtensionSystemImpl::Shared::InitPrefs() {
94  lazy_background_task_queue_.reset(new LazyBackgroundTaskQueue(profile_));
95  event_router_.reset(new EventRouter(profile_, ExtensionPrefs::Get(profile_)));
96// TODO(yoz): Remove once crbug.com/159265 is fixed.
97#if defined(ENABLE_EXTENSIONS)
98  // Two state stores. The latter, which contains declarative rules, must be
99  // loaded immediately so that the rules are ready before we issue network
100  // requests.
101  state_store_.reset(new StateStore(
102      profile_,
103      profile_->GetPath().AppendASCII(extensions::kStateStoreName),
104      true));
105
106  rules_store_.reset(new StateStore(
107      profile_,
108      profile_->GetPath().AppendASCII(extensions::kRulesStoreName),
109      false));
110
111  blacklist_.reset(new Blacklist(ExtensionPrefs::Get(profile_)));
112
113  standard_management_policy_provider_.reset(
114      new StandardManagementPolicyProvider(ExtensionPrefs::Get(profile_)));
115
116#if defined (OS_CHROMEOS)
117  const chromeos::User* user = chromeos::UserManager::Get()->GetActiveUser();
118  policy::DeviceLocalAccount::Type device_local_account_type;
119  if (user && policy::IsDeviceLocalAccountUser(user->email(),
120                                               &device_local_account_type)) {
121    device_local_account_management_policy_provider_.reset(
122        new chromeos::DeviceLocalAccountManagementPolicyProvider(
123            device_local_account_type));
124  }
125#endif  // defined (OS_CHROMEOS)
126
127#endif  // defined(ENABLE_EXTENSIONS)
128}
129
130void ExtensionSystemImpl::Shared::RegisterManagementPolicyProviders() {
131// TODO(yoz): Remove once crbug.com/159265 is fixed.
132#if defined(ENABLE_EXTENSIONS)
133  DCHECK(standard_management_policy_provider_.get());
134  management_policy_->RegisterProvider(
135      standard_management_policy_provider_.get());
136
137#if defined (OS_CHROMEOS)
138  if (device_local_account_management_policy_provider_) {
139    management_policy_->RegisterProvider(
140        device_local_account_management_policy_provider_.get());
141  }
142#endif  // defined (OS_CHROMEOS)
143
144  management_policy_->RegisterProvider(install_verifier_.get());
145
146#endif  // defined(ENABLE_EXTENSIONS)
147}
148
149namespace {
150
151class ContentVerifierDelegateImpl : public ContentVerifierDelegate {
152 public:
153  explicit ContentVerifierDelegateImpl(ExtensionService* service)
154      : service_(service->AsWeakPtr()) {}
155
156  virtual ~ContentVerifierDelegateImpl() {}
157
158  virtual bool ShouldBeVerified(const Extension& extension) OVERRIDE {
159    if (!extension.is_extension() && !extension.is_legacy_packaged_app())
160      return false;
161    if (!Manifest::IsAutoUpdateableLocation(extension.location()))
162      return false;
163
164    if (!ManifestURL::UpdatesFromGallery(&extension)) {
165      // It's possible that the webstore update url was overridden for testing
166      // so also consider extensions with the default (production) update url
167      // to be from the store as well.
168      GURL default_webstore_url = extension_urls::GetDefaultWebstoreUpdateUrl();
169      if (ManifestURL::GetUpdateURL(&extension) != default_webstore_url)
170        return false;
171    }
172
173    return true;
174  }
175
176  virtual const ContentVerifierKey& PublicKey() OVERRIDE {
177    static ContentVerifierKey key(
178        extension_misc::kWebstoreSignaturesPublicKey,
179        extension_misc::kWebstoreSignaturesPublicKeySize);
180    return key;
181  }
182
183  virtual GURL GetSignatureFetchUrl(const std::string& extension_id,
184                                    const base::Version& version) OVERRIDE {
185    // TODO(asargent) Factor out common code from the extension updater's
186    // ManifestFetchData class that can be shared for use here.
187    std::vector<std::string> parts;
188    parts.push_back("uc");
189    parts.push_back("installsource=signature");
190    parts.push_back("id=" + extension_id);
191    parts.push_back("v=" + version.GetString());
192    std::string x_value =
193        net::EscapeQueryParamValue(JoinString(parts, "&"), true);
194    std::string query = "response=redirect&x=" + x_value;
195
196    GURL base_url = extension_urls::GetWebstoreUpdateUrl();
197    GURL::Replacements replacements;
198    replacements.SetQuery(query.c_str(), url::Component(0, query.length()));
199    return base_url.ReplaceComponents(replacements);
200  }
201
202  virtual std::set<base::FilePath> GetBrowserImagePaths(
203      const extensions::Extension* extension) OVERRIDE {
204    return extension_file_util::GetBrowserImagePaths(extension);
205  }
206
207  virtual void VerifyFailed(const std::string& extension_id) OVERRIDE {
208    if (service_)
209      service_->DisableExtension(extension_id, Extension::DISABLE_CORRUPTED);
210  }
211
212 private:
213  base::WeakPtr<ExtensionService> service_;
214  DISALLOW_COPY_AND_ASSIGN(ContentVerifierDelegateImpl);
215};
216
217}  // namespace
218
219void ExtensionSystemImpl::Shared::Init(bool extensions_enabled) {
220  const CommandLine* command_line = CommandLine::ForCurrentProcess();
221
222  navigation_observer_.reset(new NavigationObserver(profile_));
223
224  bool allow_noisy_errors = !command_line->HasSwitch(switches::kNoErrorDialogs);
225  ExtensionErrorReporter::Init(allow_noisy_errors);
226
227  user_script_master_ = new UserScriptMaster(profile_);
228
229  // ExtensionService depends on RuntimeData.
230  runtime_data_.reset(new RuntimeData(ExtensionRegistry::Get(profile_)));
231
232  bool autoupdate_enabled = !profile_->IsGuestSession();
233#if defined(OS_CHROMEOS)
234  if (!extensions_enabled)
235    autoupdate_enabled = false;
236#endif
237  extension_service_.reset(new ExtensionService(
238      profile_,
239      CommandLine::ForCurrentProcess(),
240      profile_->GetPath().AppendASCII(extensions::kInstallDirectoryName),
241      ExtensionPrefs::Get(profile_),
242      blacklist_.get(),
243      autoupdate_enabled,
244      extensions_enabled,
245      &ready_));
246
247  // These services must be registered before the ExtensionService tries to
248  // load any extensions.
249  {
250    install_verifier_.reset(
251        new InstallVerifier(ExtensionPrefs::Get(profile_), profile_));
252    install_verifier_->Init();
253    content_verifier_ = new ContentVerifier(
254        profile_, new ContentVerifierDelegateImpl(extension_service_.get()));
255    content_verifier_->Start();
256    info_map()->SetContentVerifier(content_verifier_.get());
257
258    management_policy_.reset(new ManagementPolicy);
259    RegisterManagementPolicyProviders();
260  }
261
262  bool skip_session_extensions = false;
263#if defined(OS_CHROMEOS)
264  // Skip loading session extensions if we are not in a user session.
265  skip_session_extensions = !chromeos::LoginState::Get()->IsUserLoggedIn();
266  if (chrome::IsRunningInForcedAppMode()) {
267    extension_service_->component_loader()->
268        AddDefaultComponentExtensionsForKioskMode(skip_session_extensions);
269  } else {
270    extension_service_->component_loader()->AddDefaultComponentExtensions(
271        skip_session_extensions);
272  }
273#else
274  extension_service_->component_loader()->AddDefaultComponentExtensions(
275      skip_session_extensions);
276#endif
277  if (command_line->HasSwitch(switches::kLoadComponentExtension)) {
278    CommandLine::StringType path_list = command_line->GetSwitchValueNative(
279        switches::kLoadComponentExtension);
280    base::StringTokenizerT<CommandLine::StringType,
281        CommandLine::StringType::const_iterator> t(path_list,
282                                                   FILE_PATH_LITERAL(","));
283    while (t.GetNext()) {
284      // Load the component extension manifest synchronously.
285      // Blocking the UI thread is acceptable here since
286      // this flag designated for developers.
287      base::ThreadRestrictions::ScopedAllowIO allow_io;
288      extension_service_->component_loader()->AddOrReplace(
289          base::FilePath(t.token()));
290    }
291  }
292  extension_service_->Init();
293
294  // Make the chrome://extension-icon/ resource available.
295  content::URLDataSource::Add(profile_, new ExtensionIconSource(profile_));
296
297  extension_warning_service_.reset(new ExtensionWarningService(profile_));
298  extension_warning_badge_service_.reset(
299      new ExtensionWarningBadgeService(profile_));
300  extension_warning_service_->AddObserver(
301      extension_warning_badge_service_.get());
302  error_console_.reset(new ErrorConsole(profile_));
303  quota_service_.reset(new QuotaService);
304
305  if (extensions_enabled) {
306    // Load any extensions specified with --load-extension.
307    // TODO(yoz): Seems like this should move into ExtensionService::Init.
308    // But maybe it's no longer important.
309    if (command_line->HasSwitch(switches::kLoadExtension)) {
310      CommandLine::StringType path_list = command_line->GetSwitchValueNative(
311          switches::kLoadExtension);
312      base::StringTokenizerT<CommandLine::StringType,
313          CommandLine::StringType::const_iterator> t(path_list,
314                                                     FILE_PATH_LITERAL(","));
315      while (t.GetNext()) {
316        std::string extension_id;
317        UnpackedInstaller::Create(extension_service_.get())->
318            LoadFromCommandLine(base::FilePath(t.token()), &extension_id);
319      }
320    }
321  }
322}
323
324void ExtensionSystemImpl::Shared::Shutdown() {
325  if (extension_warning_service_) {
326    extension_warning_service_->RemoveObserver(
327        extension_warning_badge_service_.get());
328  }
329  if (content_verifier_)
330    content_verifier_->Shutdown();
331  if (extension_service_)
332    extension_service_->Shutdown();
333}
334
335StateStore* ExtensionSystemImpl::Shared::state_store() {
336  return state_store_.get();
337}
338
339StateStore* ExtensionSystemImpl::Shared::rules_store() {
340  return rules_store_.get();
341}
342
343ExtensionService* ExtensionSystemImpl::Shared::extension_service() {
344  return extension_service_.get();
345}
346
347RuntimeData* ExtensionSystemImpl::Shared::runtime_data() {
348  return runtime_data_.get();
349}
350
351ManagementPolicy* ExtensionSystemImpl::Shared::management_policy() {
352  return management_policy_.get();
353}
354
355UserScriptMaster* ExtensionSystemImpl::Shared::user_script_master() {
356  return user_script_master_.get();
357}
358
359InfoMap* ExtensionSystemImpl::Shared::info_map() {
360  if (!extension_info_map_.get())
361    extension_info_map_ = new InfoMap();
362  return extension_info_map_.get();
363}
364
365LazyBackgroundTaskQueue*
366    ExtensionSystemImpl::Shared::lazy_background_task_queue() {
367  return lazy_background_task_queue_.get();
368}
369
370EventRouter* ExtensionSystemImpl::Shared::event_router() {
371  return event_router_.get();
372}
373
374ExtensionWarningService* ExtensionSystemImpl::Shared::warning_service() {
375  return extension_warning_service_.get();
376}
377
378Blacklist* ExtensionSystemImpl::Shared::blacklist() {
379  return blacklist_.get();
380}
381
382ErrorConsole* ExtensionSystemImpl::Shared::error_console() {
383  return error_console_.get();
384}
385
386InstallVerifier* ExtensionSystemImpl::Shared::install_verifier() {
387  return install_verifier_.get();
388}
389
390QuotaService* ExtensionSystemImpl::Shared::quota_service() {
391  return quota_service_.get();
392}
393
394ContentVerifier* ExtensionSystemImpl::Shared::content_verifier() {
395  return content_verifier_.get();
396}
397
398//
399// ExtensionSystemImpl
400//
401
402ExtensionSystemImpl::ExtensionSystemImpl(Profile* profile)
403    : profile_(profile) {
404  shared_ = ExtensionSystemSharedFactory::GetForBrowserContext(profile);
405
406  if (profile->IsOffTheRecord()) {
407    process_manager_.reset(ProcessManager::Create(profile));
408  } else {
409    shared_->InitPrefs();
410  }
411}
412
413ExtensionSystemImpl::~ExtensionSystemImpl() {
414}
415
416void ExtensionSystemImpl::Shutdown() {
417  process_manager_.reset();
418}
419
420void ExtensionSystemImpl::InitForRegularProfile(bool extensions_enabled) {
421  DCHECK(!profile_->IsOffTheRecord());
422  if (user_script_master() || extension_service())
423    return;  // Already initialized.
424
425  // The InfoMap needs to be created before the ProcessManager.
426  shared_->info_map();
427
428  process_manager_.reset(ProcessManager::Create(profile_));
429
430  shared_->Init(extensions_enabled);
431}
432
433ExtensionService* ExtensionSystemImpl::extension_service() {
434  return shared_->extension_service();
435}
436
437RuntimeData* ExtensionSystemImpl::runtime_data() {
438  return shared_->runtime_data();
439}
440
441ManagementPolicy* ExtensionSystemImpl::management_policy() {
442  return shared_->management_policy();
443}
444
445UserScriptMaster* ExtensionSystemImpl::user_script_master() {
446  return shared_->user_script_master();
447}
448
449ProcessManager* ExtensionSystemImpl::process_manager() {
450  return process_manager_.get();
451}
452
453StateStore* ExtensionSystemImpl::state_store() {
454  return shared_->state_store();
455}
456
457StateStore* ExtensionSystemImpl::rules_store() {
458  return shared_->rules_store();
459}
460
461InfoMap* ExtensionSystemImpl::info_map() { return shared_->info_map(); }
462
463LazyBackgroundTaskQueue* ExtensionSystemImpl::lazy_background_task_queue() {
464  return shared_->lazy_background_task_queue();
465}
466
467EventRouter* ExtensionSystemImpl::event_router() {
468  return shared_->event_router();
469}
470
471ExtensionWarningService* ExtensionSystemImpl::warning_service() {
472  return shared_->warning_service();
473}
474
475Blacklist* ExtensionSystemImpl::blacklist() {
476  return shared_->blacklist();
477}
478
479const OneShotEvent& ExtensionSystemImpl::ready() const {
480  return shared_->ready();
481}
482
483ErrorConsole* ExtensionSystemImpl::error_console() {
484  return shared_->error_console();
485}
486
487InstallVerifier* ExtensionSystemImpl::install_verifier() {
488  return shared_->install_verifier();
489}
490
491QuotaService* ExtensionSystemImpl::quota_service() {
492  return shared_->quota_service();
493}
494
495ContentVerifier* ExtensionSystemImpl::content_verifier() {
496  return shared_->content_verifier();
497}
498
499scoped_ptr<ExtensionSet> ExtensionSystemImpl::GetDependentExtensions(
500    const Extension* extension) {
501  return extension_service()->shared_module_service()->GetDependentExtensions(
502      extension);
503}
504
505void ExtensionSystemImpl::RegisterExtensionWithRequestContexts(
506    const Extension* extension) {
507  base::Time install_time;
508  if (extension->location() != Manifest::COMPONENT) {
509    install_time = ExtensionPrefs::Get(profile_)->
510        GetInstallTime(extension->id());
511  }
512  bool incognito_enabled = util::IsIncognitoEnabled(extension->id(), profile_);
513
514  bool notifications_disabled = false;
515#if defined(ENABLE_NOTIFICATIONS)
516  message_center::NotifierId notifier_id(
517      message_center::NotifierId::APPLICATION,
518      extension->id());
519
520  DesktopNotificationService* notification_service =
521      DesktopNotificationServiceFactory::GetForProfile(profile_);
522  notifications_disabled =
523      !notification_service->IsNotifierEnabled(notifier_id);
524#endif
525
526  BrowserThread::PostTask(
527      BrowserThread::IO, FROM_HERE,
528      base::Bind(&InfoMap::AddExtension, info_map(),
529                 make_scoped_refptr(extension), install_time,
530                 incognito_enabled, notifications_disabled));
531}
532
533void ExtensionSystemImpl::UnregisterExtensionWithRequestContexts(
534    const std::string& extension_id,
535    const UnloadedExtensionInfo::Reason reason) {
536  BrowserThread::PostTask(
537      BrowserThread::IO,
538      FROM_HERE,
539      base::Bind(&InfoMap::RemoveExtension, info_map(), extension_id, reason));
540}
541
542}  // namespace extensions
543