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_error_controller.h"
6
7#include "chrome/browser/extensions/extension_service.h"
8#include "chrome/browser/extensions/pending_extension_manager.h"
9#include "extensions/browser/extension_prefs.h"
10#include "extensions/browser/extension_registry.h"
11#include "extensions/browser/extension_system.h"
12#include "extensions/common/extension_set.h"
13
14namespace extensions {
15
16namespace {
17
18ExtensionErrorController::UICreateMethod g_create_ui =
19    ExtensionErrorUI::Create;
20
21}
22
23ExtensionErrorController::ExtensionErrorController(
24    content::BrowserContext* context,
25    bool is_first_run)
26    : browser_context_(context),
27      is_first_run_(is_first_run) {}
28
29ExtensionErrorController::~ExtensionErrorController() {}
30
31void ExtensionErrorController::ShowErrorIfNeeded() {
32  IdentifyAlertableExtensions();
33
34  // Make sure there's something to show, and that there isn't currently a
35  // bubble displaying.
36  if (!blacklisted_extensions_.is_empty() && !error_ui_.get()) {
37    if (!is_first_run_) {
38      error_ui_.reset(g_create_ui(this));
39      if (!error_ui_->ShowErrorInBubbleView())  // Couldn't find a browser.
40        error_ui_.reset();
41    } else {
42      // First run. Just acknowledge all the extensions, silently, by
43      // shortcutting the display of the UI and going straight to the
44      // callback for pressing the Accept button.
45      OnAlertClosed();
46    }
47  }
48}
49
50// static
51void ExtensionErrorController::SetUICreateMethodForTesting(
52    UICreateMethod method) {
53  g_create_ui = method;
54}
55
56content::BrowserContext* ExtensionErrorController::GetContext() {
57  return browser_context_;
58}
59
60const ExtensionSet& ExtensionErrorController::GetExternalExtensions() {
61  return external_extensions_;
62}
63
64const ExtensionSet& ExtensionErrorController::GetBlacklistedExtensions() {
65  return blacklisted_extensions_;
66}
67
68void ExtensionErrorController::OnAlertAccept() {
69  error_ui_->Close();
70}
71
72void ExtensionErrorController::OnAlertDetails() {
73  error_ui_->ShowExtensions();
74
75  // ShowExtensions() may cause the error UI to close synchronously, e.g. if it
76  // causes a navigation.
77  if (error_ui_)
78    error_ui_->Close();
79}
80
81void ExtensionErrorController::OnAlertClosed() {
82  ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context_);
83  for (ExtensionSet::const_iterator iter = blacklisted_extensions_.begin();
84       iter != blacklisted_extensions_.end();
85       ++iter) {
86    prefs->AcknowledgeBlacklistedExtension((*iter)->id());
87  }
88
89  blacklisted_extensions_.Clear();
90  error_ui_.reset();
91}
92
93void ExtensionErrorController::IdentifyAlertableExtensions() {
94  ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
95  ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context_);
96
97  // This should be clear, but in case a bubble crashed somewhere along the
98  // line, let's make sure we start fresh.
99  blacklisted_extensions_.Clear();
100
101  // Build up the lists of extensions that require acknowledgment. If this is
102  // the first time, grandfather extensions that would have caused
103  // notification.
104
105  const ExtensionSet& blacklisted_set = registry->blacklisted_extensions();
106  for (ExtensionSet::const_iterator iter = blacklisted_set.begin();
107       iter != blacklisted_set.end();
108       ++iter) {
109    if (!prefs->IsBlacklistedExtensionAcknowledged((*iter)->id()))
110      blacklisted_extensions_.Insert(*iter);
111  }
112
113  ExtensionSystem* system = ExtensionSystem::Get(browser_context_);
114  ManagementPolicy* management_policy = system->management_policy();
115  PendingExtensionManager* pending_extension_manager =
116      system->extension_service()->pending_extension_manager();
117  const ExtensionSet& enabled_set = registry->enabled_extensions();
118
119  for (ExtensionSet::const_iterator iter = enabled_set.begin();
120       iter != enabled_set.end();
121       ++iter) {
122    const Extension* extension = iter->get();
123
124    // Skip for extensions that have pending updates. They will be checked again
125    // once the pending update is finished.
126    if (pending_extension_manager->IsIdPending(extension->id()))
127      continue;
128
129    // Extensions disabled by policy. Note: this no longer includes blacklisted
130    // extensions, though we still show the same UI.
131    if (!management_policy->UserMayLoad(extension, NULL /* ignore error */)) {
132      if (!prefs->IsBlacklistedExtensionAcknowledged(extension->id()))
133        blacklisted_extensions_.Insert(extension);
134    }
135  }
136}
137
138}  // namespace extensions
139