1// Copyright (c) 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 "chrome/browser/extensions/suspicious_extension_bubble_controller.h"
6
7#include "base/lazy_instance.h"
8#include "base/metrics/histogram.h"
9#include "base/strings/utf_string_conversions.h"
10#include "chrome/browser/extensions/extension_message_bubble.h"
11#include "chrome/browser/extensions/extension_service.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/ui/browser.h"
14#include "chrome/common/url_constants.h"
15#include "chrome/grit/chromium_strings.h"
16#include "chrome/grit/generated_resources.h"
17#include "extensions/browser/extension_prefs.h"
18#include "extensions/browser/extension_system.h"
19#include "extensions/common/extension.h"
20#include "grit/components_strings.h"
21#include "ui/base/l10n/l10n_util.h"
22
23using extensions::ExtensionMessageBubbleController;
24
25namespace {
26
27base::LazyInstance<std::set<Profile*> > g_shown_for_profiles =
28  LAZY_INSTANCE_INITIALIZER;
29
30////////////////////////////////////////////////////////////////////////////////
31// SuspiciousExtensionBubbleDelegate
32
33class SuspiciousExtensionBubbleDelegate
34    : public ExtensionMessageBubbleController::Delegate {
35 public:
36  explicit SuspiciousExtensionBubbleDelegate(Profile* profile);
37  virtual ~SuspiciousExtensionBubbleDelegate();
38
39  // ExtensionMessageBubbleController::Delegate methods.
40  virtual bool ShouldIncludeExtension(const std::string& extension_id) OVERRIDE;
41  virtual void AcknowledgeExtension(
42      const std::string& extension_id,
43      ExtensionMessageBubbleController::BubbleAction user_action) OVERRIDE;
44  virtual void PerformAction(const extensions::ExtensionIdList& list) OVERRIDE;
45  virtual base::string16 GetTitle() const OVERRIDE;
46  virtual base::string16 GetMessageBody(
47      bool anchored_to_browser_action) const OVERRIDE;
48  virtual base::string16 GetOverflowText(
49      const base::string16& overflow_count) const OVERRIDE;
50  virtual base::string16 GetLearnMoreLabel() const OVERRIDE;
51  virtual GURL GetLearnMoreUrl() const OVERRIDE;
52  virtual base::string16 GetActionButtonLabel() const OVERRIDE;
53  virtual base::string16 GetDismissButtonLabel() const OVERRIDE;
54  virtual bool ShouldShowExtensionList() const OVERRIDE;
55  virtual void LogExtensionCount(size_t count) OVERRIDE;
56  virtual void LogAction(
57      ExtensionMessageBubbleController::BubbleAction action) OVERRIDE;
58
59 private:
60  // Our profile. Weak, not owned by us.
61  Profile* profile_;
62
63  DISALLOW_COPY_AND_ASSIGN(SuspiciousExtensionBubbleDelegate);
64};
65
66SuspiciousExtensionBubbleDelegate::SuspiciousExtensionBubbleDelegate(
67    Profile* profile)
68    : profile_(profile) {}
69
70SuspiciousExtensionBubbleDelegate::~SuspiciousExtensionBubbleDelegate() {
71}
72
73bool SuspiciousExtensionBubbleDelegate::ShouldIncludeExtension(
74      const std::string& extension_id) {
75  extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_);
76  if (!prefs->IsExtensionDisabled(extension_id))
77    return false;
78
79  int disble_reasons = prefs->GetDisableReasons(extension_id);
80  if (disble_reasons & extensions::Extension::DISABLE_NOT_VERIFIED)
81    return !prefs->HasWipeoutBeenAcknowledged(extension_id);
82
83  return false;
84}
85
86void SuspiciousExtensionBubbleDelegate::AcknowledgeExtension(
87    const std::string& extension_id,
88    ExtensionMessageBubbleController::BubbleAction user_action) {
89  extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_);
90  prefs->SetWipeoutAcknowledged(extension_id, true);
91}
92
93void SuspiciousExtensionBubbleDelegate::PerformAction(
94    const extensions::ExtensionIdList& list) {
95  // This bubble solicits no action from the user. Or as Nimoy would have it:
96  // "Well, my work here is done".
97}
98
99base::string16 SuspiciousExtensionBubbleDelegate::GetTitle() const {
100  return l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNSUPPORTED_DISABLED_TITLE);
101}
102
103base::string16 SuspiciousExtensionBubbleDelegate::GetMessageBody(
104    bool anchored_to_browser_action) const {
105  return l10n_util::GetStringFUTF16(IDS_EXTENSIONS_UNSUPPORTED_DISABLED_BODY,
106      l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE));
107}
108
109base::string16 SuspiciousExtensionBubbleDelegate::GetOverflowText(
110    const base::string16& overflow_count) const {
111  return l10n_util::GetStringFUTF16(
112            IDS_EXTENSIONS_DISABLED_AND_N_MORE,
113            overflow_count);
114}
115
116base::string16
117SuspiciousExtensionBubbleDelegate::GetLearnMoreLabel() const {
118  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
119}
120
121GURL SuspiciousExtensionBubbleDelegate::GetLearnMoreUrl() const {
122  return GURL(chrome::kRemoveNonCWSExtensionURL);
123}
124
125base::string16
126SuspiciousExtensionBubbleDelegate::GetActionButtonLabel() const {
127  return base::string16();
128}
129
130base::string16
131SuspiciousExtensionBubbleDelegate::GetDismissButtonLabel() const {
132  return l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNSUPPORTED_DISABLED_BUTTON);
133}
134
135bool
136SuspiciousExtensionBubbleDelegate::ShouldShowExtensionList() const {
137  return true;
138}
139
140void SuspiciousExtensionBubbleDelegate::LogExtensionCount(
141    size_t count) {
142  UMA_HISTOGRAM_COUNTS_100(
143      "ExtensionBubble.ExtensionWipeoutCount", count);
144}
145
146void SuspiciousExtensionBubbleDelegate::LogAction(
147    ExtensionMessageBubbleController::BubbleAction action) {
148  UMA_HISTOGRAM_ENUMERATION(
149      "ExtensionBubble.WipeoutUserSelection",
150      action, ExtensionMessageBubbleController::ACTION_BOUNDARY);
151}
152
153}  // namespace
154
155namespace extensions {
156
157////////////////////////////////////////////////////////////////////////////////
158// SuspiciousExtensionBubbleController
159
160// static
161void SuspiciousExtensionBubbleController::ClearProfileListForTesting() {
162  g_shown_for_profiles.Get().clear();
163}
164
165SuspiciousExtensionBubbleController::SuspiciousExtensionBubbleController(
166    Profile* profile)
167    : ExtensionMessageBubbleController(
168          new SuspiciousExtensionBubbleDelegate(profile),
169          profile),
170      profile_(profile) {}
171
172SuspiciousExtensionBubbleController::~SuspiciousExtensionBubbleController() {
173}
174
175bool SuspiciousExtensionBubbleController::ShouldShow() {
176  return !g_shown_for_profiles.Get().count(profile_->GetOriginalProfile()) &&
177      !GetExtensionList().empty();
178}
179
180void SuspiciousExtensionBubbleController::Show(ExtensionMessageBubble* bubble) {
181  g_shown_for_profiles.Get().insert(profile_->GetOriginalProfile());
182  ExtensionMessageBubbleController::Show(bubble);
183}
184
185}  // namespace extensions
186