1 // Copyright (c) 2012 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_ui_default.h"
6 
7 #include "base/check.h"
8 #include "base/notreached.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_finder.h"
14 #include "chrome/browser/ui/chrome_pages.h"
15 #include "chrome/browser/ui/global_error/global_error_bubble_view_base.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "extensions/browser/blocklist_state.h"
18 #include "extensions/browser/disable_reason.h"
19 #include "extensions/browser/extension_prefs.h"
20 #include "extensions/common/extension.h"
21 #include "extensions/common/extension_set.h"
22 #include "ui/base/l10n/l10n_util.h"
23 
24 namespace extensions {
25 
26 namespace {
27 
GenerateTitle(const ExtensionSet & forbidden)28 base::string16 GenerateTitle(const ExtensionSet& forbidden) {
29   int app_count = 0;
30   int extension_count = 0;
31   for (const auto& extension : forbidden) {
32     if (extension->is_app())
33       app_count++;
34     else
35       extension_count++;
36   }
37 
38   if ((app_count > 0) && (extension_count > 0)) {
39     return l10n_util::GetStringUTF16(IDS_EXTENSION_AND_APP_ALERT_TITLE);
40   }
41   if (app_count > 0) {
42     return l10n_util::GetPluralStringFUTF16(IDS_APP_ALERT_TITLE, app_count);
43   }
44   return l10n_util::GetPluralStringFUTF16(IDS_EXTENSION_ALERT_TITLE,
45                                           extension_count);
46 }
47 
GenerateMessage(const ExtensionSet & forbidden,content::BrowserContext * browser_context)48 std::vector<base::string16> GenerateMessage(
49     const ExtensionSet& forbidden,
50     content::BrowserContext* browser_context) {
51   std::vector<base::string16> message;
52   message.reserve(forbidden.size());
53   ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context);
54   for (const auto& extension : forbidden) {
55     BlocklistState blocklist_state =
56         prefs->GetExtensionBlocklistState(extension->id());
57     bool disable_remotely_for_malware = prefs->HasDisableReason(
58         extension->id(), disable_reason::DISABLE_REMOTELY_FOR_MALWARE);
59     int id = 0;
60     if (disable_remotely_for_malware ||
61         (blocklist_state == BlocklistState::BLOCKLISTED_MALWARE)) {
62       id = IDS_EXTENSION_ALERT_ITEM_BLOCKLISTED_MALWARE;
63     } else {
64       id = extension->is_app() ? IDS_APP_ALERT_ITEM_BLOCKLISTED_OTHER
65                                : IDS_EXTENSION_ALERT_ITEM_BLOCKLISTED_OTHER;
66     }
67     message.push_back(
68         l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension->name())));
69   }
70   return message;
71 }
72 
73 }  // namespace
74 
75 class ExtensionGlobalError : public GlobalErrorWithStandardBubble {
76  public:
ExtensionGlobalError(ExtensionErrorUI::Delegate * delegate)77   explicit ExtensionGlobalError(ExtensionErrorUI::Delegate* delegate)
78       : delegate_(delegate) {}
79 
80  private:
81   // GlobalError overrides:
HasMenuItem()82   bool HasMenuItem() override { return false; }
83 
MenuItemCommandID()84   int MenuItemCommandID() override {
85     NOTREACHED();
86     return 0;
87   }
88 
MenuItemLabel()89   base::string16 MenuItemLabel() override {
90     NOTREACHED();
91     return {};
92   }
93 
ExecuteMenuItem(Browser * browser)94   void ExecuteMenuItem(Browser* browser) override { NOTREACHED(); }
95 
GetBubbleViewTitle()96   base::string16 GetBubbleViewTitle() override {
97     return GenerateTitle(delegate_->GetBlocklistedExtensions());
98   }
99 
GetBubbleViewMessages()100   std::vector<base::string16> GetBubbleViewMessages() override {
101     return GenerateMessage(delegate_->GetBlocklistedExtensions(),
102                            delegate_->GetContext());
103   }
104 
GetBubbleViewAcceptButtonLabel()105   base::string16 GetBubbleViewAcceptButtonLabel() override {
106     return l10n_util::GetStringUTF16(IDS_EXTENSION_ALERT_ITEM_OK);
107   }
108 
GetBubbleViewCancelButtonLabel()109   base::string16 GetBubbleViewCancelButtonLabel() override { return {}; }
110 
GetBubbleViewDetailsButtonLabel()111   base::string16 GetBubbleViewDetailsButtonLabel() override {
112     return l10n_util::GetStringUTF16(IDS_EXTENSION_ALERT_ITEM_DETAILS);
113   }
114 
OnBubbleViewDidClose(Browser * browser)115   void OnBubbleViewDidClose(Browser* browser) override {
116     delegate_->OnAlertClosed();
117   }
118 
BubbleViewAcceptButtonPressed(Browser * browser)119   void BubbleViewAcceptButtonPressed(Browser* browser) override {
120     delegate_->OnAlertAccept();
121   }
122 
BubbleViewCancelButtonPressed(Browser * browser)123   void BubbleViewCancelButtonPressed(Browser* browser) override {
124     NOTREACHED();
125   }
126 
BubbleViewDetailsButtonPressed(Browser * browser)127   void BubbleViewDetailsButtonPressed(Browser* browser) override {
128     delegate_->OnAlertDetails();
129   }
130 
131   ExtensionErrorUI::Delegate* delegate_;
132 
133   ExtensionGlobalError(const ExtensionGlobalError&) = delete;
134   ExtensionGlobalError& operator=(const ExtensionGlobalError&) = delete;
135 };
136 
ExtensionErrorUIDefault(ExtensionErrorUI::Delegate * delegate)137 ExtensionErrorUIDefault::ExtensionErrorUIDefault(
138     ExtensionErrorUI::Delegate* delegate)
139     : profile_(Profile::FromBrowserContext(delegate->GetContext())),
140       global_error_(std::make_unique<ExtensionGlobalError>(delegate)) {}
141 
142 ExtensionErrorUIDefault::~ExtensionErrorUIDefault() = default;
143 
ShowErrorInBubbleView()144 bool ExtensionErrorUIDefault::ShowErrorInBubbleView() {
145   Browser* browser = chrome::FindLastActiveWithProfile(profile_);
146   if (!browser)
147     return false;
148 
149   browser_ = browser;
150   global_error_->ShowBubbleView(browser);
151   return true;
152 }
153 
ShowExtensions()154 void ExtensionErrorUIDefault::ShowExtensions() {
155   DCHECK(browser_);
156   chrome::ShowExtensions(browser_, std::string());
157 }
158 
Close()159 void ExtensionErrorUIDefault::Close() {
160   if (global_error_->HasShownBubbleView()) {
161     // Will end up calling into |global_error_|->OnBubbleViewDidClose,
162     // possibly synchronously.
163     global_error_->GetBubbleView()->CloseBubbleView();
164   }
165 }
166 
GetErrorForTesting()167 GlobalErrorWithStandardBubble* ExtensionErrorUIDefault::GetErrorForTesting() {
168   return global_error_.get();
169 }
170 
171 }  // namespace extensions
172